For more than a year the product team I work with has been developing a new product that we will formally unveil next month. I’ve been routinely impressed with the quality of work the team does, the creative solutions they find to problems, and their ability to balance new feature development with refactoring on pieces of code that were developed before. The strength of our product helps deepen my appreciation for the Agile software development methodology that I’ve been blogging about.
In spite of the many successes we’ve had, there have also been periods where certain problems seemed to crop up continually. Each sprint we would think we had solved the presenting issue, only to see it pop up again later. Or else we would address one aspect of an issue only to find another side of the same basic problem emerge elsewhere. At some times in the past few months it felt like we were dealing with a problem like this one: http://www.youtube.com/watch?v=fdSLP-qz_fw
So what can be done to finally put these persistent problems to rest? Rather than having such issues hanging around to haunt and annoy us, we’ve used the following three strategies to make sure persistent issues get fully fixed.
- Get to the root of a problem, don’t just address the symptoms. The responsibility for this rests squarely on my shoulders as the product owner. I have to work with the developers to make sure that they understand the business rules or user requirements behind a particular feature so that the coding and testing logic is developed appropriately. Some scenarios have very basic solutions (for example, never return a negative number or always ignore the first data point); but in most cases things are not that simple. The business rules that govern how to calculate certain financial metrics for instance can be subtle and nuanced, and so both the coder and the tester need to understand the requirements well enough to develop sophisticated solutions to the complex problems. Often a recurring issue in the software product points to business requirements that were not well articulated or understood in the beginning. Getting deeper clarity on these can help to address the root cause of persistent problems.
- Address technical debt on a regular basis. In the fast-paced and rapid-deployment environment of many Agile shops, quick fixes that address the basic needs for a feature or that allow the quick development of prototypes can introduce unexpected consequences. As different components within a complex software system interact, and as the understanding of central business needs evolves during the development process, programmers must continually revisit their existing code base and look for areas to improve and streamline it. Past choices to ‘do it this way for now and come back later to improve it’ have to be followed up with a reliable plan to in fact revisit the old code and refactor or improve it. (There are lots of places on the web to read more about technical debt but here’s a place to begin if you want to know more: http://c2.com/cgi/wiki?TechnicalDebt). Just as the first step here is the responsibility of the product owner, this second step rests with the programmers to allot consistent time in their development cycles to revisit and refactor existing code to keep technical debt to a minimum.
- Develop a comprehensive test coverage plan. QA developers also have a role to play in minimizing the recurrence of persistent problems. This means base-lining expected results and developing appropriate automated tests to ensure that these results don’t change inadvertently. A solid combination of manual and automated tests that cover all of the important aspects of a software package help to confirm that fixes in one area don’t introduce (or re0introduce) problems in another area. The more thoroughly covered a product is by testing the more likely it is that unexpected errors will be caught before deployment.
These three ideas aren’t rules to follow – in fact following ‘simple rules’ often leads to problems (which should be no surprise because in truth it’s not that simple). Too often rigidly following rules actually promotes surface fixes, introduces technical debt, and encourages shallow test coverage. The flexibility of an Agile approach allows room for developers to dig into why a problem arises, using a principle-based rather than a rules-based approach to understanding and solving problems. This leads to software products designed and supported by people who care about the quality and sustainability of what they create.
The strategies above – applied in a creative and principle-based environment – are helping us catch and resolve issues that might otherwise continue to plague our products. Implementing these steps can be a helpful way to deal with problems that won’t seem to go away. Of course, in truth it’s not that simple.