"Alright, folks. We need to build this thing in 3 months. We've got a hard deadline to meet. If you need to hire a contractor or two, do it. But the deadline can't move."
It was the beginning of a new project -- a rewrite of an existing app. We had to get to parity, and our timeline was short. The addition of a few contractors helped, but if you know anything about the Mythical Man Month, you know it's not a silver bullet.
As the deadline loomed, you could feel the pressure rise. I knew I couldn't add more contractors to take on more work -- ramping them up at this point would only slow me down. And the deadline was fixed. So the next logical "lever to pull" was in code quality. I began to cut corners. I left "TODO's" all over the app, I avoided spending time refactoring, and I certainly didn't write any tests. I knocked out the feature and moved on.
Most times this story can culminate with someone telling you how everything went fine until just before launch. But things actually went just fine. We showed off the app to the stakeholders, everyone cheers, and we launched. And oddly enough, things were ok ... for the first week. Then the bugs started rolling in. I couldn't keep up. And now the lack of tests made me scared to change anything. Would I break an existing feature? The TODO's littered throughout the app drove me crazy. Who wrote this crappy code? Oh. I did.
Even large chunks of code that I personally wrote were confusing. No refactorings led to spaghetti code and spaghetti code means spending hours untangling the mess before making any forward momentum. I had hit the deadline, but had crippled our ability to move beyond the launch date. I had won the battle, but lost the war.
Here are a few "small things" that can unknowingly create major problems:
- "We can write tests for it later."
- "I know it looks complicated, but I don't have time to refactor it."
- "The build fails sometimes, but it passes most of the time. Let's just move on."
Cut some corners, rush some code out the door, don't write any tests. It'll catch up to you sooner than you think. Cutting corners creates bugs. Those bugs? They're going to turn up late at night or over the weekend. They'll push out your deadlines. And now you're rushed. So you write more bad (and probably un-tested) code on top of your already bad code. And the vicious cycle repeats itself.
A few easy ways to avoid all this technical debt:
- Work small. Smaller tasks lead to faster iterations and increases your ability to course-correct with more frequency.
- Work clean. Use SOLID principles in your code. Simply learning and implementing "single responsibility" has made a huge difference in the quality of my code.
- Keep Master green. Use a CI server like Jenkins or TDDium to ensure that you're test suite stays clean. Don't EVER let your master branch stay broken. You'll regret it.
Some technical debt is simply unavoidable, but it's up to you to constantly be paying it off. If you don't stay on top of it, it'll overrun you. Stay fast and agile and always be refactoring.