This is the fourth post in a series that formed the basis of my 2017 DevCon session on Increasing Code Quality While Staying Lean. Check out the first post for an introduction to the series. These techniques have made a big impact at SeedCode and we hope you’re inspired to incorporate some of these into your own work.
We Record our Debt
In Documenting our Decisions, we talked about “creating a path from the customer’s cases (or feature specs) to the code that addresses them—a path that our future selves can follow.”
Similarly, when we take shortcuts, we record the path not taken as a new case. Technical debt taken on intentionally can help us get there faster, just like debt financing can help a company grow faster. Debt taken on invisibly is like a variable rate loan—not good—and in both cases it’s the unknown that makes all the difference.
What We Do
- We know there is a better way to do something but we’ll defer hardening until our work is validated by the customer. Instead of premature optimization we create a case for the optimized approach and ship what we’ve got.
- We can’t finish a feature, or can’t get to the edge cases, so we create a case for what’s undone. Sometimes the isn’t debt, but just “Friday”—I find myself making cases at the end of the week or end of the day for what I wanted to get done but couldn’t. Come Monday, it takes less time to get back to work because I know just where to pick up. This is a version of Hemingway’s dictum to always stop when you know exactly what you’re going to do next.
- When we’re doing QA videos we create cases for any bugs we see that aren’t going to be fixed IN the video. By creating a case for anything weird we see, we can deflect the hard work of deciding when to fix it, or who’s going to fix it, or even to fix it at all. Without having to worry about that we can pay attention the nuances of the bug, and tag the case with any customers who’ve been affected.
Why This Works
Recording instead of coding lets us observe our work without the pressure to fix it. I’m just capturing the bug, not also trying to determine how big a change it’s going to be. This means we see more–and see more consequences–than if we were just looking for how to fix something.
[bctt tweet=”Recording instead of coding lets us observe our work without the pressure to fix it.” username=”seedcode”]
This also works hand-in-hand with delivering small chunks. Think of a feature as hub with several spokes. The hub might be creating a new contact. The spokes might be checking to see if the contact already exists and then merging the new contact with that existing record. Would an existing contact count if they were archived? What constitutes a “duplicate” contact, is it an exact name match or a close name match at the same domain? And who is allowed to create new contact anyway? Who is allowed to merge?
It’s much easier for me to create cases for these “spokes” (to treat them as debt) than to account for them in my code. If my code is the only place to capture these spokes then I’ll capure very few of them. Further, the deferring part of technical debt means I embargo the spoke cases until the hub has been validated by our customer: and that’s key. Because if we get something wrong about the hub, I’d rather just rework the hub than rework the hub and all it’s spokes.
Defering the spokes until the hub is validated is proving to be key. It mean we’re less resistant to chages suggested by the customer and, importantly, less resistant when the customer wants to pivot to a new problem: we’ve already got the landscape of this problem documented.