 I just gave this talk at PyCon two days ago, but they didn't let me drink beer during. So I think I'm going to have a better time today. So I cut it short if you want to see more there. The slides are on SlideShare. There's a video, but I've been a developer for eight years now working in giant banks and tiny startups and five different programming languages. And I've seen a lot of technical debt. I've seen some things. I think anyone who writes software has seen some things. So what exactly is technical debt? It's a series of bad decisions that are both business and technical, and they lead to architecture and code that's really error-prone. So you need to use more resources, but you end up accomplishing less. But really in layman terms, it's what decisions were made in the past that prevent me from getting shit done today. So some causes of it are me and you. I hope that doesn't come as a surprise to anyone. So if you've written code, if you've written 10 lines of code, you've probably been somewhere created technical debt. So some mistakes that I made early on were I didn't really see the value in unit tests. So my code worked. Doesn't that mean I'm done? No, actually. I didn't really know how to say no to features, so I ended up just creating a lot of feature bloat. And I kind of ended up giving overly optimistic estimates because I didn't value tests. Or I'd be like, I'll get this done in an hour. And it wouldn't really account for the tests, or iterating, or refactoring, or anything like that. I didn't really care what my design looked like, or if my code was reusable. I promise I've learned the error of my ways since then. So things that kind of lead to that is a time crunch. It's like, ooh. It's like this project was due yesterday, so I'm just going to fix it now. And I'm going to, you know, I'll clean up my mess tomorrow. So how many of you have said that? And how many of you go back tomorrow to fix or clean it up? Like, four people? I see you. You can raise your hand high. Yeah, it's a good thing. We should applaud. So all this ends up in some really unneeded complexity. I've worked with some developers who think that lines of code committed equal the amount of work that they've accomplished. I will tell you that this is very much not true. So sometimes if you come up with a really simple way of doing it, you're like, maybe I missed something. Maybe it needs to do some of these other things, or if it's too simple, I haven't proved how smart I am, or simplicity is a really, really good thing. Even for yourself, if it's just you, when you come back two months later, and you're like, what was I even doing? Simple is good. Less code is good. Some of the things that can cause it is a lack of understanding. So I think we've all gone through this workflow. Step one, we have a problem. Step two, we look up how to do it on Stack Overflow. And then we copy and paste it into our code base. And it works, right? It's great. But no, question mark, question mark, question mark. At some point in the future, you might end up with some serious bugs. So don't put it in your code and forget about this. If you're going to do it, you're going to have a really bad time. So even if it's just some hot fix, make sure you understand it. And you have some idea of why someone else's fix works before you just paste it into your code base. And then technical debt ends up leading to this culture of despair. So this code base is already a heaping pile of trash. And who's going to notice if I just put this broken bottle on top and walk away? So even if it was a heaping pile of trash before you got there, that's not an excuse to try to sneak things on top. So some red flags. How do you know you have it? Code smells. So code smells are not bugs, but really they're just an indication of a deeper problem. Things like lots of duplicated code, really long methods, classes. My rule of thumb is if it doesn't fit on one screen, then it's too long. You shouldn't really have to scroll. And then that contrived complexity that I talked about. So a few more code smells, half implemented features. Someone thought we needed that at the time. We didn't, but it's still on the system. No documentation, poor documentation. So some cowboy coder is like, I'm just going to hack all this stuff out. But really that means your code base is an optimized for teamwork. It's optimized for that one person. So that's not a great thing. And also if you're writing Python and you have doc strings and you use something like Sphinx for code generation, then you get a lot for free. I'm going to put down my beer so I don't look like an alcoholic in this video. Some more commented out code. Incorrect comments, no tests, broken tests. So if you're trying to skim the code of something, you don't have time to sit there and read it and really deep dive. If you have a bunch of wrong comments littered around, you're going to get a bad idea of what's going on. And then in my opinion, as far as tests go, if you're not going to be diligent about testing, broken tests are so much worse than having no tests at all. Because I think we all hate seeing that little red x, right? So if you try to run tests and you just get negative reinforcement, you get these red x's all the time, you're not going to want to run them. So if your tests are broken and you have some serious code problems, just take them out until you can get things sorted. So poor documentation, you're thinking, how bad can it really be? Well, so I borrowed this sample code from Raymond Heddinger, but I changed some things. So we have a pizza factory, and it serves this awesome, organic, gluten-free pizza. But we ran out of dough. And we don't really have time to do things right. So we're just going to comment that out. And instead, we're going to serve this like GMO, gluten-full, awful dough. So if you're skimming through this, I think it would be pretty easy to miss something like that. I'm sorry, I'm just going to stand in this little square, too. I hope that that kind of gets the point of cross. So you can also have some architecture and design. I'll also call them smells. There's parts of the code base that no one wants to touch. So you couldn't pay me enough money to work on the core, that kind of thing. Or if changing code in one area of the code base causes something completely unexpected to break, and this can result in some pretty severe and unexpected outages. So good design. It's pretty easy to implement features, bad design. You just feel like you're shoe-horning things into the system. And it doesn't have to apply all the time, but try to think of it as an 80-20 rule. So if 80% of the time adding new features with the current design is easy, then you're probably doing something right. Some Python-specific smells. If functionality changes, but variable names don't. I hope you all know why that would be a bad thing. So we have some employees, but someone comes along and changes employees to Bob somewhere, and then you want to get the first employee. And in this case, you're expecting John, but really, you're just going to get a big, old capital letter B. So not at all what you'd expect and could probably cause some subtle bugs. So if you're changing data types, try to keep your naming consistent and go through and check all the places where that's used. Monkey patching. Who's done some monkey patching before? Get out of here. Not welcome. So if you're doing something like this outside of a test, you might want to re-evaluate why. What's that? So if you're patching some sort of library or something, maybe you should just rewrite the feature or try a different library. Decorators, so what exactly does that decorator do? In this case, mine is evil and just changes the return value of the method to false. Decorators are an extremely powerful tool and they can mess with any arguments passed into the method, return values. Decorators are not usually evil. They're actually pretty great, but if you're using decorators from some code base, especially if they're home brewed, maybe you should go take a look and see what they do and understand what side effects they can cause before using them. Circular dependencies. If you're doing this, chances are there's something horrible going on. Just so, if you're doing this just to avoid having circular dependencies, there's a good chance you have a serious design problem. How do you battle this monster? And I just want to make a point that bad code, code smells, these things are not technical debt, but they're just like, they're an indication that you probably have some deeper problems going on. So first, don't point fingers. If Joe, some guy that worked there four years ago is the cause of technical debt and he quit, well, he hasn't worked there in four years, so you can't really point your finger at him. If he still works there, you still should not point your finger at him because technical debt is a team-wide problem and everyone really needs to be a part of the solution, so take responsibility. It happens. Work together. So come up with some code standards. For us Python developers, Pepe is a great start as to how your code should look, but there are some nuances, so maybe someone likes 80 character lines and someone likes 120 character lines and whatever it is, just pick something and stick with it. Other programming languages don't really have it, so if you have other stuff in your code base, create code standards for that as well. I like to say that a really elegant code base is one that has been worked on by multiple people, but looks like it was written by one, so if you have that, you're very lucky. And then pair programming is really huge. Sometimes you're working on some code and in the back of your mind, you're like, that's kind of a bad idea, but when you're pair programming, you think something is a bad idea and you skip over it, chances are someone will tap you on the shoulder and say, actually, that's a bad idea, let's work through that. And then code reviews are the golden standard, so my rule of thumb is unless something is on fire, like literally that garbage can is burning down or something or you're losing a lot of money, unreviewed code should really never be merged into master. It's like those little things, those little excuses and those little ways that bad things sneak into your code that kind of end up adding up. So stay accountable, unit and integration tests are huge. Pre-commit hooks, so run your test before committing your code. Continuous integration, I'm a huge fan of Travis, so you'll have a little green thing or a little red thing on your pull request and it's great, Travis says your test failed, well then just don't merge that branch back into master. Now, how do you sell all this to management? It sounds like it kind of takes a lot of time. You really have to tell your manager that when you take time to tackle technical debt, it improves productivity in the long-term, features are easier to add, your code is better, it's easier to maintain, there's less bugs, less problems, less failures and managers like charts. So I made this one, I call it if it's not broken, the why fix it chart. So we have this like red project that doesn't maintain any, like doesn't have any tests, doesn't tackle technical debt. On the left we have cost on the bottom is time, so when we first start on this red project, it's like look at how fast we're doing things then as time goes on, the cost for features, skyrockets, well that green line is the project with the tests and the project where people go and clean up after themselves and so it kind of starts out at this higher cost but then it also maintains that same cost. So over time, the cost is generally cheaper. Managers also like scheme, so you can explain it as a ski rental problem. You know, you're going skiing for an unknown number of days, it costs a dollar a day to rent, $10 to buy. So renting is, you know, not maintaining your technical debt and just kind of skirting along whereas you could just pay that $10, tackle some debt and then you own those skis. There's a little Wikipedia article at the end and there's some other fun examples about ski rental problems. So there's another cost to having a ton of technical debt in your system. It's, you know, hiring developers is really hard and you need us more than we need you and technical debt really frustrates developers, makes us super mad and frustrated developers are more likely to quit. So, you know, if you're looking for a new job and it's a smaller company and you have the opportunity, a word of advice I can give you is see if you can sign an NDA and then pair a program with someone or take a look at their code base before you sign their offer and check for some of these red flags. If they're all there, maybe you don't want to take that job. So, you know, some debt is inevitable, every project kind of has a tolerance, you know, try to tackle it, but don't be a perfectionist. You can use these just arguments to justify this to managers, but like in the end, if they're still like no, you can say, well, someone who maintains my code might be like a serial killer and if I don't maintain it and they're just gonna like come get me, they know where I live. So, tell them it's for your safety. So, pay down the debt, you want to prioritize, what are the biggest pain points, try to tackle those first? The shelf life is also something that you should take into consideration. If like you're working on banking software and it has a long shelf life, pay more attention towards tackling debt. If you're working on a Yo app and it has a shelf life of five minutes, then you can probably afford to accrue some. So, just like with monetary debt, pay off the high interest stuff first. You can also be strategic about it. So like with that Yo example, you know, if you made Yo and you paid no technical debt and your thing was super successful for, you know, three months, well then you kind of won. You got, you know, something for nothing. I'm not gonna chat about refactoring, but if you'd like to come talk to me about it afterwards. So, I'm just gonna leave you guys with a few tips. To make time, if you have a small team, try to devote a week every six to eight weeks. If you have a medium size team, maybe one person on rotation for a week. If you have a large team, you can kind of afford to maybe spend 10% of everyone's time cleaning up. And then I'm gonna leave you with my one of my favorite quotes. So, there's this Boy Scout rule and the Boy Scout rule is always leave a campground cleaner than when you found it. So, when you go camping in the woods and you see, you know, a broken bottle, pick it up and take it with you. Uncle Bob Martin has applied a similar rule to programming and he says, always check a module in cleaner than when you found it. Cleaner than when you checked it out. So, if you have that heaping pile of trash, maybe instead of hiding something on top, you should pick it up and take it with you. And then you're gonna be like super frustrated doing this. You know, your technical debt might have built up over months, days, years, you know. It could feel like untangling a ball of yarn. So, really you should expect to be frustrated and please don't give up. So, thank you guys very much.