Crafting Code Podcast

~/podcast

$ cd episodes/031-clean-code

~/podcast/episodes/031-clean-code $ ls -1a
. .. episode-summary.txt published.txt references.txt themes.txt transcript.txt get-mp3.sh
~/podcast/episodes/031-clean-code $ cat episode-summary.txt

The concept of clean code is one that Dave and Allan feel is very important. But sometimes we hear or read of people saying it is unimportant or unnecessary in some cases. In this episode, we explain what we mean by 'clean code' and why we think it really matters. After all, it's exponentially easier to make a mess than it is to keep things clean.

~/podcast/episodes/031-clean-code $ cat references.txt ~/podcast/episodes/031-clean-code $ cat themes.txt ~/podcast/episodes/031-clean-code
$ cat transcript.txt

[00:00:16] Allan Stewart: Welcome to the Crafting Code Podcast, where we discuss the importance of doing the right thing at the right time with the right tools. I'm Allan Stewart, a software architect, and lately I've been thinking about balancing system health against seasonal needs for new product features.

[00:00:31] Dave Adsit: And I'm Dave Adsit, a VP of engineering. And recently I've been thinking a lot about AI. Is it a boon? Is it a bane? Or is it just a scam?

[00:00:40] Allan Stewart: The topic for this episode is clean code. Dave, what even is clean code?

[00:00:47] Dave Adsit: This is a question I've been thinking about for a long time, since I was first introduced to it when I bought a copy of Robert Martin's Clean Code book. It's gotta be forever ago now when it was brand new. But in the last few years, my personal definition of clean code has come to be a code base. Let me scratch that a little bit, go back a little bit. Okay. In the last few years, I've come to think that a code base feels clean when the cost of delay to deliver a new feature is low relative to the value of that feature. So in other words, clean code is code that can be changed in a reasonable timeframe when our needs for the code change or when we have a new feature we need or a deeper understanding of the domain. Clean code should be maintainable and extensible without starting over.

[00:01:47] Allan Stewart: I like that definition. It's kind of working backwards from the result that you want. This is the outcome that we want. And so code that allows that must therefore be clean.

[00:01:59] Dave Adsit: Right. Doesn't tell us a lot about what the characteristics of the code are along the way. It just tells us how the code behaves once we have it.

[00:02:07] Allan Stewart: Sure. I like that. And I'd agree with that outcome. My own definition is maybe a little little bit closer to a book definition, I guess. But for me, it kind of boils down to code that is easy to read, understand and maintain. And that fits with what you were saying. If you can, when you open a piece of code, and you just, you don't understand, like, what is even going on in here, you're scrolling up, you're scrolling down, you're trying to divine the, the intent of these names, or, like, what exactly does this function do anyway? Because it doesn't communicate that well. That is unclean. And it's hard to work in. It's hard to understand what's going on. And so you're more likely to break things. So yeah, that's one of the pieces of my definition. I also like self-documenting code as part of the definition, eliminating the need for comments, by actually encoding intention and meaning right into the code itself. And that way, if things change later, that's okay, because a rename refactoring will pick all those up and you're not left with these extra comments that are floating around.

[00:03:28] Dave Adsit: Yeah.

[00:03:29] Allan Stewart: I'd also say, and this is kind of, I guess this one's kind of cheating, but just generally good cohesion and coupling. When I look at some code and I see that things that don't belong together are all intertwined and the coupling is super high, then I automatically just think, well, this is not very clean code because they haven't separated individual concepts apart in a way that you can follow the train of thought. Lot. And then finally, consistent patterns. If I go into one file and it is formatted differently than the next file, and then the third file is yet different too, it's really hard to read. If people have different naming conventions and it seems like 60 different people all independently were writing different bits of code, then it's hard to work through that. So those things kind of come together into my definition.

[00:04:29] Dave Adsit: I think it's interesting that you talk about good coupling and cohesion, because almost all of the patterns and practices, not the patterns, but all the practices and techniques that we use in software development boil down to having loose coupling and high cohesion. It really, those really are core to what we do when it comes to software development. I liked other aspects of that definition as well. Self-documenting code made me think a lot about the practice of having a ubiquitous language for the domain that you're working in, whether that is specific to the domain of software engineering or specific to the problem domain of the code that you're building. Yeah. And having some of both of those can be very useful. For sure. Almost essential. So I guess the question then becomes, we have definitions for clean code. Why does clean code even matter?

[00:05:25] Allan Stewart: Yeah. Clean code matters to me a lot around that coupling and cohesion problem. I want to work in code where I can go in and achieve those outcomes that you were talking about in your definition. I don't want to edit code just for the sake of editing code. That can be kind of fun. We've We've talked about the difference between like code as delivering value versus code as art. And I definitely enjoy writing code. I think it can be really fun to solve a hard problem or just get in and see the computer bend to my will. But ultimately, day to day, I want to work in a system where I feel like it's not going to be really buggy. It's not going to be constantly plagued by firefighting and unexpected work because, oh no, some, you know, big client X can't do the thing that they thought that they should be able to do, and that you're just sifting through and trying to figure out what is even going on. I want to be able to write features that that deliver value and do it in a way that is relatively bug

[00:06:41] Dave Adsit: Yeah, I think one of the things that to me is important about clean code and leads to my definition is that I think of coding as a craft, and our purpose in the craft is to deliver some kind of value for someone. One. Most of the time it's delivering value for the customers of our business or other employees of our business. And so to me, what I'm looking for in clean code is code that allows me to deliver value often and without too high of a cost. I guess what it all boils down to is just, I want to have a low cost of delay in creating new value for my customers and users. And so that can be accomplished in a lot of different ways. Clean code is one of the tools and techniques that I've used throughout my career to make that happen. Every developer I've ever worked with has wanted to have a positive impact on the organization that they're working in. We all, they, we, all want to deliver value, make people happy, make people's lives easier in some way or better in some way. Every engineer I've worked with has tried to create a positive impact where they're working. And I find that when you're working in a clean code base, you are able to have more of a positive impact in a more reasonable timeframe. And I mean, frankly, you start to get some of those returns on investment in terms of dopamine hits for like, "I built a thing and somebody liked it and now I'm happy. They're happy and that makes me happy." Right. And so having that positive impact, I think is super rewarding, both emotionally, but also, I mean, if we're good at writing clean code, we get rewarded. Financially as well, because we can deliver more, more often, more consistently.

[00:08:41] Allan Stewart: I agree with that. I was thinking back, you mentioned Robert Martin's book, Clean Code. And for me, reading that book, it came at a time in my career that was very, very pivotal for me. And Clean Code is one of those pieces, or like one of the things that changed how I view code, how I think about writing code with other people and so forth. It was around that same time that I was learning some other things about DevOps and test-driven development and some interrelated practices. But I do remember that prior to reading Clean Code, there was code that I didn't like, and I couldn't really vocalize what I didn't like about it. I didn't have a framework or a rubric by which to judge this code. I just had just kind of a vague sense of, well, this seems bad. And honestly, some of the things that I thought were good or bad were also just kind of mixed up with my personal preferences. I didn't have a lot of, you know, I didn't have a consistent way of judging that code. But reading that book in particular, and then some other related things around it. I remember I read Martin Fowler's Refactoring book around the same time, and I could start to identify what bothered me in some pieces of code and be able to better communicate why I believed things should be done in certain ways. There's one experience that really stands out to me. I remember I was working at an educational company doing some kind of, like, multimedia, rich internet applications is what we call them back in the day. And it was educational software for students. So, like, K-12 learners. And there was one program in particular or piece of a program that would help them learn about integers. And, like, they, they gave you these integer chips and you could divide them. And so if you had six integer chips, they could be divided in half into three and three. Um, but once you get down to one integer, that was indivisible and you could create these different stacks and you could break the stacks and combine the stacks and probably multiply the stacks. I don't remember exactly what you could do, but the code for it was extremely difficult to understand and it didn't always work. It would get into weird scenarios where it stopped working because the global, I mean, it was just a ball of mud global state.

[00:11:32] Dave Adsit: Can computers even handle integers really? Do we even know how to do math with computers yet?

[00:11:39] Allan Stewart: I hope that one day we will learn. Anyway, I went through a whole process of taking these things that I had been learning about clean code and refactoring, and I just slowly picked apart, like, these things belong together. These things need a new name. This shouldn't be global variable. Let's break it down. Let's identify what patterns. I guess another book around that time. I was learning a lot about patterns like the Gang of Four book. And so I applied a model view controller pattern and it changed the structure dramatically. But all of a sudden it was working great. There were no more bugs. It was easy to make changes. Some of my coworkers were a little bit skeptical because it was unfamiliar to them now. It was a different style of writing code that took some getting used to, but, uh, but it, it's definitely left a lasting impression on me, just the difference before and after of being able to take this code and turning it from a mess into something that I could make all kinds of interesting and useful changes to deliver additional value quickly, which couldn't be done before, before we were taking several days to add each new feature. And then I took several days to refactor it, and we could add a couple of features every day.

[00:13:06] Dave Adsit: Right. Yeah. I remember it's been 16 years now since Clean Code came out. Surprisingly. I remember when I first was introduced to it, I was at a conference that Bob Martin was speaking at and they were selling his book, which had just been printed at the conference bookstore. And I picked up a copy and brought it back to my team. And I was on a team that was trying to do test-driven development and not doing a very good job at it because most of the code we had predated the idea that we wanted to do automated testing. And I was able to use the Clean Code book as a way of teaching and reinforcing the concepts around what makes good code and how can we test it and ensure that it's working. And so it was super, super powerful, super useful for me in that, in that environment that I was in at the time.

[00:14:05] Allan Stewart: Yeah. And it makes me think about how clean code is more like a process than an event. Because you said that, you know, your code predated the desire to do any kind of automated testing, right? And the code, I've seen code like that. It actively resists testing because it is just so tightly wound together. But I think it's really easy to miss the mark and just assume that clean code is just going to happen, that there's some, perhaps some magical people who are able to just write this beautiful code and it comes out perfectly the first time. And I have yet to meet somebody like that. Now with practice, you start to learn patterns. And I think that there's some truth that the more that you practice clean code, you're going to write better code from the get-go. But more importantly, it's this understanding of you're not just going to write code, get it working. And the first time that it works, you say, "well, I'm done now." But then you take these additional steps to say, "OK, how can it be improved further? How can this be more understandable? Is this thing that we just added related to this other thing that used to be in the code? Maybe we should merge them together or maybe something that we thought was the same isn't the same and should be broken apart." And it's that process of going through the code that actually ends you up in a place where you say, "yes, this is clean." Yes, we can work through it rather than it just kind of magically appearing that way. Right. You know, flowing out of your fingers into the keyboard somehow just because this this is clean code because you loaded up your keyboard with a bunch of soap before you started writing.

[00:16:03] Dave Adsit: Right. So one of the things that that makes me think is one of the definitions of clean code from the book Clean Code is actually code that pretty much does what you expect it to. Right. So that speaks to both naming, but also simplicity and someone taking care to make sure the code expresses the domain intent or the design intent. And so, yeah, that is one of the things that you look for in clean code, right, is that it ends up in a state where it's understandable, readable, maintainable, where you can make changes to it in a reasonable timeframe. It doesn't necessarily start there. In fact, almost no code base that I've ever worked at starts there, so much so that some people would say, "you can't have clean code in the early phases of a project or a startup." What do you think about that, Allan?

[00:17:02] Allan Stewart: Yeah, I've heard this before. And I just I disagree. Because if you are successful, you have set future company up for a bad time, if not failure, just outright failure. I think that keeping your code clean as you go is just, it's just necessary for survival. Bible. So yeah, there are times where I don't know what the code should look like. I'm doing something new, something I've not done before, or there's new requirements coming in every day that maybe are changing very drastically because we're doing a prototype or we're the early phase startup, like you were saying. But if we just start throwing things at the wall and make a mess, like, making messes happens exponentially faster than cleaning messes. And so it's only a matter of time before you've, you've generated more mess than you can afford to get yourself back out.

[00:18:05] Dave Adsit: Right. There's that concept of what is the total cost of owning a mess. And if you are not keeping your code clean, you are not able to quickly deliver new value. And if you're not able to quickly deliver new value, the chances that your startup or new product or whatever finds its product market fit before it becomes overly burdensome to continue maintaining it, that's not good. Not good chances, right? The one thing that characterizes every startup I've ever worked at is that we have to go fast. And what do they say about going fast? "Slow is smooth, smooth is fast," right? If we are making a mess, we're going to get in our own way and not be able to go fast for very long. My kids like to pull all of the toys out, all of the blankets out, all of everything out and make a giant pile in the living room. But then they don't have that much fun playing because they can't find the things they actually want. If we can keep things, I advocate for keeping those things clean and tidy so that we can actually find the toy we want when we want

[00:19:13] Allan Stewart: to play with it. Yeah, yeah, I love that quote. Um, you know, the only, the another variant that Uncle Bob will say sometimes is, "the only way to go fast is to go well." Yep. And I think sometimes we get mixed up because you're exactly right, an early phase startup or if you're building prototypes, you want to be able to iterate quickly and you're going to have to have clean code if you want to maximize your ability to iterate, or you have to throw everything away and start from scratch every time, which you're starting from a clean slate and effectively that's some clean code, right? Like, there's no code better than and cleaner than no code at all. And I don't mean no code, like, you know, use, like, a no code solution. I mean, there is no code at all. Right. But, but that's not to say that you follow every practice, right? Like, I think that's where people get confused and they say, "oh, we don't need clean code." No, you, you probably do. You You want clean code, but that doesn't mean that you have to follow every practice, every pattern. Clean code doesn't mean that you had to do a perfect hexagonal architecture for every project. And that the brand new thing that you're starting up that only has three database tables is, you know, perfectly isolated. And you've got, I don't know, you know, a snowflake schema for all of your data analytics. And you've got all this extra stuff, maybe microservices for one service for every table. That's overkill. And it's not necessary any cleaner to do your code that way. And we get confused. We mix up. We confuse the idea of clean code with other concepts that are sometimes related and sometimes useful, but are solving different problems.

[00:21:11] Dave Adsit: Yeah. Well, what if our code has to scale to ones or even tens of simultaneous users? Then we'll be glad that we spent six or 12 months building that microservices architecture. Right. Meanwhile, we burn up all of our operating capital and go out of business.

[00:21:28] Allan Stewart: Right. And you're going to need those microservices for all the developer that is in your system.

[00:21:33] Dave Adsit: All of the one developer that you were able to hire with your meager budget.

[00:21:37] Allan Stewart: Right.

[00:21:39] Dave Adsit: Right. Yeah. So you're right, when it comes to practices, there are a ton of practices that we can use to support our journey towards clean code. One of the things that I pull out all the time, I think one of the first ones to think about is simple design, right? You mentioned hexagonal architecture, simple design, and another pattern for overall system structuring. Simple design, basically you want to minimize the things that you have and make sure they're tested, right, you want your code to be expressive and well tested. It's a good, good place to start. It's not always where we start when we're at the very beginning of our journey. Maybe we're, what we've got a code base that's 10 years old and we're like, "how do I clean from here? Well, I know they didn't do TDD, and I know they didn't do simple design, and I know they didn't follow hexagonal architecture, so now I'm going to have to start refactoring my way to glory." Yeah. Right. I can clean up in the area that I'm in. That's one of the concepts that I like from the clean code mindset, which is the Boy Scout principle or the Scout principle now, where you leave a space cleaner than you found it or leave a campground cleaner than you found it, leave a code base cleaner than you found it. If you are adding to it, don't add to the mess, add to the cleanliness of it. Refactor things as you understand them. You come into a method that's 200 lines long and you don't understand it and you start reading. Well, start applying extract method as you go. Once you understand what a block of code does, extract it and name it. Once you understand what a variable is for, name it. These types of things, the little things that we can do as we go in a code base that help us keep it clean. And those are the techniques that you have to apply always. Because as you said, we rarely start with clean code. If we just, like, write our test, write our first test, great, good start towards clean code. And now I go implement the solution to that test, implement the code that causes that test to pass. Great. Is that clean code? Well, maybe not. Maybe I need to go in and do one more step of refactoring. So maybe even before simple design, the first rule, the first practice of clean code is refactoring.

[00:23:48] Allan Stewart: I could see that. And if you're going to do a true refactoring, you're going to need tests. Otherwise, you're just changing stuff. Although if tests are hard and coming because you're in a legacy code base, I'll take a restructuring or just a hope and a prayer in some cases. But you get at least enough of a handle around something that you can start getting some tests in there. But I also liked what you're saying. It reminded me of Don Norman's book. Is that a design of everyday things? Yes. And in that book, he talks about how research has shown that there's a limited number of things that we can keep in mind at any given time. And when you're reading through some complex piece of code, it makes me think about that, right? There's even, there's even comics that I've seen about this where, you know, somebody, they're in the code and they're like, "well, what does this mean? This, I guess, like, there's this complicated, like, mental graph, mental model that's forming." And then somebody comes and interrupts them. And, like, all of the metal mental models fallen apart and they have to start over from the beginning. Yeah. Well, refactoring is a way of putting that knowledge into the world, right? Going back to Don Norman, you put it into the world. So you don't have to to remember it. What, what is this weird variable? Oh, well, let me rename it now that I understand what it actually is, whether it was a lie or it was just badly named. It was just X. And I don't know what X is in this, in this case, but well, now you don't have to figure it out again. And when you get interrupted, you're not going to have to remember what was X again. Oh yeah. I already changed it. I made it better by virtue of this continuous process of, of cleaning things as you go. For sure.

[00:25:37] Dave Adsit: Yeah. So if we say not all these practices are necessary, refactoring probably is necessary to get to clean code. The rules of simple design may be necessary, may not be necessary. First one passes the test, then it reveals intention, has no duplication and has few elements, the fewest possible elements to implement the solution. So if those are the rules of simple design, I mean, you would say that code that follows those rules is probably pretty clean. Not necessarily, but most cases, probably pretty clean. But you don't necessarily have to have all of those things to be perfectly clean. For example, one of the things that I put on my list of practices that I want to use almost all of the time is either TDD or at least good unit test or GUTS. There's a talk my team watched recently from QCon that was about programming with GUTS. And one of the best ways to get good unit tests is to do test-driven development. So do I want those? Usually the answer is yes. Do I always have them in every code base? No. Do I consider some of the code bases that don't have tests to be clean or at least clean enough for purpose at the time? Probably. Probably sometimes the tests, the tests, I think of, I think of tests as a discovery and design technique, as well as a tool that I use to basically hold the code in place, like a vice or a clamp. So I can work on it without breaking parts. I didn't want to break. And if I'm looking at this code and thinking, this is a prototype that I'm going to throw, I'm going to work on for three days and then throw away. Way, I may not write tests for that because that code is not intended to be long lived. And I may still consider it clean because at the end I'm throwing it away.

[00:27:29] Allan Stewart: Yeah. Another example I think of is the rule of no duplication. And I think that's a good rule, but I love our friend Matt's rule of thumb. What does he call it? It's basically three times is his charm, right? I don't know. The rule of three. The rule of three. That a lot of times in code, if there's a lot of things that are duplicated, that's a big problem. But if you are too obsessive about removing all duplication, then you start this downward spiral of trying to make everything just the same. Like it's all got to fit into this one bucket. If I can just use generics hard enough, they will all be the same. And that doesn't make it cleaner. That actually makes it worse because some things that weren't meant to be duplicated are suddenly now, are things that weren't actually the same and should be separate are now combined. And so no duplication is one that I might, in certain contexts, ignore a little bit and say, "hey, I'm going to allow for two or maybe even three of these things to crop up before I see what the real pattern is and then apply cleanliness to it."

[00:28:42] Dave Adsit: When it comes to duplication, one of the things, one of the concepts that I learned in language learning is the concept of a cognate, which is a word that is basically the same in two languages, right? But you also have things like false cognates, which are words that appear to be the same in two languages and are not. And I think that happens sometimes in our code base as well. Sometimes we, in our rush to avoid duplication, we take two things that were actually different and force them to be the same. And then we later pay the price of trying to make one thing serve two purposes, right? So an example in Spanish, or in English, the word embarrassed sounds very, very similar to Spanish embarazada, which means pregnant. So you would not want to say "I am embarazada" if you are embarrassed because you would be instead declaring that you were pregnant.

[00:29:37] Allan Stewart: Which in turn would make you embarrassed.

[00:29:41] Dave Adsit: It would just increase the amount of embarrassment you are feeling when you realized what you had actually said. So if we are not careful, we run into false cognates. I think one of the things that often leads to not very clean code is the rush to abstract from a single example.

[00:30:01] Allan Stewart: Yes.

[00:30:02] Dave Adsit: If I go and I try to say, "oh, I have one example of this concept. Therefore, I'm going to create a factory pattern around it with the template methods and all kinds." Like, no. Pump the brakes. Move on. When you have two or maybe three, the third time you're implementing something, implement it to fit your current purpose. And then look at all of the places and say, "are these really, in fact, the same? And can I remove this duplication?" So one data point is not a trend. One data point is not a trend. And in many cases, two is not a trend either. So there's a lot of other practices. Let's run through some of them kind of quickly, right? Like, one of the things that I like to do is collaborative programming, whether it's mobbing or teaming or ensemble programming, whatever you call that version, or the more simple and older pair programming where you only have two people instead of the whole team at the keyboard, right? I feel like these are tools that we can use. These are practices that help us increase the cleanliness of the code for a lot of reasons. One is working together, we're going to help each other remember and follow the rules that we've agreed to as a team. Working together, we have to communicate about the code we're writing and communicating about it is the first step to making code that is expressive of the intent and the concepts that that it's trying to cover. And so I like those tools. There's a bunch of other tools you can use as well to get some of the same benefits, but not quite as good. Like, if we're using linters or things like that, those are very valuable tools and I would put them in place. I might not have them for the first six or 12 months of a project that I'm working on. And then I might add one, or if it's really easy and I've set it up recently, I might set one up on day one so that I make sure that I never fall out of sync with the current coding style for the language I'm

[00:31:57] Allan Stewart: following. Yeah. And sometimes the linters either can't or are difficult to set up for certain larger patterns of language. Like, it's one thing to specify if it's going to complain if you've got white space at the end of a line, but it's another thing to try and teach the linter. Oh, in a case like this, we use a particular pattern in the code and communicating that by talking it out together and and learning the language to be able to express, like, what is the difference between a field and a local variable, um, being able to to say, you know, what what is that thing that is, you know, that goes in the parentheses here, is does it have a name, and then we can use that name to refer to it in the future. Yeah, it just it gets you to cleaner code a lot faster because just as you say, we're working on it together and we're kind of coming to a natural consensus about how we want it to be, an evolving consensus even, rather than, well, we set up rules one time and hope that everybody follow it.

[00:33:05] Dave Adsit: Yeah. Well, another tool or practice that I like to use to ensure clean code is continuous integration. And by continuous integration, I'm going to be very explicit. I mean, every single developer on the team, every single developer on the project project integrates with main every single workday. No other thing that you do will count as continuous integration under this definition, right? So every developer is integrating with main every single day. And that's going to help us keep code clean because we're going to have to be working in small steps that we can commit and push. We're going to have to be working in with tools that that allow us to basically put in code that won't necessarily get executed by users, right? So this is a technique that is often very useful for keeping the code clean, right? We're not going to have big merge conflicts. We're not just going to dump a bunch of code on top of each other at the end of the sprint right before we try to release and then have a problem with integrating it for days. It helps us keep the code clean. Absolutely. Again, may or may not use it on every project. Usually I will use it on every project, but there's times, right? Another one that you and I have put in place at one of the companies we worked at together is observability. Actually understanding what the code is doing goes a long way towards helping you understand how to change it effectively, how to maintain it, how to keep it clean, right? And knowing, logging, monitoring, knowing what methods are being called in what conditions is super valuable from my perspective and understanding the code. It can actually even help you identify code that's never called and can be removed from the code base, thus simplifying your overall maintenance load.

[00:34:55] Allan Stewart: That one can be particularly difficult to figure out if you don't have some kind of observability. You might be carrying around a bunch of dead code, trying to maintain it, trying to keep it working only to find out later that nobody has called that in over a year, that, that API, especially at, like, at layers, like a API boundary. So understanding that, being able to, to know what's actually going on in the code. There's been plenty of times where I thought I knew, oh, we're having a performance problem. Well, obviously the answer is X, but then when you go and measure it, it turns out that no, no, that's not the real problem. And only through measuring it, are you going to figure out what was the problem?

[00:35:41] Dave Adsit: So related to both observability and my personal definition of clean code is the DORA metrics that you can track for your code base. Right? We look at things like deployment frequency. How often are we successfully releasing code? The lead time for changes. How long does it take from the time I've committed a change to main until it is in the production environment? Change failure rate. How often does one of my releases actually blow up when it hits production? And then of course, what do I do about it? What is my mean time to restore service once I've identified a problem? So if you're tracking those things in addition to your basic observability, you have that much more insight into whether or not this is clean code. Can I change this code? Can I enhance this code? Is this code super brittle and I don't ever want to change it? Because every time I try, it blows up and then I have a sad day.

[00:36:39] Allan Stewart: Yeah. Right. Yeah. They're lagging indicators of the cleanliness, but they're also indicating whether or not you're actually achieving the objective of the cleanliness. It's not just clean because you're a neat freak or because of some kind of artificial ideal of, well, clean is better, but actually you're getting some measurable, demonstrable value out of the cleanness. Yeah. Another practice that can help sometimes with clean code is having good documentation, right? If the code is good documentation itself, like, ultimately, the code is the only documentation of what the code really does because comments tend to lie, but But the code by itself doesn't often express high level intent. It's really easy to get down into the weeds of the code. And so having some kind of documentation about why does the product work the way it does, what kinds of personas do you have in your product, or as far as product users, what kind of architectural decisions have you made, reasons for why the things are the way they are, can help you to understand and keep the code clean because you're not changing it in a way that gets it out of alignment of what the intent was for the product or the intent was for the architecture. Because you have a signpost there, essentially, that keeps you on track.

[00:38:14] Dave Adsit: Right. In most cases, I would say if your code is littered with Javadocs, I wouldn't consider that super clean. But I do want to have things like ADRs and some kind of a log of the product decisions we made. I want to, it's exactly what you said. I want to understand why the code is the way it is. And I would consider most of the function names and the tests to be part of good documentation for a well-documented code system. Yeah.

[00:38:40] Allan Stewart: And it will depend on what you're delivering as your product. If you're delivering a code library that other people are going to be using, then maybe those Javadocs- Are pretty important there because at the interface, like right at the boundary that they're going to be exposed to. But if the docs are just there for you and the other two developers on your team and no one else is ever going to look at that code, maybe it's unnecessary.

[00:39:05] Dave Adsit: Yeah, hopefully both of you know, or all three of you know how to look at the method name and the method signature, including the return type, and infer what the Javadoc would say if it told you the method name and the method signature and the return type. Right. So other things, other practices that help us with clean code include all types of automation. We've talked already a lot about tests. Automating your tests is important. Automating your tests before you check in, automating your tests when you do check into your centralized server, automating testing in many places is super valuable in helping you maintain and build clean code. I think other tools that I've used in the past successfully, static analysis, understanding cyclomatic complexity, and the coupling and cohesion across my system, visualizing that and looking into those concepts using automated tools to do that kind of analysis. I think one of the things that I reach for right away in most projects is automated build and automated deploy. I want every time I check in, I want the code to be built on a machine other than my development environment. And I want all the tests to be run against it. And I want to see that it actually still works even not on my machine. Right? That is important to me. And then I want to deploy it. I want automated deploys, which help us to keep our code clean because nobody wants to check in code that's going to blow up the staging environment or heaven forbid the production environment. And so we're going to think a little bit more about the code that we're writing before we push it out.

[00:40:46] Allan Stewart: One of the things that I really like about automation and especially test automation is that by itself, it's not a measure of cleanliness, but it's kind of like setting the guardrails that allow you to make change, make change quickly and discover if something goes wrong quickly, right? It goes along with the continuous integration that you were talking about before, like the Trunk-Based Development concept of, like, everybody get together often and we'll know if it's working or we'll know if it has a problem quickly while the change sets are small and we can fix it quickly. So having automated tests doesn't necessarily mean that your code is clean. But if you can quickly find out that a change broke something, that enables you to make more change faster and you can continue on that process of making things cleaner as you go, rather than assuming that because I had an automated test, therefore it is clean. And it's like a state of being rather than a process that you're continually moving towards. Yeah, it's kind of like that, that story from This is Lean, where they brought in the very well respected Japanese leader from Toyota, and they kept asking him, "is this the, is this the leanest place that you've ever been? Like, how great we are at lean. We've done this all over the place. Every part of our factory is so lean." And he didn't really say anything. He was not enthusiastic about it. And they finally are like, "look, is this the best lean that you've ever seen or what?" And he's like, "I don't know. I wasn't here yesterday." I think clean code is that way too. I don't know if your code is clean or not. We'll have to see how it is progressing over time.

~/podcast/episodes/031-clean-code $ cat published.txt

~/podcast/episodes/031-clean-code $ cat ../../copyright.txt

Copyright © 2026 - Crafting Code Podcast