Tuesday, August 04, 2009

Rigid definition of done considered harmful

Most people that has been doing iterative development in general and scrum in particular are probably familiar with the concept of discussing a definition of done. I have more than once been on projects where the concept of done has been defined in one form or another, and where project members have been trying to deliver running parts of a system that is compliant with such a definition. Even more I have witnessed scrum-masters proudly announcing that their definition of done is really done, done, done. The concept of done, done, done will of course be different from appliance to appliance, but it usually ends containing some of these:

  • Code checked into SCM
  • Code passed QA
  • Tests running green in the Continuous build system
  • Running part of the code in a test system ready to be accessed by functional experts and product-owners
  • Possible discussed and assessed by product-owner before staged to the demonstration environment
  • Possibly accompanied by customer driven tests like fitnesse
  • Ready to be put into production

My claim goes as follows; forcing your team members to adhere to a definition of done that is to rigid, and using that same definition as a criteria before moving it to the done category on the scrum board (complete in the current iteration), will cause your team to deliver less functionality than they could, and with properties that will make that functionality more difficult to change or even remove. I will try pinpoint why following such a rigid definition along with some indicators on going in the wrong direction.
Just to clarify one thing; for me, writing code with accompanying tests that are checked in and runs green in the CI system is all about the same thing. Make no mistake, I do it and I encourage my team-members, and everybody else for that matter, to do the same.

Team-members are reluctant to pushing functionality out

All those parts that need to be completed to get the "done, done, done" badge might not be necessary or even productive work to deliver the functionality ready for test. Maybe the criteria that says that all functional tests should be supported by a FIT test or some test specified in some BDD-flavor just isn't the way to go if the functionality doesn't lend itself to such a definition easily. Maybe only programmers are going write tests and specifications for that part of the system, in which case JUnit will probably be the best choice for a Java-based system. Not easily being able to comply with the done-criteria will probably cause some developers to go that extra mile to comply even if it is probably not worth the effort for that particular piece of functionality.

Consistency is will of course matter here. Using the same techniques for every bit and piece of the system will make it more consistent. But the strive for consistency will also manifest in supporting test-code or a greater number of test artifacts. These bi-products will have to be maintained and refactored together with everything else, and may actually make it more difficult to change the system later on. It takes experience to know when to put emphasis on consistency over throughput.

Somebody is questioning why we need to work further on something that we have moved off the board

Does this question sound familiar: "I thought you said that this task was done, done, done. We really doesn't have time to take this task back in again". I have heard it quite a few times and although it tends to be accepted, it still surprises me that this is not perceived as the rule, not the exception. If you get all the functionality right most of the time, my claim is that your lead-time to production is probably much longer than it should have been. If you develop build and deploy fast, like in hourly or daily increments, the likelihood of getting it right the first time is probably lower, but the basis for distilling the functional requirement is the running system itself, not some temporary artifact used just for aiding the specification process. Do as much of the specification work as possible in the production code. 

The irony of all this is that it is the people evangelizing on how to eliminate waste that are most prone to push forward a framework to assist in the specification-process where that framework is not part of the code running in the production system. The observant reader may have understood that I am being intentionally vague here, and I have chosen not to prove my point with an example.

It tends to propagate into rigid definitions of other areas of development

The work to be put down to comply to a rigid definition of done to sign off on a user story or a task has the tendency to propagate into all areas in development. I think this is partially caused by the fact that you tend to move the some finalization-criteria out of the common-sense and ad-hoc part of decision making and into an (often) static set of rules. We need some statement on what the rules are, if not for anything else, at least to get some transparency related to the development process so that it may be explained to architects, management and other stakeholders and decision makers.
I believe that the urge to push rigid definitions of compliance rules forward is partially caused by the strive for consistency. The expectation is as follows; if you have rules that govern the development process, in the case the definition of done to move something off the scrum-board, then you will end up having delivering functionality in a consistent and predictable manner. That may be, but what if the functionality delivered is delivered slower than it could be and, and much more hardened in the source-code in terms of difficult to refactor tests and Fit tables.

The same goes for code-qa (pair programming is not always how code comes to light). Way too often this boils down to developers commenting on each-other code that may have been developed another way. Some times it identifies and prevents serious design-flaws, which is great. Developers produce at different levels of quality, use this input in the QA-process as well, it is nothing wrong with checking A's code with a great level of scrutiny while you may browse through B's commit-log in a split second. That's life, learn and educate instead, don't force the same compliance requirements on everyone.

What to do and where to go?

"There is no sense being exact about something if you don´t even know what you´re talking about." (John von Neumann).

It is very important that you observe and take notes of undesired effects of certain rules that your team is using to guide their day-to-day operation. This goes for code and architecture-centric rules as well as for rules that are meant to support the day to day process of harvesting requirements. When undesired effects show up, maybe it is time to remove or adjust the rule accordingly. Maybe this particular web-module wont need the Selenium-harness?, or maybe it does.

All in all it is about delivering functionality in the running system, supported by tests so that you may change code when new knowledge and requirement tells you to. A rumor says that Thomas Edison did not hire employees if the person on the interview salted his/her soup without tasting it. Use your ruleset the same way, don't always strive for consistency when applying your rules, it may lead to code manifesting in a way that makes it harder to implement your functionality fast and with less effort.