We love to plan when we build software. We create requirements and mock-ups. We create requirement documents, use cases and user stories. We create backlogs of all the things and we might even break them into fine-grained tasks with estimates.
We need to stay organized right?
We need to track progress and ensure that we know what to work on next. If it’s not in the backlog, it’s not important.
Of course we need to stay organized. And accountable. And we need to show progress.
But maybe our list of tasks or features misses out on one of the most important aspects of awesome software.
In my experience, the best work has been a healthy mix of working on focused tasks and some time spent just improving pieces of the system as I come across them or have new ideas. Improving past work. Sometimes the most important work in a project is the work that we don’t talk about.
What does it mean to “finish” a feature? With an overemphasis on tasks and tracking time against them, are we unintentionally creating a barrier to evolving our code bases? We may not feel like we have the freedom or time to work on anything not immediately related to a task. And we may feel like we shouldn’t go back and work on improving a feature that was “finished” a couple weeks ago.
One of the phrases that stuck with me from one of my earlier jobs was a colleague saying “done is not done” during a stand-up when another colleague said he was done working on a task. He was trying to emphasize that although the feature worked as intended, there was lots of room for improvement. Was it properly tested? Was the code clean? Was it consistent with the rest of the system?
We’re often not accounting for the over-arching continuous improvement task. Should a percentage of our time be allotted for general improvements?
“Always leave the campground cleaner than you found it.” – The Boy Scout Rule
We come across a lot of related or unrelated pieces of a system as we’re working on creating or modifying features. We might be inspired and discover a better way to do something that we had considered done last week.
We almost never do things 100% awesome the first time. Great software evolves. But when is it appropriate to improve it?
Should we create tasks for every little improvement that we can make and then include them in the backlog for prioritization? We’re just trying to stay accountable, but let’s be honest, tasks like improving readability, refactoring, simplifying, and reducing duplication will likely be at the bottom of the list in a typical team even though they may be relatively small tasks individually. We’ll wait until our technical debt becomes a bit more intimidating.
The expectation of crunching through tickets can create a “not my problem” or a “we don’t have time” attitude within teams and the quality of the system suffers. Software that isn’t continuously refactored and simplified just keeps getting more complex.
So tackling issues sooner often has a payoff. We’re evolving our solution, keeping our code base clean, and culling technical debt early. We’re making future work easier.
Now if we maintain a responsibility to the appearance of only working on tasks from our task list and we also decide to take responsibility for continuous improvement, we’re going to be borrowing time from our other tasks. And so most of our tasks are lies. They’re slightly inflated by the good work we did elsewhere.
That’s great if we can beat our estimates for the things we promised to work on – we might be able to give ourselves a bit of room to keep the system from getting out of control.
But what if we don’t have room in the estimate? What if we’re dealing with a list of tasks with estimates that we just can’t beat and someone’s breathing down your neck. Maybe they were created by someone else. We might be working with new tools or a new team and we’re just barely getting by thrashing through tickets. We might feel pressured to stay late to make improvements and not tell anyone. But our dedication to quality is just helping to propagate the lie that it is possible to do things perfectly the first time.
But we’re scrambling and falling behind. And the quality of the system is spiraling out of control. But at least we’re getting the features completed.
Where does that leave us after a few months? A few years?
Everyone is still expecting quality work from us. We’re just pretending to get it right the first time. Hoping no one notices. Or maybe we naively believe that we will magically be granted time for improvement later. We finished all the features, now we can relax and refactor. Has that ever happened?
Is it possible to be more up-front about quality expectations? How can we emphasize code quality throughout a project? Maybe we need to formalize it.
Maybe we need something like the Google 20% time for code bases. 80% of our time is tracked against features on our backlog. Those absolutely need to get done. They’re the core of what we’re building. But we also have the freedom to spend up to 20% of our time just improving past work and evolving the solution forward. Or 10%. Whatever works.
Maybe “Improving the code base” could even be a formal task allocated each sprint per developer. We’re communicating that this is a priority and we have a bucket to draw hours from so we’re not inflating time tracked against our other tasks. The team has a clear understanding that quality is always an expectation.
I’m not sure, but I think that there is a need to be more transparent and up-front with expectations of quality and account for it more often in software projects. I think that the freedom to improve things also gives a sense of ownership and more opportunity to take pride in our work.
We should be spending (and encouraging each other to spend) a portion of our time just making things more awesome. Continuously.
Godspeed, fellow developers. Godspeed.