When introducing scrum or an agile software development approach to a team or within a company, it may happen, that team members only grasp the buzzwords, but not the fundamental ideas behind them. This leads to misconceptions and contradictory situations. That’s what happened at my current project, when I asked a team member to refactor his source code to increase its readability after a source code review. He responded with the words of our scrum master, which the scrum master always repeats like a mantra: Done is better than perfect and you aren’t gone need it (YAGNI). Justified by these words he refused to do the refactoring. The source code he has written, would satisfy the requirements of the user story(Done) and does not have to be changed by any other developer in the future (you aren’t gonna need it).
But how valid is this argument? In the rest of this article this question is discussed using different prespectives trying to solve the contradictory goals based on this statement – refactoring on the one hand and YAGNI on the other.
Project management perspective
From a project management perspective a radical usage of YAGNI and Done is better than perfect like in the statement from above compared to refactoring leads to advantages in a short-run. The developer saves the time and effort to touch the already working source code. Thus, the developer can proceed with other tasks at hand enhancing the velocity of the project. Also the risk of breaking already working code while refactoring can be avoided this way.
However, this approach leads to problems in the long-run, if the source code needs to be read or modified by other developers. First indications for problems may already show up at code reviews, if the reviewer has problems understanding the implemented functionality. Also future enhancements can be difficult, if the structure of the source code is chosen inappropriate and could have been improved by a refactoring it beforehand.
Software development perspective
From a software development perspective the statement from above must be considered utterly critical. Wrong structured or unintelligible source code makes extension and maintenance of existing software seriously harder. Beside the fulfillments of the given requirements, software needs to be maintainable und readable. Due to this fact, refactoring is an approved method to achieve this goal. Software development clearly states the necessity of refactoring. Merely the question when to refactore needs to be considered. After all refactoring can also take place when the source code is actually reworked in the future. This would be in the sense of Done is better than perfect and YAGNI as in the statement above. However, applying this approach leads to another problem. The knowledge regarding the behavior and purpose of the source code could already be lost at a future point in time. The cause could be that the person looking at the source code is not the same as the original author. Even the original author could forget the purpose and behavior of the source code after a long time. This leads to problems when either adding future enhancements or performing maintenance. For enhancements it may not be clear where to apply changes or which parts of the application influence each other. As a consequence integrating enhancements becomes significant harder. For maintenance to be fast the source code needs to clearly readable. Otherwise a lot of maintenance time is wasted trying to figure out, what the behavior of the source code is. It is therefore advisable to carry out the refactoring when the knowledge of the behavior and intent of the source code are still present. Moreover, it is not the goal of such refactoring to be completly able to protect the source code from any subsequent adjustments. Despite post-processing, the source code may need to be refactored when applying later extensions to facilitate implementation or to integrate changed requirements. However, this later refactoring is much easier and faster, because the source code already exists in an understandable and well-structured form and does not need to be transformed into a well-structured form beforehand.
Test-driven development perspective
When developing in a test-driven fashion, then the case is clear. Test Driven Development is based on the TDD cycle or red-green cycle, which consists of three phases: In the first phase a test for the functionality to implement is written. The test fails when run causing a red broken test indication. In the second phase source code is added fixing the failing test. The test now succeeds causing the test indication to turn green. Refactoring is the third and final phase before a whole cycle is complete. Thus the test-driven development cycle is not complete without a final refactoring. The answer to the question for the time of refactoring is clearly given as well: Refactoring takes place immediately and as a consequence directly rebuffs postponement of Done is better than perfect and YAGNI like stated above.
Agile software development perspective
The goal of agile software development is to deliver working software continuously and early. For this goal to be achieved, the software quality needs to be high and the software itself has to be kept flexible to be able to quickly react to changes. This procedure also promotes incremental development. As already described in the software development perspective, subsequent refactoring involves time loss and problems in understanding compared to refactoring at creation time. Until the subsequent refactoring has been carried out, the quality and flexibility of a software has dropped. Accordingly regular refactoring and a clean source code belong to high quality software. Under this premise a postponement of refactorings also is no option for this perspective.
Looking at YAGNI and Done is better than perfect in their birthplace, agile software development itself, their notion mainly relates to the implementation of features. They should remind the developer to not make unnecessary development effort for future features at the present time. These features can be implemented, if necessary or when they are eventually scheduled for implementation. The time freed up by this approach should then be used for the improvement of the software quality, which includes refactoring as well. The later integration of new features can only take place in a well-crafted source code, so YAGNI also encourages software to be flexible. Consequently, YAGNI and refactoring do not contradict, but even literally depend on each other.
Here is a short summary of all reasons from above:
|no refactoring||immediate refactoring|
|functionality can not be broken||higher software quality|
|time savings in the short run||readable source code|
|extending the software in the future is easier|
|knowledge of the purpose of the source code still available|
|TDD principles satisfied|
In summary, refactorings at creation time are necessary in any case. Assuming that YAGNI and refactoring contradict each other is a clear misunderstanding of certain software developers.
Finally, a recommandation: It is often argued against refactoring that there are no clear goals. Taken to the extremes, a piece of software can be refactored and optimized for any length of time. It is therefore necessary to define clear goals for the software quality and refactoring. So a “Done” is also achieved for refactoring. Thus, it is my advice to utilize the definition of done in scrum to define quality criteria using source code analysis tools such as sonarqube and checkstyle. Then refactoring takes place until the source code meets the requirements of the definition of done based on the Source code analysis tools in use.