SAM: This episode of Greater Than Code is brought to you by Atlas Authority. Atlas Authority helps organizations manage and scale their Atlassian stack. With expertise in Jira, Confluence, Bitbucket, and other software development tools, Atlas Authority offers consulting, training, licensing, and managed hosting services. Visit AtlasAuthority.com/GTC to find out more and learn why organizations trust Atlas Authority to implement, to support, and maintain their critical Atlassian applications. CORALINE: Hi and welcome to Episode 136 of the Greater Than Code podcast. My name is Coraline Ada Ehmke. I will be one of the hosts today. Also with me is my dear friend, Jamey Hampton, aka Jamey Bash. Hi, Jamey. JAMEY: Hi. I'm really excited to be on the show for the first time in a little while. And I'm here with my friend, Rein Henrichs. REIN: Hi, Jamey and hi [inaudible]. I am here with my friend, Sam Livingston Gray. SAM: It's one big, happy [inaudible] family. Hello, everybody. How are you today? CORALINE: I feel empty inside when all my dreams are dead. Having a great day so far. SAM: Sweet. Let's do a rest. CORALINE: The attentive listener will never say, we did not introduce a guest today. And in fact, we do not have a guest today. This is a special edition panelists only show and we're going to talk about something that Sam had been tweeting about recently that got some attention. Sam, do you want to introduce us to the topic for today? SAM: Why, yes, I will. Thank you. Last week, I gave a talk about Refactoring at my local Ruby user group. It was actually a slightly edited version of a talk I gave back in 2013. I was about Refactoring and somebody else watched a video of the talk online. There's a link to that in the show notes, by the way. And they sent me a tweet saying, "Thanks for the talk on Refactoring. Do you have any advice on getting team members to see that kind of Refactoring as a necessary step to delivering value?" And that really started got me thinking like, "How do you do this?" And my first reaction was to quote the tweets that we often quote on this show, which is, "I don't know how to convince you that you should care about other people," but that's glib and not very satisfying. It doesn't make for a very good show. So, what do you all think? CORALINE: This is something I'm actually facing at my work. We have kind of a distributed monolith architecture. We have a centralized shared database and 33 applications that talk to various tables in that database. And we've been spinning up services. We have some go services that don't talk to the database and some of our infrastructure is kind of old. We're a six-year old company, so we have six-year old apps and some of them are getting pretty creaky. So we've been talking a lot about how we can responsibly refactor these applications while resisting the urge that I think every developer feels sometimes of just like burn it all down and start over. And one of the things that's been really helpful for us is rather than thinking about refactoring targets as technical debt, we're talking about technical friction. I think friction makes it a little bit more actionable, it implies motion. And really the only parts of the code base that we care about refactoring are those parts of the code base that are getting in our way of delivering features. So that's like a lens that we look through to evaluate refactoring targets. And I think that for us that's one way to get people more excited about it because it's like, "Hey, there's this controller that you're always working in and it's a source of constant bugs. What if we did some more combat controller to make your life easier in the future?" SAM: I like the technical friction metaphor. I think Ward Cunningham came up with the Technical Debt metaphor as something that was palatable to the business people he was working with. And I suspect that word was able to express that in a way that captured, I think more accurately what everybody else has sort of gone astray with, with regard to using technical debt. I don't like the metaphor of technical debt just because debt as a financial instrument is much more predictable as opposed to having something in the code base that could never come to bite you in the butt or it could take your whole business down. The scope of possible outcomes is a lot more swish with technical debt and a lot less predictable. CORALINE: I think the language that we use really matters too. That's a term I beat a lot in my talks about how language sort of constraints our thinking and constraints our problem solving abilities. So I think that, as a metaphor, like has its good qualities. But as you pointed out, Sam, it's an incomplete metaphor and I think we should always be looking for newer and better metaphors to better express the challenges that we face. So yeah, I was happy to land on technical friction. SAM: You sort of touched on something else that I had put in my talk, which is that my friend Jim Shore, I had taken a class from him. Actually the first time we met I think was in a class that I took at Portland State University on Extreme Programming. And I think it wasn't even during the class, it was maybe even just an aside, but he named something that I found really impactful to the way that I approached code, which is that he said when a lot of programmers encounter code that they didn't write, their first reaction is very often to throw up their hands and say, "This is crap. I can't work with this." And I definitely heard myself in that when he said it. I was like, "Oh, oh, that's me. I got to change." JAMEY: I'm actually experiencing the exact opposite thing almost at my job right now, which is that I have been at my company for almost three years. I was at one point the only programmer and everyone else who is on the team now has joined since then. And so we just did a major refactor that I wasn't directly involved in it's still kind of ongoing. But before the refactor, almost all of the code in the entire code base I had, if not written myself, at least touched and understood. And now there's been a huge overhaul of it with this refactor. And there was a huge release branch that got merged in and then suddenly I was like, "Oh my God, I don't understand any of our code anymore because it was all rewritten by the other team." And that's been surprisingly hard to deal with emotionally. SAM: Interesting. JAMEY: I mean, I think that a lot of the things they've done in the refactor are really great and I think that there was a lot of technical debt or otherwise that was involved in some of the code that I had written. So it's not so much like, "Oh, I'm emotionally attached to my code and you took it out." But it's more just like I'm so used to having this pretty full understanding of the entire architecture and now suddenly, I kind of don't in the same way anymore. It almost feels like starting a new job and like looking at a new code base. It's so like overstretching of the entire app, which is a wild feeling, I guess. I'm not sure exactly what my thought about that is, but it's kind of funny to me that we talk about this old code that someone else wrote and now this shiny new code that I wrote and I'm kind of experiencing it now in reverse. SAM: [Laughs] That's actually a really interesting point. I like it. I've certainly had an experience where I was working in some code where like littered throughout the code base were case statements that were literally switching on database record IDs. It was an application that was written for a company that had several different brands and it was like case brand.id: 1, 1 do this, 1, 2, do that. And I looked at this and I was horrified and I carefully spent a day or two going through. And I came up with like a 400-line patch that took all of those things and replaced them with attributes on the brand model, which at least was a little bit easier to deal with, I thought. And then I put that patch into subversion and then it was reverted because it would've been too hard to apply that patch across the three or four other branches that had diverged from the one that I happened to be looking at. CORALINE: No. SAM: And this was super frustrating. And at the same time, I probably could have had a little bit more empathy for the person who was trying to maintain that stuff. That's not quite the position that you're in, Jamey, but it reminded me of that. CORALINE: Yeah. JAMEY: Yeah. I think that there's an interesting passing of empathy on both sides because I was feeling a little bit at first, like I wanted someone to hold my hand, I guess, through like 'what all did you do to my code' a little bit. It's not all my code, but like I was feeling kind of like, "Yeah, well if you changed it, like you should teach me the new way." And there was kind of a discussion about like, "Well, why don't you just like go in and look at it?" SAM: Just read the code. JAMEY: So, there was like a little bit of friction there. But we're working it out. SAM: First, just read the code. It's obvious, this is what the original author would say if they were still around, right? CORALINE: Yeah. SAM: There was something else there, Jamey. So, the original question was about how you can advocate to your team members to start caring about refactoring as an important step. And this sort of skips past that, and I do want to get back to that. But what it sounds like you went through was this process of a refactor, or I almost want to say a redesign that took place over a long period of time in a separate branch. Do you know how that was managed? Like did they keep merging back in from the production branch and periodically or keep rebasing? Or how did that work? JAMEY: I actually don't really know. I feel weird about answering this question because I didn't work on this project and I don't really know how they did it. I'm sorry. SAM: Like go grab a co-worker and drag him in. JAMEY: No. CORALINE: Maybe that's a problem now when you are making significant changes to the code base. I'm of the opinion that a PR is like a code review of last resort when you're doing something big. I really prefer to have code walkthroughs where you have an engineer who wrote or at least understands the code, walk through it, and I think that's what you're asking for, right Jamey? Like give me a walkthrough of layout, what the design principles are. Tell me what's your philosophy for this redesign was, tell me what the new mappings between our business and our business objects are. I don't think that's an unreasonable thing to ask for. And I think it's the responsibility of someone who's making a big change and what sounded like a breaking change to the design, at least. That's kind of on them to bring the rest of their team along. REIN: There's a value for the senior engineers. Talk about the honor, the code that came before you, that sort of thing, which isn't just honor the code, it's honor the effort of the people who wrote the code. SAM: And the circumstances they were in. REIN: Yeah. And all of the value that they put into that code that you may not understand now, but that doesn't mean it doesn't exist. And one of the things I think about when I refactor, we like to think that refactorings are simple. You just keep the behavior of the way it is and you make it the way it does that thing better. But there are a lot of edge cases, there are a lot of things where you look at the code and you go, "Is that a bug? Is it supposed to be that way? That's weird." And then you go talk to someone and they say, "Oh that's because of X." And now you know whether it's a bug or not. And you need to know those things to know whether you're refactoring correctly. JAMEY: That's a great point. REIN: I just did the refactor of a really critical code path in the code base I'm working on where we have basically this handler mechanism that dispatches this object to some handler that handles it. And it was a giant case statement of like these 12 different hand for classes. And each class, some of them, the thing for doing the handling was like a hundred lines long and I thought, "How can I possibly refactor all of those handlers and come up with something that's correct when I don't understand any one of the handlers." And what I realized was I don't have to understand them. I can keep them the same and just change the way that the dispatching works. And so, sometimes the thing to do with old code is honor it and not change it because that's actually not the thing that's causing the problem for your team, which kind of gets to a point I wanted to make, which is that you do a refactoring to solve a problem. You don't just do it because it's fun, or at least I don't think you should. CORALINE: That kind of ties into one of the cultural values that we have at Stitch Fix as an engineering organization. We had an architect and he was one of the original developers of most of our systems. And the question that he always raised was what is the problem you're trying to solve? And that's such a simple question, but it was amazing to me how many times people would get caught up in that. They had this notion in their head of something they wanted to do, but it had become disconnected from the reality of the problem that they were trying to solve. And I really think if you can't clearly state the problem you're trying to solve, then you have no business writing code on it. JAMEY: We do our tasks with user stories, so we don't do this 100% of the time, but we try to, like when we have cards in Pivotal or whatever we're using, we're using Pivotal right now, but like we try to use the format of like as a blank, I want to blank. And so, a lot of them will be like users like as a grower, because I work in agriculture, so like our customers are farmers. Like as a grower, I want to be able to move my crop, blah blah blah, like stuff like that. But like we can also do it for developer happiness kind of stuff. Like as a developer on this project, I want to be able to go into this piece of code and understand the documentation. I think that there can be a similar, like I agree with you about the problems to solve and I think there's like different people that have the problems and sometimes those people are our customers and sometimes they're ourselves. CORALINE: Yeah. That's such a healthy approach I think because I believe that we write code for people first and if fellow developers are struggling with the piece of code or don't understand a particular subsystem, that's a problem. And I love that you addressed them as users with user stories. I think that's brilliant. REIN: And actually saying "the problem" is a bit reductive because usually there are a bunch of problems that are all related to each other. JAMEY: That's true. REIN: Russell Ackoff said a problem isn't abstraction extracted from a mess by analysis. So the message, all of these interlocking in to interdependent problems. And when we focus on one thing, we call it "the problem" it's because we have extracted it from this context. And I guess where I'm going with that is that if you're refactoring, you're now a part of the mess. You have to make sure your problem, your solution to your problem doesn't have other interactions that you didn't understand or predict. CORALINE: I think that comes into breaking down our problem into the smallest possible parts. And it's okay for a problem to be multifaceted, but I think it's a dangerous position to put yourself in if you say, "I'm going to solve this entire nest of problems," because then you end up unraveling the sweater and getting yourself potentially in over your head. SAM: Yeah. As somebody with ADHD, that is definitely a trap that I fall into is like, "Oh, I'm working on this thing. And oh my God, what's that mess over there?" And then I sort of started untangling that mess and like, "Oh, it leads to other things because code ugliness is fractal." REIN: So this is why I think that problem forming is a more important skill than problem solving. SAM: Yeah. But all of this assumes that you can get your coworkers to go along with you, which was the original question. REIN: So, let me get back to that because there's a specific thing I wanted to mention, which is that status quo bias often prevents us from understanding or perceiving the costs of not changing. And so, I think often when we're trying to convince the people who need to be convinced that we should do a refactoring, we do ourselves a disservice by talking about the costs and the value of the refactoring in a vacuum. I think what we ought to say instead is, "Look, in a month, the code can look like A and have these costs and benefits or the code can look like B and have these costs and benefits and what do we prefer?" SAM: That just reminded me of one of my favorite cognitive biases, which is The Well Traveled Road Effect. It's a bias in which travelers will estimate the time taken to traverse routes differently depending on their familiarity with the route. So if you know the mess, if you're comfortable with it, then you can navigate it very quickly because you know where to look. If you're new to it or if you're easily distracted for various reasons, then a certain bit of code can cost you a lot more than it costs to somebody who's been working with it for awhile. CORALINE: Yeah, I think that's a great point. In the book I'm co-authoring with Naomi Freeman, Compassionate Coder, we talk a lot about working with legacy code. But one of the other things that we addressed is what you could learn from the process of onboarding a new developer. Sam, your point with the Well Traveled Road, we get used to the code being in a certain state and we're like, "Oh yeah, that part is kind of complicated or that part's kind of quirky," but we kind of deal with it because that's the status quo. And when a new person comes in and they're confused about the code, maybe that's a sign that, "Hey, maybe it would be better for us if we took a look at that and thought about like, does that still match our best practices? Is that still mapped to the business domain?" I think things that confuse other people can be a code smell too. REIN: I think we've all seen the new developer come in and say, "I'm going to change all the things. All the things can be better. I don't understand why they're like this." And it's easy to dismiss that as, "Oh, you have summer child." But actually that perspective is super valuable if you can integrate it. CORALINE: And there's a timing aspect to it too because in six months, that developer's also going to be on that well traveled road where, "Oh yeah, that controller's just to mess. We try not to work in there." So, you really have to kind of strike while the iron's hot and like document this area, the code is hard to understand. And I am in favor of senior engineers keeping a shadow backlog. I know a lot of us who work for product companies or for service companies, we're very focused on delivering customer facing features. So that's often what drives our roadmap for development. We're working with business partners who are asking for our feature to be delivered by a given date, but I think having a shadow backlog of things that you want to work on when you have time and then working with business partners to communicate why working on those things is important, what the value of them is, is really good. But without that shadow backlog, if that opportunity presents itself, you're going to be faced with the question of what do I do next? And being paralyzed on that question is a terrible position to be in. JAMEY: I worry that having too long of a backlog would cause the same effect of being paralyzed. CORALINE: Well, it's got to be stocked right, right? SAM: Yeah. It's basically like if you put a tick mark by everything every time it annoys you, then you pretty quickly know what to prioritize. JAMEY: That's a great idea. One thing that is kind of related to what Rein was talking about earlier about like respecting the code and like talking about new developers coming in as like inexperienced that I've had a lot is when we have new developers, they'll come to me and ask me questions about like, "Well, why is this like this?" And I don't think it's meant to be a loaded question, but it's kind of interesting because like sometimes the answer is like, "Oh, well there's this very specific thing and like here was the error and here's how we got around it." Or like, there was a specific customer that we had to do something for. Or sometimes it's like, when you're running out of time and we were in crunch and sometimes the answer really is just like, "I don't know, because we were stupid. We didn't think about it." And I mean, that's glib but it's how I feel about it sometimes. But I try to be honest about it but I guess what I wonder is like when somebody new comes to me like which of those answers do they want to hear? REIN: Yeah, that's why I try to not ask. Why is it like this? What I say is, "Hey, I think it could be like X, is that possible?" And then they have like a concrete thing that can give me feedback on rather than having to justify the existence of a thing. JAMEY: I used to be very stressed out about justifying the existence, especially when the answer was like, "I don't know, because I did it three years ago..." REIN: Three years ago and we weren't good. JAMEY: Yeah. I used to feel very self conscious about the answer but I wonder if that's like, if someone's coming to me asking why is this like this because they want to change it. Like that's the answer they want to hear. They want to hear like, "I don't know, because it was dumb." They don't want to hear, "Oh, there's a very specific reason why it was like this and you can't change it." REIN: So what I would do in that situation is I would try to get them to say that I would say, "Why do you want to know? Is there something you want to change?" JAMEY: That's great advice. SAM: I'm in a similar situation where I've been, I'm working on a code base that's about 10 years old, at least. I was looking in the initial import intake git was in 2009. I've been working on this code base for about four years and I've tackled on a number of the large messes. I've actually been really fortunate to be able to spend a lot of time doing heads down big refactors and not be expected to deliver a lot of customer facing features. But that means that since I've dealt with some of the biggest messes, I've actually had this experience now of somebody coming in and looking at some search code that I introduced that is pretty confusing. But my reaction when I was first asked about it was, "Well, you should see what came before." So that's my own status quo bias I think is like, "I fixed it and it's better, but it's not better enough." JAMEY: That's like some computer science version of like 'you should see the other guy'. [Laughter] REIN: It's interesting how existing designs constrain us even when we don't want to be constrained. Maybe the reason you didn't come up with the thing that they did is because you were basing your design on what you thought was possible given the existing design and then they were doing the same thing. SAM: Yeah, I like it. REIN: So, talking about how do we convince people to refactor, maybe the place to start is by examining the people who are invested in the code and what the code does and where they often fall in and what arguments they often make. What positions they often take when you discuss refactoring. So, team leaders, product owners, and so on. JAMEY: I agree. I was going to make a similar point about it but it's a hard question to answer because it really depends on why there is resistance to refactor. And I feel like there's a number of reasons that resistance could exist. I think that's kind of what you're saying. REIN: Yeah. I found that the success of being able to do the refactoring mostly depends on the attitudes of the people who have power over that decision. CORALINE: And that those people may not be engineers. That was like the point I was trying to make with justifying the business partners, your stakeholders, because those people may not understand the value and I think that's where those metaphors come in really handy. If they understand the concept of technical debt or if you can convince them or if you can give them an understanding of technical friction, if you can say, "Look, we'd had 12 bugs over the past year in this part of the code and that part of the code is going to continue to be a source of the bugs because it's complicated. We need to do something about it." REIN: So let's say that it's the product owner and the product owner wants us to ship features and the product owner doesn't want us to "waste time" refactoring when we could be shipping. That's maybe a bit of a straw man, but it's a thing I've literally heard. SAM: I have heard this as well. CORALINE: I think it's natural and normal because the problem they're trying to solve is delivering value to the customer and the problem you're trying to solve is delivering value to other developers and to yourself. That's why I like Jamey's approach so much about having user stories that have developers as actors. SAM: I'm not sure that's necessarily true though, because the way that you framed it just now is like there's a conflict between delivering value to customers and delivering value to developers. And I think one of the main problems with technical friction is that it slows down your ability to deliver to customers. CORALINE: Yeah. SAM: Users actually, not customers. Users. CORALINE: And that's a tool you can use when you're talking to stakeholders about why that change is necessary. And that's something they can definitely understand. You can point to bug frequency, you can point to, "Look, it's going to cost two sprints to implement this relatively simple feature because that code is very difficult and it's going to continue to cost us more and more and more time as we move forward making changes to this part of the code base. We really need to make that investment now." And I think if you frame it in terms of an investment, that's also a metaphor that maybe non-technical stakeholders can wrap their heads around. REIN: So, I'm a constructivist. When I look at this situation, what I see is an opportunity to construct a new understanding between me and the product owner where we both have different views of the problem and both of our views are valid. And if we can construct a shared understanding by discussing, "I think that the refactoring would benefit us and solve your problem by doing X," and so on, then I think you can rather than just having this be a conflict, you can turn it into an opportunity. SAM: The thing I like about this and what I like about Jamey's approach both together is that being forced to go back and think about things in terms of user value does help keep you focused on what the problem is that you're actually trying to solve and maybe helps keep you a little bit more focused. I mean, that's one thing that I've always liked about Cucumber tests is that regardless of whether or not they're executable, they get me thinking at that bigger level again about like, "Wait, what am I actually trying to do here?" And maybe there's a user way... REIN: It also forces me to be more explicit about understanding the problem that I'm trying to solve and relating the problem I'm trying to solve back to our shared goals as a team. So, the problem I'm trying to solve is actually not, 'oh, this code sucks'. The problem I'm actually trying to solve is 'I want to do stuff with this code'. I want to change it in a way that benefits the team and it's difficult now and would be easier later. And I think that the refactoring, the cost of the refactoring would be paid off by all of the future development of this thing being easier. That's the assumption that I have and the reason why I want to do the refactoring. And if I can just be explicit about that and turn those assumptions that I have into a shared understanding, I think that once you can formulate the mess, the mess often just dissolves. CORALINE: And I think that kind of turns Sam's question on its head because there will be situations where a refactoring is not worthwhile if it's not related to a problem that you're having. SAM: Yes. CORALINE: If you just say, "This code is ugly, I don't like it. I wouldn't have written it this way." That's not a good justification for doing a refactoring. That's being a cowboy. REIN: I've had situations where I've been really excited to do a refactoring and I've talked to the team leader, I've talked to the product owner and we've discussed why I think it's a good idea and why I think it benefits the team. And it turns out I was wrong. It turns out that I didn't understand that this actually wasn't as much of a priority or actually we're going to be moving on to work on this thing sooner and so on. And actually the refactoring wouldn't have given the team the value I thought it would have. CORALINE: Oh my God, I want to pitch this tool that one of my coworkers wrote. His name is Dan Mayer and he has a Ruby gem called Coverband. You know how when you use like simple [inaudible] and it shows you how your tasks have exercised your code and it gives you that like source code view and little lines are highlighted that have been tested, it actually like keeps a tally of code path executions so you can go and you can browse your code paths and say, "Oh my God, this one was hit 20,000 times over the past 24 hours." Maybe that's something that we would really want to focus on versus, "Wow, this could path rarely ever gets executed. Let's just leave it the hell alone." SAM: Or delete it. REIN: But it'll tell you, "Hey, this is a critical code path and if we're going to touch it, we need to do it with the most delicate of gloves." CORALINE: Exactly. It's such a cool tool and we've been integrating it into a lot of our apps at Stitch Fix. My job is to do service integrations and service extractions. And the last thing we want to do is spend a lot of time refactoring code to use at service when it's not even part of an execution path. SAM: That's fascinating. My usual approach for using a tool like Coverband, which is awesome, is like I said, it's just if something is even still used and I can delete it. But I like your focus as well. REIN: So, we've been talking about sort of the costs and the benefits of refactoring, but we haven't talked much about the risks. So the whole goal of refactoring is to not change the behavior of a thing, but to change its shape, right? SAM: Yeah. REIN: But that's not foolproof. SAM: [Chuckles] But Rein, there are always tests that tell you whether you've changed the behavior of the code. REIN: Yeah. But tests can't be complete. I will refer you to [inaudible]. SAM: [Inaudible] to challenge my assumption that there are always tests at all. JAMEY: [Laughs] REIN: Right, also true. But even when you think that code is tested, even when you have good coverage, it's always possible for there to be things that aren't covered that actually happen in the real world. And there's no real way for you to know even with coverage tools. SAM: Oh, there's a great line from travelers that I'm going to borrow here, which is no plan survives contact with the past. REIN: Nice. I like that more than the enemy. Although arguably the past is... SAM: Oh, yeah. JAMEY: We're talking about this a little bit with our refactor, which again was like, it had more to it than that. But someone was like, "Oh well, if there are bugs in the new version," blah, blah, I'm like, "No, stop. There will be bugs." There's always going to be bugs. There's bugs in the old version. There's bugs in the new version. Bugs are in code and that's just part of writing code. So, let's all get that straight. [Laughs] SAM: That reminds me of a thing I was going to say a couple of minutes ago, which is that another smart person that I worked with, John Wilger, and by the way, Dan Mayer and John Wilger, we all work together, and Rein as well at Living Social. So some of the things that I'm thinking about all happened there. But one of the things that John Wilger taught me is that, "And it will make it easier for us to do X in the future is much less convincing than you probably think it is because you may not ever want to do X in the future. By the time you get there, your plans may change." JAMEY: The world might end. REIN: A thing I learned from Ackoff, again, he has a tool called Idealized Design, which is a way to figure out how to make your business not collapse. But what he does is he says, "Okay, imagine that the system that we are in was destroyed last night. It's all gone. All of our code is gone, all of our servers are gone, the team is gone, everything is gone, and we're going to rebuild from scratch. And we can do anything that we want as long as we follow three rules. One, it has to be technically viable. No science fiction. Two, it has to be organizationally viable. They can't break any laws. It can't be something that if we ran like this for six months, we'd cease to exist. And three, it has to be a system that's capable of improvement over time." So what I think about in these situations is -- oh, by the way, the goal of figuring out what the system would be is not what you would do five years in the future, it's what would the system be like today to solve the mess we're in today? Because we know about today, but we don't know about six months from today. So what I think about is, Sam, instead of solving the problems of the future, how should the code be today to solve the problems of today? SAM: And taking that question back into the past that often helps me build some empathy for the code and its original authors is because I just assume that the code is the way that it was because it solved the problem that they had then. REIN: The way I often frame it is if this code worked this way today, the thing we're building now, we would get done faster and it would be less buggy, and so on. CORALINE: I think in the trigger document, I worked for the engineering friction working group that I lead at Citrix, we outlined three different kinds of technical debt. One is intentional that you have a deadline, you have a massive strategic initiative. You don't have time to do things in an optimal way, but it's important to document them so that in future you can go back and include things up. Then there's evolutionary debt, which is more of what you two were just describing where a design that worked in the past is increasingly not appropriate for the problems that you are having now. And then finally there's bit rot, which I think also has to be addressed that the quality of code tend towards entropy, the more people who work on a code base, the less well that adheres to its original design. And I think it's really important to think about what kind of refactor you want to do based on the shape of that code, where it lies in that domain of technical debt. REIN: Yup. That's really interesting especially because only one of those is intentional. The other two are systemic. CORALINE: Yeah. REIN: And the idea of that code tends toward entropy is especially fascinating to me. One of the things that refactoring is, is a firebreak against that, right? CORALINE: Yeah, that's true. REIN: We say we've seen the direction this code is going in and we want to get back to a state that's different that prepares us more for changes in the future. CORALINE: Yeah. Like I said, that shapes the kind of refactoring you want to do in the motivation and there are tools that are helping you identify areas where there's a lot of bit rot. You can use a tool called churn, which will literally count the number of times that a particular line of code or a particular class has been modified through its git history. SAM: [Crosstalk] class or file level. CORALINE: Yeah. REIN: How does categorizing technical debt help you approach refactoring? CORALINE: It gives you a goal in mind. Like if it's intentional debt, then you're like, we had to prioritize this because we didn't have time in a moment to get it right and we know or we sensed that if we leave this code alone, it's going to cause problems down the road. I think there's this sense of timeliness and urgency. REIN: Is there a sense of like you made a promise to yourself when you assume the technical debt and now you have to fulfill the promise? CORALINE: I think that's exactly right. REIN: We said we would pay this off and if we don't, then we're lying to ourselves. CORALINE: Yeah. SAM: Do you have a trigger condition for intentional debt? Like, this is this way because right now we don't have to solve this problem, but when we get to 10X the load that we have now, it's going to fall down. CORALINE: I think that's a very healthy way to approach it. SAM: So how do you distinguish, like how do you know that something is intentional debt? Like was there a document that was produced at the time that that choice was made? CORALINE: You have to document it. You have to have at least a shadow backlog. You have to have documentation of some kind because otherwise, it's going to slip out of your mind. It's going to be something that sort of nags you in the background every now and then, and you're never going to get to it. I really believe if things aren't written down, they're going to be lost, especially in a larger company. REIN: Speaking of documentation, have any of you used architecture decision records or any kind of decision records? And if so, did they help you when you go back to look at why your thing is the way it is today? CORALINE: [Inaudible] one of the first contributions to the engineering culture that I made. And we have a process for considering them. We start with a Google doc and then we invite people to comment on a Google doc that allows us to iterate quickly. And then we make a PR with a document to our [inaudible] Wiki and then we have a meeting where engineers get together. It's called [inaudible], it's a meeting that I run now. We're interested engineers get together and we spend 15 minutes timeboxed to discuss the details of [inaudible] in an attempt to drive toward consensus. Consensus is not necessary, but if you don't get consensus, that's a sign that maybe this needs more work. And then after that 15 minute timebox, we take a pulse. We actually use a poll on Slack in our back channel to say, 'yes, adopt it', 'no, needs more discussion'. And we do that to get everyone on board and sort of socialize the decisions that we're making. If we're just writing [inaudible] that's in a vacuum, then they're not really affecting how anyone else assess their work. SAM: Interesting. JAMEY: My first programming job ever was like I found this job on Craigslist. It was just tiny. It wasn't even a startup. It was like these owners and me, and I was the only developer. It was in Greenfield. There was like kind of a code base. But I worked there for like a year and a half. And so I was in this kind of unique position where like every bad decision that had been made was like past me. Like always. Like there was no point in doing like a get blame to see whose fault like this bad code was because it was always me. And it was bad because it was my first job and I was learning Ruby like as I was doing it. And now I'm in this position where I'm like the oldest, longest running developer at my company and so there often is like bad code that we can look back on and like it's kind of a joke because like I'm aware of it and they'd be like, "Jamey, what were you thinking?" And I'm like, "I don't know. I was thinking that as a new developer then and I didn't know what I was doing." But I think that like there's a skill to being able to admit that and it can be tough because it's kind of humbling. And so, I'm wondering about like if you're in a situation where you can admit that, then it's one thing. But if you're in a situation where you yourself or maybe someone else like can't admit like there's some code that has problems that they wrote and there's like egos getting in the way, that might be like a different aspect of this that we could discuss. CORALINE: I would challenge you on one thing, Jamey. You said bad code and I try really hard to keep value judgments out of code because really bad code is going to put you on the defensive, right? It's going to put anyone on the defensive. And it's not really descriptive and it doesn't really lead to action. So you can say code is too slow, code that doesn't follow canonical Ruby style. You can talk about code that is error prone. But I don't think a value judgment helps you or will motivate you or will will lead to that humility and that being humble about what you are in the past because a value judgment is necessarily going to bring into some emotional component, which isn't really helpful when you're looking at code, I don't think. JAMEY: I think that's really valuable and I totally agree and I would clarify that. I wouldn't call, I probably wouldn't use the phrase bad code. The only reason I use it is because I was talking about my own code. So, I feel like I have that right. [Laughs] REIN: I call my own code 'bad' all the time. And the thing I'm trying to stop doing is telling other people that may code is bad. SAM: There's a question that I use that may help you shift out of that, which is, what does this code have to teach me? CORALINE: I like that. REIN: When I think about making a value judgment, what I think is that there are criteria that I'm using either implicitly or explicitly to form this value judgment. And by giving people the value judgment and not the criteria, I am sharing the least interesting and useful thing and hiding all of the useful things. CORALINE: You can't act on some -- like the reaction to 'this is bad' is, "Oh, I guess we should get rid of it." And it's not always the best way forward. REIN: Because sometimes it's a visceral, effective reaction. It just feels bad to me. But if I take the time to try to process that, I can come up with better feedback. CORALINE: Even saying it feels bad to me or it makes me feel bad, it's better than saying it is bad. JAMEY: That's a great point. A thing I try to think about is like, it stresses me out. Like it stresses me out to look at this code. SAM: Right. I look at this code and then I have to unpack what it means in English. REIN: Because this gets into the psychology and cognitive systems a little bit, but those feelings are coming from a part of our brain that's still processing information but on a different level. CORALINE: I think when you are acknowledged you're having an emotional reaction to something, it's really important from an emotional intelligence perspective, and I cover this in my programming empathy talk, identify what triggered it and decide what you're going to do with it. The feeling is valid. The feeling is something [crosstalk]. SAM: And identify the feeling itself. CORALINE: Yeah, of course. Yeah, identify the feeling. [Crosstalk]. SAM: Sorry for the crosstalk. CORALINE: No, that's perfectly valid and that's a great point to make. But we have a decision point like we can decide 'I'm going to walk away from it'. We can decide 'I'm going to burn it down'. We can decide 'I'm going to work with someone else to see how it can be improved'. We can decide 'it doesn't matter'. REIN: I'm trying so hard not to name drop someone right now... SAM: [Laughs] REIN: But the feelings are for ourselves and we get to decide how we share them with others. SAM: Is it Virginia Satir? REIN: It could be. SAM: [Laughs] REIN: No comment. JAMEY: It could always be Virginia Satir. REIN: Our reactions that we have are valid, but then we get to decide what we do with them. CORALINE: Exactly. I got you to name drop Virginia Satir. Now I name dropped Virginia Satir. [Laughter] REIN: Stop saying it! Oh, no! I said it. SAM: So, we've talked about how to convince somebody who is a product owner that you aren't necessarily wasting time refactoring. But the other person that you often have to convince to care about refactoring is a coworker. And whether or not that coworker is the person who wrote the original code that you're looking at, you still have to have a conversation with them about where you're going to go with it and whether it's worth the effort to clean it up or what. And I've seen people come down on a lot of different sides of this and I'm curious where you all have had experience with trying to make this argument. CORALINE: I think having the discussion around it is valuable because you may be acting viscerally, maybe reacting viscerally to looking at a piece of code. And it can really be a good thing for you to get like a second opinion on whether it's even valuable. If it's valuable from like a rational perspective as opposed to just the emotional trigger you get from looking at the code. REIN: I keep coming back to this idea that there are many sides and that the truth is somewhere in between often. I have an idea and they have an idea. And if we combine them, we'll probably get closer to reality. SAM: My idea is this could be better and their idea is this was perfectly fine. REIN: Or maybe that's not their idea. Maybe their idea is, "Yeah, it could be better, but we should work on this other thing instead." CORALINE: I swear that's where the team dynamics really come into play. I think that [inaudible] of where the company is. If you're in a company where it's maybe early stages and as an engineer on a team of five, you have a lot of autonomy, that's very different from a more mature company with working software that's delivering value that you want to change but it is initially tied to any value beyond your own sense of satisfaction with having written better code. JAMEY: That's a great point because I was thinking of almost the opposite, which is like when I was kind of talking earlier about like there are different reasons that one might be resistant to refactor and I think one of those reasons might, like particularly at a small company since that's where like all of my experiences, it's like we literally don't have time or enough people to do that. Like we literally just can't, like maybe we all agree that it's a good idea, but like we're just too understaffed and we can't. REIN: One of the things that, in terms of like the full lifecycle of the code asn the system that I think is really important that we kind of haven't touched on yet. We talked about like how do you know what to change things into if you can't know the future is that it's a cliche but it's very true. The only constant is change. If our code base isn't changing is because our company is no longer in existence. And Sandi Metz talks a lot about you don't refactor code to change it to the way it ought to be in the future. You refactor code and you write code so that it can be changed to make it more changeable. And that's a value that's really hard to describe concretely. The resilience community talks about adaptive capacity, which is our capacity to adapt to unforeseen futures and about being poised to adapt. And when I think about refactoring, what I often think about is how can we make our code more poised to adapt to changes in the future. Like we often know what code is likely to change because it's often yesterday's weather. The code that changes tomorrow will probably be the code that changed yesterday. And so we can come up with some ideas about what code is likely to change and then use that to drive our decisions about where we focus our refactorings. CORALINE: I like that idea of adaptive capacity. I think that's really good. And that also ties into what we talked about with intentional debt where maybe you set criteria for when the proper time to go back and refactor is based on how many transactions per second can this code handle or other factors that are measurable. REIN: Because when you incur that technical debt intentionally, you're also intentionally underwriting a risk. And the risk is that you're intentionally making the code harder to change in their future and the risk you're underwriting is, you're going to need to change it real fast. SAM: Under intense pressure. REIN: You didn't predict, but suddenly this is the most important thing for the company. It has to be done yesterday. And if only you would spend the time to refactor. SAM: Yeah, that was the thing that I've today learned, especially at one particular job where this company had gone through their hockey stick growth phase. Then I came in later and I made the mistake of sharing one of those. This is crap jokes that I like to make when I know that code is mine and I made the mistake of essentially saying that about somebody else's code, and the political implications of that were really not good. And what I found though in the aftermath of that was that I really had to clarify. "No, I have to say that I have to respect the way that this code is because if you hadn't done it like that, I would not be here to to criticize it. You wouldn't have gone through that hockey stick phase if you hadn't written the code this way and you wouldn't have made so much money that you could afford to hire somebody who specializes in cleaning that stuff up." REIN: I love that so much. One of the things I noticed when I do code review is that some code is easier to review than others because it's more revealing of its intention and so on. And I find that code that is easy to review, it's easy to give feedback on is also easy to change because it's easy to give a code review. You have to understand what the code is doing SAM: And in order to change the code you have to understand what the code is doing. So those are correlated, aren't they? REIN: Yeah. And so when I see code and I'm reviewing code and I go, "I don't really have a lot to say about this," is it because it's perfect or is it because I don't understand it? CORALINE: It ties into what I was saying earlier about significant changes should trigger a code walkthrough as opposed to just a code review. If the very first time you're seeing code is in a PR, there's that old joke that a five line code change will get five comments and a 5,000 line code change will get five comments. That's a real factor. And I think we're doing a disservice to our coworkers if the first time they're hearing about something or even thinking about a new design is in a PR. REIN: Yeah. Let me make a maybe contentious argument. If I read code and I say, "Wow, there are 10 obvious ways that you could change this to make it better," that's a sign that the code is good and not a sign that the code is bad. If the code was bad, what I would say instead is, "Wow, this doesn't feel good, but I don't know what I would do about it." SAM: And so it's not that the code is good or bad, it's the code is more or less understandable to you. REIN: Bad in terms of my end goal of changeability. SAM: Sure. CORALINE: It's amazing to me as an aside, how I think the four of us in general demonstrated a lot of empathy toward other developers. Maybe a little less kindness sort to ourselves, but almost all of us have called code bad or shitty over the course of this podcast. That's really how we're wired to respond to things is very viscerally. And I think we have little habits that we should all work on changing with regard to this value judgements. REIN: It's interesting that I have to be really intentional or I fall into those habits. And then it's much easier for me to be intentional when I'm being considerate of the feelings and the emotional state of someone else. CORALINE: Yeah. We don't have a tendency to be very kind to ourselves and I fall into that all the time. SAM: Yeah. I find it sometimes very informative to look at an interaction that I've had with myself and ask if I would say that thing to somebody else. Or if I see an interaction between two people or like the way that I sometimes treat members of my own family, I look at that and I think, "Would I treat a coworker that way?" And the answer is often no. REIN: This has turned into a therapy session and I'm here for it. [Laughter] CORALINE: Actually my therapist, they point this out to me when I was being self critical. She was like, Would you say that to a friend?" And that's absolutely a tool I learned from therapy. SAM: Yeah, absolutely. JAMEY: I've said this on the show before, but I love when people start a story with like 'in therapy' or 'my therapist said'. It piques my interest and I feel like my ears just like pick up and listen because I'm like, "Ooh, free therapy." SAM: This is going to be good. [Laughter] SAM: All right, free therapy. That's our episode title. [Laughter] REIN: That's honestly like what [crosstalk] for me. I'm not even joking. SAM: Same. JAMEY: It's not free. You have to pledge to us on Patreon. REIN: It has a cost. JAMEY: But for real, you should pledge to us on Patreon and then you can join our cool Slack community and get more therapy. CORALINE: How would I go about doing that, Jamey? JAMEY: Oh, you can go to Patreon.com/GreaterThanCode and you can pledge at any level, even a dollar. Then you can be on our Slack. CORALINE: And our guests from the show in the Slack community too? JAMEY: They are. All of them are actually. CORALINE: Wow. What an opportunity to learn and grow and share what we've learned from our collective therapists. REIN: You have to pledge like $100? JAMEY: No, you can pledge even $1. SAM: And if your circumstances changed, do you have to keep pledging the same amount that you started with? JAMEY: Nope. You can change it. SAM: Wow, this sounds amazing. CORALINE: This has been a lot of fun. I've definitely learned some things. I'm going to go and Google adaptive capacity and see if I can bring that back to my team. So, thank you for that, Rein. And Sam, thank you for the topic. I think it's really interesting when something starts as a thought and we put it on Twitter, we get discussion and we don't often have a chance to really dig in. I don't think anyone would welcome a Twitter thread that said everything we said in the show today. SAM: No. [Laughs] JAMEY: Almost as if Twitter isn't the best platform for long nuanced conversations. SAM: Really. JAMEY: Who knew? I know. SAM: We'll find out more about that. REIN: By the way, adaptive capacity is also [inaudible] John Allspaw's consulting company. He was a former guest and I've learned a lot about resilience from him. CORALINE: Nice. REIN: Which I guess brings me to my reflection, which is that I think a lot about whether things are viable in terms of can they continue to exist in the changing environment. The goal of resilience is viability. The goal of resilience is to keep the thing existing by being resilient, by doing things that make you more resilient. And when I think about refactoring, I think about it as being a part of resilience or viability. I think if we can identify, Jamey, you were talking about like how much runway do we have with this query that we're doing and things like that. If we can identify these threats to the viability of our code base of the systems and we can address them through refactoring, then we give the entire system a better chance of continuing to exist. And I think that is a really big value over liability and of refactoring. And if we can find some way to share that understanding effectively, I've found that it helps to convince people to do refactorings. If we can say, "Hey, we've got about six months until this thing stops to work if things go the way they're going now, and we can get out in front of that by doing this, by refactoring this or by changing this other system," let's do that. SAM: So I have kind of a [inaudible] reflection, which is that this started because I gave a 35, 40 minute talk about refactoring. And then somebody asked a question that fit in a single tweet. And now we have had a call that is at least twice as long as the original talk that I gave and said absolutely nothing about the actual technical skills of refactoring. And that really to me, brings it back to the whole reason we do this show, which is that once you get past a certain point, the technical skills are not your limiting factor. It's about dealing with people and trying to work effectively with and for them. So I'm glad that we're all here. REIN: So in the resilience community, they often say that an incident is an encoded message about your system. And I find a lot of encoded messages all over the place. A tweet turned into an hour-long conversation because that tweet was an encoded message that contained all of the seeds necessary to have this conversation. SAM: Nice. Well, thank you. I was really looking forward to having this conversation with all of you and it was even better than I could have hoped. I learned a lot of wonderful stuff and it's so great to have such good friends to talk about interesting things with. And listeners, I hope some of that comes across to you and that you feel like joining us and joining the conversation. Either way, we'll be back at you next week.