Keep Your Promises — How to deliver software on time
We’ve all experienced a rough development cycle, where we get bogged down by unexpected problems and scope creep. Our CEOs get frustrated when product timelines slip, and our efforts to explain the chaos does little to help. We are all familiar with agile development, but it takes discipline to keep a constant and clear communication flow throughout the development cycle. When you make a promise to your boss, how can you reliably keep that promise in the chaotic world of a startup?
Well, that depends on the promise itself.
Let’s say you make this promise to your boss:
“I promise that I will deliver an application with features A-Z precisely 30 days from now.”
How likely are you to succeed in delivering on that promise? Any number of things can go wrong. You don’t know yet how difficult those 26 features will be to implement. What if someone gets sick? What if something breaks in production and your developers have to push a patch? What if you didn’t think of all the possible use cases and edge cases that could arise? What if, half-way through the release, your boss decides a new critical feature must be added?
Let’s say instead you make this promise:
“I promise that I will deliver a functional application, with a critical set of features A-F, and as many wanted features G-Z as possible, in order of priority, 30 days from now. I also promise to provide a consistent, transparent stream of communication along the way, giving you the freedom to change priority as needed.”
Now you have set yourself up for success. That’s only the beginning, however. Now you must deliver on that promise. With this process, and some discipline on behalf of you and your development team, you will deliver on that promise.
The First Law of Software Development
Before we begin, I want to state what I call The First Law of Software Development:
You can have it good, fast, or cheap, but you can only pick two.
Since startups are typically strapped for cash, software development at a startup is always a tug-of-war between Fast and Good. Since startup CEOs want everything fast, then you end up tearing apart the Good into its components of quality, functionality, and polish. Quality should be the top priority, so only functionality and polish should be negotiable. In a time crunch scenario, you can either release fewer features, or make those features less robust and polished.
The first step towards success is forming an agreement between everyone involved. Your boss, your development team, and you must agree on the process, scope, priorities, deadline, and communication.
Agile methodology — Most software startups these days use Scrum. I strongly recommend that everyone at your company from the developers to the CEO become familiar with Scrum, and then apply the level of rigor that feels right to you. While it certainly adds overhead, it’s worth the cost to have a sustainable and predictable business that churns out quality software on a regular basis.
Scope creep and Deadlines — Scope creep happens. Typically when you scope out a release, you are missing important information, or haven’t thought through every possible scenario for the required features. As you get farther along, you realize that a feature cannot be implemented without other detail or supporting features. Your boss should understand up front that this will likely happen, and it will result in either the deadline moving out, or low priority features being pushed to the next release.
Status reports and meetings — Clear and consistent information is critical to make good decisions. You should agree on when and how status should be communicated. With your development team, you should meet once per day to address any problems. With your boss, you should meet or at least send a report once per week with the current status of the release, calling out any new information such as changes to scope, or expected deadlines.
Milestones and release dates —Agree on when the product is expected to ship, what features will be included, and when certain milestones will be met. Major milestones include scope completion, design completion, some interim functional prototypes, code completion, QA completion, and deployment. At each milestone, hold a review with your boss to make sure you are on the right track with the design and priorities haven’t changed.
Success or failure of a startup depends on you building the right things at the right time. With every feature that you implement, you are making a bet of time and money that it will improve your business in some measurable way. You should have an ongoing list of possible features, scored and ranked by impact to user acquisition, conversion, and retention. These are the key parts of the growth funnel, and every feature should tie to at least one of them in a measurable way.
With every feature that you implement, you are making a bet of time and money that it will improve your business in some measurable way.
Allocation — With each release, you should consistently allocate a proportion of time (or story points) to new features, technical debt / refactoring, and polish. I recommend 50% to new features, 30% to technical debt / refactoring, and 20% polish. Your boss will always push for more features, your developers more technical debt / refactoring, and your designer more polish. By budgeting this time into every release, you avoid having to do a maintenance build, in which no new features are added and the time is spent tearing apart and fixing old code that probably hasn’t been looked at in a long time.
The term technical debt is one of the most important terms in software development. By moving too fast, cutting corners, squeezing QA, or otherwise being disorganized, you create problems in your application that will need to be fixed at some point. It’s called technical debt because you can’t avoid paying the cost, and the longer you wait, the more interest you have to pay. Interest may include an unstable app that costs you users, having to dig through legacy code that is not fresh in the developers mind, or having to black box a legacy component entirely because it is too far gone.
Maintenance builds are very expensive for this reason. By letting technical debt sit for so long, you end up spending a lot of time fixing issues, while at the same time no features are being implemented. Pay off your technical debt like you would a credit card, regularly and consistently, with no exceptions.
It’s called technical debt because you can’t avoid paying the cost, and the longer you wait, the more interest you have to pay.
Define detailed tasks — Each feature needs to be broken down into simple, clearly defined tasks. Start with the Epics, which are the major roadmap features, and break them down as small as possible. Use a tool like Wrike, Trello, or JIRA to capture your tasks.
Prioritize — Meet with your stakeholders and rank each in terms of priority. Identify which are must-have and nice-to-have features. This step is so important because when that scope creep starts to come in, you can have the discussion about how important it is really, and compare it to the other tasks in the scope. Revisiting priorities forces the stakeholders to make a tough decision about what’s really important to the business.
Estimate tasks— The developers should provide an estimate for each task and subtask. As a general rule, any task over a day should be broken down into smaller tasks. Many developers are reluctant to give estimates, especially for uncertain tasks. You must coax them into giving an estimate, assuring them that these are just estimates and can change when new information arises. You should also learn who on the team consistently over and under estimates and adjust accordingly.
Assess Uncertainty — It’s critical to understand the level of uncertainty in estimating tasks. Tasks with more uncertainty should be given a wider time range, and additional buffer. Use a simple 1–10 or 0–100% scale.
Give Time Ranges — It’s difficult to say exactly how long something will take, so go for a best-case / worst-case range. The more uncertainty, the wider the range.
Buffer for uncertainty — The higher the uncertainty, the more buffer you should add onto the task. For a low uncertainty task, I’ll add around 20%. For a high uncertainty task, I’ll add up to 50% extra time.
Create dependencies — Determine which tasks are dependent on each other. Follow the chain to identify the critical path.
Estimate velocity — Everyone has different levels of productivity. While many people say they work 8 or 10 or 12 hours per day, the amount of hands-on productive development time is typically around 5–6 hours per day. In a typical day, you have lunch and bathroom breaks, meetings, waste tasks, switching costs, and research that eat up a considerable amount of time. Some days are better than others, but on average I shoot for 5-6 hands-on productive hours.
Create rough timeline — You should now be able to create a best-case/worst-case timeline. Add up the total number of task hours, divide by the number of developers, and then by 5. This will give you the number of working days it should take to complete the release. If this does not line up with your boss’ expectations, you can decide whether or not to adjust the timeline or push out scope.
On the first day of development, create a goal for the week. Select the highest priority tasks earliest in the dependency chain, and fill up a Current Week folder so that each developer gets assigned 25 hours worth of tasks.
As each developer begins working on a task, they should move it from a To Do to an In Progress folder or board. When the task is finished, it should be moved into a Testing folder / board. When validated, it should be moved to a Done folder / board.
Track Velocity — At the end of each week, count up how many hours or points were completed by each person and keep a running tally. This is your development velocity. It may fluctuate from week to week, but over time it will give you a good working average to use for all short and long term planning.
Track Waste — Waste works its way into every development project. Waste tasks may include getting stuck on a task because they had wrong information, or fighting fires in production, or handling support issues, or getting pulled into excessive meetings. You should do your best to keep track of these waste tasks in a separate folder, with time estimates for each. It’s pretty eye opening when you get to the end of a release cycle and look at exactly how much time was wasted by being disorganized. You should work to eliminate waste by improving your processes, organization, documentation, and communication.
Weekly Review — At the end of each week, you should send a report to the team and your stakeholders that shows what you accomplished in that week, how much time was spent on waste, how velocity compared to the historical average, any new tasks that were added to the scope, and if the timeline is expected to shift. Burndown charts are a great way to show the team’s progress towards completion. Keep these reports in a central shared repository so anyone on your team can review them.
Release regular development builds — Regardless of how long the release cycle is, you should work on 2 week development sprints and release an internal development build at the end of each sprint. This way, members of the team can see how the features are coming together, and play out any possible scenarios that may not have been foreseen. The earlier you get this information, the earlier you can adjust and the cheaper the changes will be. This also allows your QA folks to stay busy on stable builds.
Keep large features on separate branches from small ones — Whenever possible, keep your major epic features on a separate branch. In some cases, epic features can get bloated and cause timelines to drift, holding back important features that are easier to implement. For example, a tweak to the business model may require a simple change to put something behind the paywall. The CEO may push to get that out in order to increase conversion, but it may get stuck behind a much larger feature. Now you have to rush the epic in order to get that small change out the door. By keeping epics on a separate branch, you can push out a small release in between to relieve some pressure.
Validate with users as early and often as possible — You designed a set of features in order to solve problems for your users. As soon as you can, even before development begins, you should attempt to validate that your proposed solution will actually solve that problem. As the dev builds are released, take the time to get feedback from anyone you can outside of your organization. Hold focus groups with new and existing users, show the build to friends and family, even stop a stranger at the coffee shop and ask for his or her opinion. I addressed this topic in more detail in my last article, How To Avoid Design By Committee.
Each week, you should review the team’s progress and assess any necessary course changes.
Reset velocity — If the velocity has been drifting significantly from the historical average, open it up for discussion. Perhaps the tasks were unclear. Perhaps there have been an abnormal amount of waste tasks. Whatever it is, get to the bottom of it and try to bring the velocity back up to par.
Revise estimates — As new information is gathered, it may be necessary to revise your estimates for certain tasks. This is almost a certainty in any release. Expect some tasks to take more or less time than originally anticipated.
Break down tasks and add clarity — As larger tasks become more clear, break them down into sub tasks and add more clarifying detail. Developers should mark tasks that need clarification to be brought up in the next standup meeting.
Descope — If the original estimates were off, a significant amount of waste was introduced, or new scope was added to the release, it may be necessary to push some low priority tasks out to a following release in order to make the deadline. Make this decision as early as possible, notifying any stakeholders.
Split releases — If a release is getting bogged down with complexity or scope creep, you may decide to split it into two releases. That way your boss and your users get something, and it relieves some pressure on the developers. This is one reason why putting epics on a separate branch is helpful.
Iterate —Repetition is the key to success in this process. It’s a lot of work to keep this project on track, but by iterating consistently and often, you collect valuable data that make it easier in the future. You should create templates for all of your reports, boards, task descriptions, test cases, and requirements. You should also schedule time on your calendar to perform each of these tasks so they don’t get buried under the daily chaos.
Testing is arguably the most critical component to software development. Unstable software is useless, regardless of how many features it has. This is another argument against the constant pressure to release new features. The users aren’t asking for that shiny new feature. They just want it to work. It’s better to release fewer features that work, than more features that don’t.
Write test cases — As soon as the scope is complete, the QA team should begin writing test cases to validate each task. You should develop a master test plan that includes all test cases, and with each release you should be adding to it.
Test as tasks are completed — As soon as a task is moved into the Testing folder, your QA team should be able to begin running test cases against it. If you have a test engineer, he or she should start writing automated tests.
Never squeeze QA — It’s so common it’s become a sad cliche. The developers are always late, and the deadlines never change, so QA always gets squeezed. This is a terrible idea and has ruined countless products. Part of the up front agreement should be that the deadline applies to code completion, not release. Regardless of whether or not the code is completed on time, the QA cycle is fixed. If you are in danger of missing a deadline, move out development tasks instead.
Perform full regression test plan after code complete — By the time code is complete, most of the tasks have been validated already. There may be several QA builds as the developers and testers go back and forth. Finally, when the team is confident to build a release candidate, the QA team should run a full regression test. Ideally these tests are all automated, and if a bug is discovered that needs to be fixed, the entire regression test suite should be run again. The regression testing should be the absolute last thing that is done before deploying. Even a trivial change can have catastrophic effects. It has happened to me multiple times.
If you followed this process, you should have a high quality product with most of the requested features, delivered on time. You should have a happy boss who got what he or she wanted, happy developers who didn’t have to work through a crunch period, happy testers who didn’t get squeezed, and happy users who received an awesome new update.
At this point you should hold a retrospective with your team and your stakeholders to discuss what went wrong and what went well. There is always room for improvement, and sometimes you just have a rough cycle. Take the time to reflect on your team dynamic and your process and try to make improvements the next time around. As always, you should celebrate your releases. Do it immediately after release, before you get caught up in the next cycle.
As always, I hope this article was useful to you. Please respond with any useful feedback or war stories. I’m always eager to learn how others do it. You can read more at my blog, The Hacker’s Guide to Growth, or read my publication on Medium. I am writing a series of detailed, practical guides that cover all aspects of startup growth and product development, including strategic planning, design, product management, and software development. Best of luck!
Do you need help streamlining your product development process? Is your business struggling to scale with your growth? I’m now doing full-time strategic consulting and fractional CTO work. Check out Voyagent.io and let’s connect!