There’s a popular joke that 90% of software projects are 90% done, 90% of the time – and unfortunately it does have some truth behind it. But does it have to be this way? How can we, as leaders, ensure that our teams avoid this trap and deliver completed features in a predictable way? Here’s a few tips from my own experience.
We’ve all been there: your team is working on an important project (all projects are important, right?), and when the release is just around the corner you suddenly find out that there’s still a lot of work to connect all the dots: system integration does not work, performance is unacceptable for larger data volumes, edge cases in business logic are not properly handled, and so on. Your team ends up coding some last-minute patches, working late evenings or weekends in much haste, making mistakes. Once you release the software, the users experience some serious bugs and you have to spend several days or weeks before the customer can actually benefit from the application.
The client is unhappy, your employees are burned out, and your reputation suffers – not a result that anyone would want. So how can we prevent this ‘Almost Done’ syndrome, how can we ensure that we don’t get last-minute surprises calling for hasty patching again? There are multiple aspects that you need to take care of to succeed.
It’s natural for all of us to prefer simpler tasks over more complex ones, and developers are no exception. They will tend to put off the latter and overly focus on the former. It doesn’t mean they will avoid doing difficult work, just that they will choose to complete the parts they perceive as simpler and more clear first.
For example, when someone feels comfortable implementing complex algorithms and does that frequently, they will tend to focus on that part of a new feature, and may be putting off other important aspects – like detailed analysis of the business process, or a discussion about some integration details with another system’s developer.
What can happen without proper self-control is that developers will keep polishing one area or switch to other tasks, in order to avoid working on that least comfortable 10% of the feature. It’s natural, we all have such temptations, and the first step to fight this problem is admission. Once you and your people realize it, it’s a good ground to build your process improvements on.
Limit Work in Progress
There’s a simple yet beautiful concept in Kanban called WIP (Work in Progress) limits. It’s usually understood as the maximum number of tasks in progress for the team. When it’s reached and a new important task enters the queue, the team usually needs to focus on completing at least one of the previous tasks before they can begin it. Such approach does allow for some exceptions, but it greatly helps in making sure the team members don’t jump between tasks without control, leaving many loose ends.
You don’t actually need to follow Kanban or any other Agile practices to introduce this type of rule. You can also adjust it: sometimes you might be better off with a per-project limit (e.g. when your team is developing multiple applications) or any other variant that fits your environment best. The crucial thing is that you coach your developers to finish one task before starting another (at least in normal situations).
Definition of Done
The approach of WIP limits (or similar) will help your team avoid unnecessary multi-tasking, but a common understanding of what it means that a task is completed is also needed. Such definition should include all steps required to be performed before a feature is released as part of the new product increment (e.g. into UAT environment).
A sample Definition of Done would include steps like:
- Code changes are checked into the repository,
- The CI build is successful,
- The feature is tested in DEV and all bugs are fixed,
- Integration with other components is verified,
- A peer review is performed,
- and so on.
It’s usually best to write these steps down and make them visible to all team members, all the time.
Another aspect to work on is defining clear acceptance criteria for new features of your system. They should include both functional and non-functional requirements, so remember to clarify the expected load, frequency of the feature’s use, platforms that need to be supported etc. in discussions with your customer. Don’t forget about technical quality factors, such as maintainability, extensibility, or scalability.
You can consider including such acceptance criteria in your team’s Definition of Done too. While many of them can be difficult to describe precisely, your developers need to remember that the software won’t really be ready for a release until those requirements are met, so they need to design, code and test with all of them in mind, and not keep putting that work off till the last week of the project.
Clear Action Ownership
Many cases of loose ends occur due to miscommunication when making agreements on some side tasks (not directly related to coding), e.g. arranging some infrastructure change or confirming some edge case of business logic with the customer. I have personally run into this many times – everybody was thinking that someone else will do it, and in the end we had to rush it or just accept the risk.
To avoid such cases, make sure every action – even the smallest one – has a clear next step and an owner assigned. Coach your team members to finalize every discussion with a short summary of who-does-what, so that it doesn’t require your personal control.
Probably the best way to ensure your product will be ready for a release on the big day is to keep it always ready for a release. That can be achieved by employing a process of Continuous Delivery, where you can actually push the software to target environment at any time you want, with minor cost (‘one click’, ideally), and verify its completeness then.
However, as this technique is not very common yet and may take a long time to implement, in the short term you can at least ensure the ability to release a product increment that is created at the end of every iteration (sprint, milestone or whatever that is in your methodology). You may not be able to verify releasing it into the Production environment, but even running it on staging or UAT machines should help polish the system. It should allow you to spot and eliminate most, if not all, of possible issues with configuration, infrastructure and integration with other components.
So keep your product releasable during its whole lifecycle. Leaving that for the last week or month can often cause serious problems.
Realistic Test Data
One big source of surprises in the final phase of a project is the lack of proper test data during all stages of development. In many cases your team won’t be able to use real data and you will need to rely on fake, auto-generated sets. In such case, make sure the sets are large enough and allow to verify the system’s state not only at day one (when the database could be almost empty), but also after 3 or 5 years of its continuous use. Also, ensure that the data contains a wide range of values and includes edge cases.
The problems coming from data itself could go from simple too-long-to-display types of defects, to large performance/scalability issues that require a part of the system to be redesigned. It’s much easier to design and code for the expected volume and some data anomalies from the start, so ensure that this information is provided to your team and make the development environment reflect that.
The above advices won’t guarantee you a successful finish, but they should lower the risk vastly and allow your team to focus on other things in the last few weeks before the release. Of course there are many other aspects to take care of, like the estimation process or integration with other systems, but I hope this article motivates you to think through the topic and select items to focus on in your team’s context.