As software craftspeople, we constantly reach for sublime elegance in our work. Just beyond every module rewrite or subsystem refactoring is the paradise of ultimate modularity, configurability, and simplicity — somewhere we never quite arrive.
However, we shouldn’t fall prey to actually believing that given the necessary time to implement every abstraction, refactoring, and re-organization is doing the world any favors. Useful software needs to be used. To be used, software needs to be in the hands of users. To get into their hands, it needs to be shipped.
Most vectors for improvement are only visible once a piece of software is being used by people who didn’t create it. This is the most important point to reach in a software product’s lifecycle, as quickly as possible.
ntil this point is reached — while version 1.0 is still unreleased — two lists must be ruthlessly prioritized:
- The features to be included in 1.0.
- The technical refinements to be included in 1.0.
Some Refinements Provide More Value
Agile and lean project and product management practices largely address how to prioritize features. That task is usually, but not always, out of the hands of software makers. However, which refinements are included is often left up to the dev team.
By refinements I mean refactorings, subsystem redesigns or rewrites, addition of deploy/startup/runtime configurability via metadata, or addressing other forms of technical debt. These are the tasks that make the software more simple, modular, simple, and flexible.
To build the best release, a dev team should not strive to implement every refinement and pay back every penny of technical debt from the project. Rather, it’s our responsibility to prioritize these items so we can tackle the most important ones, ensuring the resulting release provides the most value for our client and thier users within the time we have.
Prioritize Refinements Wisely
Here are a few questions to ask yourself as you evaluate the priority of implementing a particular abstraction, refactoring, or developer tool:
- Does it fully automate a task requiring the time of your client or the end user?
- Does it empower the client to do something I would otherwise have to spend time doing on their behalf?
- Does it empower the user of the software to do something I or the client would have to do on their behalf?
- Does it insulate most of the system from a component very likely to change or be unreliable?
- Does it make the code easier to understand and reason about?
- Does it make the code prettier?
Ask yourself each of these questions for every task not directly related to a feature or bug. When you say yes, give it a priority corresponding to the number for the question. Each week, set aside part of your team’s time (I usually allocate part or all of each Friday) to tackle the items with the highest priority – 1 being the highest.
Successful software is usually never done. Once the software is being used, you’ll learn a lot. And you’ll hear yourself saying, “Man, I wish we would’ve done XYZ,” about a task that didn’t even appear on the dev team’s list representing the yellow brick road to ultimate software excellence.
Perfect software, from the perspective of a craftsperson, is also never done. There is always an improvement, a refactoring, another abstraction, or a “Friday task” that could make the system more elegant, simple, or flexible. As professionals, we need to admit to ourselves that our time is limited, and use that knowledge to our advantage by effectively managing our time. The software we create will provide more value as a whole to the world if we do.