How to Enjoy Debugging in Production with Karen Tracey
Published October 23, 2025
This video features Karen Tracey at DjangoCon US 2022 in San Diego, California, USA.
The term “legacy code” often evokes feelings of fear and loathing in developers. Yet (particularly given Django’s age), working with “legacy” codebases is often required of Django web developers. This talk will offer suggestions, drawn from experience, for ways to nurture legacy codebases so that working with them is not fraught with peril. “Legacy code” does not need to be scary!
This talk was presented at: https://2022.djangocon.us/talks/nurturing-a-legacy-codebase/
LINKS:
Follow Karen Tracey 👇
On Twitter: https://twitter.com/km_tracey
Follow DjangCon US 👇
https://twitter.com/djangocon
Follow DEFNA 👇
https://twitter.com/defnado
https://www.defna.org/
Legacy code is code with a history whose original decisions, constraints, and intended behavior are no longer fully understood. Karen Tracey argues that teams should not automatically rebuild: they should weigh whether the system still meets users’ needs, how serious its production problems are, and whether obsolete dependencies block maintenance. For codebases worth keeping, she recommends an automated, confidence-building test suite, current supported versions of Python, Django, infrastructure, and dependencies, and incremental modernization with tools such as Black, pre-commit, and linters. Longer-term health depends on preserving the story of the code through meaningful commit messages, issue references, repository documentation, and a team culture that records why decisions were made and improves the system in small steps.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: I'm excited to be here at Django Khan again in person. uh after a few years hiatus and I'm excited to give this talk. I uh enjoy myself working on legacy code and I have this impression that a lot of other people are more scared of it than I am. So I'm hopeful that I can give some clues and ways to make working with older and legacy code bases a little more enjoyable. A couple I guess about six weeks ago, I happened to see a video embedded in a tweet that uh I found to be interesting and indicative of how I think a lot of people view legacy code. So I'm gonna play that first and see if this Um resonates.
Speaker 1: Is that what you think of when you think of working with legacy code? This was a tweet by, let's see if I can get this to go to the next page without restarting the video. Whoops. Come on. This was a tweet by Addie Osmani, who I don't actually know, but uh I think he worked at Google and the tweet said, be careful with legacy code. And there's a link there and the slides will be posted. If you want to look and see what kind of engagement it got, it got a lot of engagement. I was intrigued and happy to see that a lot of things that I had thought that I would include in this talk were mentioned in the feedback to that talk, so to that tweet. So I thought that was interesting. So to get into what I'm going to talk about
Speaker 1: , I'll start describing what I mean by legacy code, what is a legacy code base and characteristics, and why it they're often feared by people. Often when you're working with a legacy code base, you start to hear a siren call of we should just start over and build from scratch. And I'll talk a little bit about how to make that decision as to whether to continue to invest in a code base that is causing some problems versus starting all over. But for the most part, I'd like to focus on how to nurture the code base that you have. And I break that into three sections, the prerequisites that I think you absolutely positively have to work do if you're gonna nurture a code base. some easy wins to freshen a code base and on the surface make it less scary.
Speaker 1: And finally go a little bit deeper and talk more about the mindset and the culture of of yourself or the whole team that's working on a legacy code base to try and make it less of a a mysterious thing for developers to work on. When I thought about what an image of a legacy code base might be, this is the kind of thing that came to mind. And I look at this page and I'm like, I can't read that. That's indecipherable. And I feel like that's often it's probably overstating what a legacy code base, how indecipherable it is, but it's it's got that kind of sense of I can't, I don't even understand this. Um at the same time though, there's beauty in that picture There's some beautiful elements, and I feel like oftentimes there's beauty and strength in a legacy code base that may be a bit under-recognized.
Speaker 1: So to switch back to words, what I mean by a legacy code base is it's code with a history. And I put in there a dark history. And by that I mean dim, not necessarily evil. It's like it's an unremembered history And that makes everything a little bit fuzzy. There's a phase a project goes through in its early stages where it's being built and things are getting added quickly and probably more than one person is working on it and maybe you have a whole team including a project manager and testing and everyone has in their head like what this thing is doing. And very quickly you can make decisions and make architectural decisions one week and start working with them and come to realize maybe that wasn't the right way to go.
Speaker 1: And because everyone has it in their head what this thing is and what all the impacts are, you can change that architectural decision in the building phase and be confident that you've fixed all the problems that that change cost. A legacy code base is not in that phase. No one has it in their head, what all the architectural decisions were and what are the impacts of changing them. Oftentimes, The current developers working on a legacy code base didn't work on building it. Or if they did, it was so long ago that they don't remember what they were thinking when they were making decisions. So There's a lack of familiarity with code base. There's a lack of knowing what it's supposed to do or why it
Speaker 1: why it behaves the way it is currently behaving. Depending on how old it is, it may also follow outmoded conventions. Coding practices change over time remarkably quickly. If something was written several years ago, it may it may have been written before some new features of the language or some new features of the framework existed. So it may be doing things in ways that look really odd today. And that Reason for that may not be understood by people who are newer to the code base and perhaps aren't even aware of the restrictions that existed in the past when this was being built. And finally, usually a legacy codebase is running in production. If it wasn't running in production, it would probably be called a dead codebase.
Speaker 1: And just the fact that it's running in production, either as a project that you're supporting or as a package that is being built up into other people's code. That just amps up the danger factor and the scariness of making a change that might break something. So all of that combines the unfamiliarity and the the danger combine to make it a little bit difficult to work with legacy code. And this is an image I came up with to sort of represent what it feels like maybe to work on Legacy Code. There's an old building there, and there may be some. beauty in its underlying structure, but working on it and the scaffolding around it is just it's difficult and it's maybe hard to understand
Speaker 1: uh exactly what's going on. So it can be kind of Daunting to work on a legacy code base. And then you're often faced with, well, should we continue to invest in this, or maybe we just start over and build from scratch? And it would be prettier and easier. So before I get into nurturing, I want to talk a little bit about what you might want to consider if you're making that decision. And the first thing I think is you need to evaluate whether or not the current code base that you have is meeting the needs of whoever's paying for it, whether that be a client or yourself, um over time, the needs and desires of a client can change over time. And if your code base hasn't kept up, then it may be that it has diverged rather
Speaker 1: a bit, rather a lot from what the client wants it to do. And if that's the case, you may be heading in the right direction if you look at a rebuild. Um but if it's pretty much doing what they want, you might want to think about sticking with what you have and nurturing it versus starting over. A second thing to consider is how much of a problem this code base is causing in production today. Is the site going down? Is the site losing data? Do you have a support team that is overwhelmed with user complaints? All those might contribute to saying, well, we really should start over. Although there's a caveat there, usually a rebuild is not a quick thing. So if you have serious production
Speaker 1: problems today, you probably need to at least mitigate those while you're rebuilding. Finally, and particularly for Django projects, because Django has an ecosystem of open source plug-in projects that you can take advantage of that it has been there since forever. You may have built your project and incorporated other things other things into it that solved particular problems and over time those the people who maintained those projects and built those projects may have moved on to other things and they may not be maintaining those projects anymore And you may find that those projects are hindering you from keeping your code up to date because you can't update Django because they use older things. So you have to come to a a decision of do you want to keep using that? If so Do you adopt it?
Speaker 1: How do you keep that dependency from holding you back in updating your own code? And you can adopt or you could find an alternative maybe that is healthier. If you have built your project around something large like a whole CMS or an e-commerce site that has gone unmaintained, that may be a a reason that you need to really think of a big refactor. or a rebuild because you probably don't want to take on writing your own CMS or maintaining a CMS. Maybe you do. I don't. So assuming you're gonna, you've just chosen that you're gonna continue to invest and nurture this code base. Um start uh diving into how to do that.
Speaker 1: And here I have fallen back to kitty pictures. This is a mama nurturing her kittens. These happen to be kittens that I was fostering a few weeks ago. So I'll start with the prerequisites of what you absolutely positively have to do if you want to say you're nurturing your code base. And the first is to have a test suite that is good and automated. And you could have a whole Talk on what makes a good test suite, but for my purposes for this talk, a good test suite is one that will give your developers confidence that when they make a change, they haven't broken something. And they can be confident that they can do that and it won't break anything in production. And it should also be one that continues to grow as
Speaker 1: As you hit production problems or problems that are found by QA, write a test case that would have covered that, that would have caught it, and make sure that you're expanding your test suite to cover cases where you've actually hit problems Um and the second meat, the second primary thing you absolutely positively have to do is get the code up to supported levels of the operating system, the deployment infrastructure, Django, all the dependencies, Python. You want to do that for the security Fix reasons you don't want to be able you don't want to be in a situation where you're running an old level, Django comes out with a security fix your code isn't covered and you have to figure out is your version of Django vulnerable and if so how you would fix it. You don't want to do that.
Speaker 1: Aside from that though, there's benefits to updating and keeping current levels One is that it's it's a good way to learn a code base to do an upgrade because you're going to hit issues and you're going to have to dive in and try and understand what was going on with the code. And the other thing is it's an opportunity and it often forces you to freshen the code because you'll be updating. And as you update Django or Python, we'll have deprecated certain things and certain older ways of doing things. So you're going to have to move your code on to the fresher, the newer way, and it will start to look a little less foreign to newer developers. So those are the prereqs of nurturing. Next I'll talk about some easy wins.
Speaker 1: This is a kind of obscure picture of easy wins probably. Um kittens sometimes are hard to get them to eat solid food without on their own and these kittens were just easy. They saw mama's food one day and said, Oh, that looks good. We're gonna start eating it. So they were some easy wins in terms of growing up. For nurturing your code bases, some easy wins that have come up in the last few years, at least that I'm aware of, are two things: pre-commit and black. for code formatting and enforcing some consistency of style or import sorting or whatever it is that you that your team would like to be consistent in and have standardized across your code base. I worked on Teams for years before we had this
Speaker 1: and one section of the code was written in one format, another section was written in another format, and it was it could be hard to to navigate between those two and to feel comfortable in both environments. So I find it very easy nowadays that black and pre-commit is there. We've pretty much well at Cactus universally adopted them to help just Bypass all religious war is about formatting, for instance. Um I also find it very helpful to have uh Linter embedded in my code editor that will when I save the file it says, hmm, the string interpolation you got here, you could use an F string. Or this set creation, you could use a set comprehension. So it it sort of guides me in easy ways that I can freshen the code
Speaker 1: base and make it more modern looking. And if I have the time when I'm working on that particular file, I'll go ahead and do it. And it's it'll incrementally as the files are touched get the code to look more modern. That might be automatable. I haven't investigated that. So let's switch to thinking a little longer term and a little deeper about how to keep your code base nurtured. And this picture looked to me like something that would take some time to think about and to plan to create this garden sculpture. So that that spoke to me in terms of how to nurture longer term And here, what I my main goal here is to get to where coders, developers can understand the story of the code.
Speaker 1: And essentially it's trying to get back to, you can never get back to the building phase where everyone had it in their head. But if the story of the code is accessible. in tools around the code, then you can get sort of a glimmer of that building phase back. And it 's helpful to know how to move forward if you can understand why the code is the way it is. And some of the things to think about are what you put in your commit messages. Of course, here I'm assuming you're using source code control. Um, so that's an assumption. You're using source code control and you make a commit and You don't just fire off a brief commit message saying, try this to fix it, but rather be a little more thoughtful about why this change is being made
Speaker 1: and focus more on the why If possible, then like the what, because the what is always going to be accessible to someone later who comes and looks at the commit because they can see the change the code that was changed. Oftentimes the commit message is not really where you want to put all the documentation around a change. Usually You'd want to have a ticket tracker that is keeping track of your issues, keeping track of your new features, keeping track of the bugs, and there's a good place to have your bigger description of the why. So oftentimes if a commit, if it references a tracker issue, would let you record enough information so that someone later on can figure out why this code is the way it is. Another aspect of keeping a code base nurtured is to include in the document, in the in the repo itself, some documentation around common things.
Speaker 1: that the developers may hit over time. So sometimes it's hard to look up in the issue track or something like this like a code base that's maintained over several years and it's got some maintenance things that you do yearly, documenting those in the repo so that the next developer who does it next year knows how to do it can do it. or if there's common server issues that occur and you can document how to solve them and how to get how to get over things like a replica database going down. having that in the code itself is helpful. So essentially developing a culture of leaving clues for the future Is essential, I think, to maintaining and nurturing a code base. It's a current investment.
Speaker 1: It may take a little longer to fully resolve a problem today. But then tomorrow, or actually more likely a few months from now, when you hit a problem, it would be easier for that person to solve it. I'm over time. Oh no, I have five five minutes left. Um so there's one more picture of mama nursing kittens. Uh in summary, legacy code I feel like has often uh a wealth of uh experience and um knowledge sunk into it that is often underestimated. And unfamiliarity with the code can lead to a lot of fear and discomfort around changing it, but I think we can overcome that. There are modern tools that can reduce the friction of just old ways of doing things
Speaker 1: that can be automated up to more newer ways of doing things. and at longer term a a culture of valuing spending time recording why and valuing digging into the why and fully understanding a problem before considering a a Bug fixed is a good way to have a nurturing culture around your older code bases. So my final picture is what a nurtured legacy code base might look like. So it's an older building, but it doesn't look scary. It looks kind of well it looks a little imposing, but doesn't look dark. And that's my talk. Thank you for listening.
Speaker 2: So first of all, let me thank you for your talk with this. Thank you. And were there any questions from the audience?
Speaker 3: Oh, that was speedy. Hey, I wanted to know what's the oldest code base you have worked on.
Speaker 1: What's the oldest code base? Huh. I so I don't know how old some of the ones we've inherited are, um, but we're currently w I'm currently working on one that we built starting in twenty eleven. that we're still working on and that's still in production. So at least a decade
Speaker 4: Cool. Thanks for the talk. Would you do you have any recommendations about maintaining a really nice commit history? Um I mean like most successful codebases become legacy codebases at some point in time. So how can you maintain your history so that it um is something that people can find the story in. I mean like some people like to squash um their branches when they merge, some people don't. Some people like to delete their branches, some people don't. And there's all sorts of different like opinions about what your commits uh like what information to put in your commits. So yeah, anything, any words of wisdom on that?
Speaker 1: That is not something I have like I have not tried to enforce it. Let's do it this one particular way. Personally, I like to only make public a logical change. Like I don't make a lot of small commits, but it within my team I don't like to inf if people are more comfortable making smaller commits, I that's okay. So essentially I would use the tools of the tools of the uh source code control to try and get back to the source. I I do uh often plea please please put a a reference to the ticket you changed it for in there. But it is hard because people do have different styles of thinking. And with a little more effort, we could probably get a little more regular about
Speaker 1: okay, have a merge commit or you know, rebase or do that. But I have not It's not a it's not something I've been willing to tackle as a team-wide thing for myself.
Speaker 2: All right. Any more questions from the audience? Oh.
Speaker 5: Okay, thank you. Good talk. I have a question about sometimes when you're working on a legacy code base, one of the problems is you have a it depends on a library that's now abandoned. Now sometimes when you get to that years later, someone's picked it up or there's multiple successors, but it can be a complicated decision. Do I want to try to make my own version or wait for someone else to do that? Do you have any advice on that
Speaker 1: Um I've seen that too, where something has gone unmaintained and other people have picked it up. So I usually try to find the one that's farthest along and see if it meets my needs. Maybe I can switch over to it. Um it just takes sort of investigating what the status is of of all the various forks that may have been created as a result of the main the original one going unmaintained. I don't think there's any straightforward, easy answer. But I have run across that like oh this one actually got all the way up to this level and I just need to go one further. So I usually start with the one that seems to be the most farthest ahead that I can find.
Speaker 2: All right, I think we had one other question.
Speaker 6: Um hi. Um my question is um How would you deal with maybe not just legacy code but maybe resistance from legacy ways of doing things within the team and if there's any like low-hanging fruit to convince other people to nurture a code
Speaker 1: I didn't quite catch the end of that.
Speaker 6: Maybe if there's any like low-hanging fruit to uh convince teammates to adopt a nurturing code.
Speaker 1: Usually it's just like encouraging starting small, like let's do this new newer thing. in a newer style and then in a newer just try to start taking steps to do things in more modern ways and then incrementally do it. That's my preference. Some people might not like having a lot of disparity and differences in code bases, but I think working piece by piece and smaller in smaller chunks and incrementally improving would be the way I would go.
Speaker 2: All right, well excellent. Let's give uh Karen one final round of applause.
Speaker 1: Thank you.
It is code with a history that current developers may not understand well, including its original architectural decisions and the reasons behind its current behavior. It is usually also running in production, which makes changes feel risky.
Discussed at 4:05Consider whether the code still meets the client’s needs, how much trouble it causes in production, and whether abandoned dependencies are blocking updates. A rebuild may make sense when requirements have diverged substantially or a major unmaintained component needs replacing, but serious current production problems still need mitigation during the rebuild.
Discussed at 7:10You need a good automated test suite that gives developers confidence and grows to cover bugs found in production or QA. You should also bring the operating system, deployment infrastructure, Django, Python, and dependencies up to supported versions for security and maintainability.
Discussed at 10:12Use tools such as pre-commit and Black to enforce consistent formatting and imports, and use a linter in the editor to suggest more modern Python idioms. Applying these improvements as files are touched can modernize the code incrementally.
Discussed at 12:31Write commit messages that explain why a change was made, link commits to tracker issues containing the fuller context, and document recurring maintenance tasks and operational fixes in the repository. This creates a culture of leaving clues for future developers.
Discussed at 14:55She is currently working on a production codebase that began being built in 2011 and is still in use, so it is at least a decade old. She did not know the age of some other inherited codebases.
Discussed at 19:15Make public commits represent logical changes, although developers can use smaller commits if that suits their workflow. Referencing the ticket associated with each change is especially useful; she does not impose one team-wide policy on squashing, rebasing, or merge commits.
Discussed at 20:28Investigate the available forks or successors and start with the one that is furthest along and appears to meet your needs. There is no universal answer, so the choice requires checking each option’s status and compatibility.
Discussed at 22:04Start small and encourage people to use the newer style in new or touched areas, then improve the code incrementally in manageable chunks. This gradual approach is preferable to trying to change everything at once.
Discussed at 23:19Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026