Definition of done or how to stop creating legacy code

Guillaume Ducret
4 min readJun 27, 2021

Too many projects end up being unmaintainable after a short period of time from their inception. Code base got complex, development is slow and considerable effort has to be involved in testing to prevent regressions. As a result, feature development cost increases exponentially. When this stage is reached, the project enters its maintenance phase. It is usually time to plan for a V2.

From the business perspective, having a product in maintenance phase is highly undesirable. It slows down the company’s ability to innovate and keep up with the competition.

To prevent such a fate, the development team should have a constant focus on managing the growing complexity of the project. The ultimate goal is to keep feature development cost as a constant. In this article I will discuss some guidelines which helped me getting closer to this objective.

Get DONE before moving on

A project does not get unmaintainable overnight. It does so slowly but surely, one product increment at a time. When calling a feature DONE, whatever amount of effort left (code clean up, refactoring, testing, pre-release tasks, …) builds up as technical debt.

The concept of DONE is crucial. The definition of DONE (DoD)is one of the most important component of SCRUM and is defined as follows:

The Definition of Done is a formal description of the state of the Increment when it meets the quality measures required for the product.

The moment a Product Backlog item meets the Definition of Done, an Increment is born.

The Definition of Done creates transparency by providing everyone a shared understanding of what work was completed as part of the Increment.

scrumguides.org

Assuming an increment is created if and only if it complies with the definition of DONE, the DoD is a direct indicator of the product quality. A strong DoD would result in high quality increments which are readily shippable.

This sounds straightforward. Unfortunately in practice it is rarely achieved and remains a wishful thinking. Nevertheless we’ll try to get there eventually.

The first step for the team is to reach a common agreement on the definition of DONE. Improving the DoD is a slow process that should be done in small increments. This was the easy part. Making sure those rules are applied is the real challenge and there is no magic recipe I know of. A team where each individual has strong ownership of his work and buys in the DoD is already a long way ahead. Having a developer lead with strong commitment to code quality and willing to mentor the team can also make the difference. Doing peer reviews is a good habit as long as it is done seriously. (How many Github PRs are done for the sake of it without any actual review involved ?)

Keep feature code simple

The business value of a software lies in its many features implemented increment after increment. To build a product at a fast-paced, developing a feature should be straightforward. The development team must concentrate on business requirements not technical aspects.

The key is to have a clear distinction between feature and technical code. Feature code should be as simple as possible, pushing complexity in reusable technical components.

Each feature bringing new technical requirements takes a fair amount of time to implement since technical reusable components are built along the way. Writing reusable code properly is hard and does take time. On a short time frame, development speed slows down. But on the long run, many other features will benefit from reusable components. Overall feature development cost remains constant.

Say no to your Boss

We discussed how to keep feature development cost low and constant. Is it possible to go one step further? Actually there is one : The least costly feature is the one you do not implement….

All along a product life cycle, developers have to make technical choices. Each choice supports the product direction, but makes it harder to change course. When a new business requirement is defined, the development team is responsible to assess how it fits in the current implementation.

Too often, product backlog entries are considered as hard requirements. Developers might lose sight of their own responsibility for code base consistency and dive head first into the implementation. This could end up trying to fit a square peg in a round hole. Questioning the real intent of a requirement often opens the door to an alternative implementation more in line with the existing code base. Sometime we might even decide to discard the feature altogether!

Wrap up

Keeping a low complexity on an ever growing project is easier said than done. But I believe those few guidelines can get you a long way if applied from day one. Remember, the fastest way to build software is to take your time. A fluid communication with the product owner and a clear vision where the product is going also help to build and maintain a good architecture.

What if my project is already cluttered with technical debt? I believe that once complexity has built up above a certain threshold, it is almost impossible to reverse the trend. If not for technical reasons, just because business will not allocate time for it. Writing a V2 with strict rules from day 1 might be the only solution. A modular architecture such as microservices would be an asset as it allows for incremental rewrite.

--

--

Guillaume Ducret

Full-stack developer. Helping startups to grow from idea to product.