Thursday, July 22, 2010

Train Model of Software Development

Traditionally software development has been considered a process in managing a classic 3 way trade-off, which looks something like this:


The basic idea is that there is always a tension pulling in opposite directions in each of these dimensions. If you add more features you need to lower the quality or deliver later. If you compress the schedule you will need to reduce the quality or the number of features.

However, the relationship is not that simple. Because software development is an exercise in constant refinement of unknowns, the three way trade-off ignores the fact that these decisions are made in the face of imprecise information. As a result there is a tendency to underestimate the effects of one of choosing these trade-offs. In particular trading off quality almost always leads to schedule slip, due to the accumulation of technical debt.

Agile development in part works because there is a recognition that this three way trade-off model is fundamentally flawed. In a classic Agile project (e.g. SCRUM) you have a fixed schedule (the iteration), a fixed level of quality (passes the acceptance tests), and it is only the features that change.

In a pure Scrum project, you would end every sprint with a release candidate. However, in practice the length of iterations does not accurately reflect the ebb and flow of a traditional software lifecycle, and as a result there has been a move towards a higher level release cycle which layers on top of this.

The analogy used is to think of software releases like a train. A train leaves the station at regular intervals following a timetable published in advance. If someone/something misses the train then another one will come along soon. Releases are planned at regular intervals (e.g. quarterly, every six months), and features are sized accordingly to fit that schedule. If a feature looks like it won't make it, it will be dropped and appear in the next release.

This model is used very successfully in a number of products (e.g. Eclipse, Ubuntu), and is well suited to software products. The customers and the Product Manager (PM) know that there is going to be a certain release at a certain time and can plan around it. If the PM has a high priority feature/bug fix, they can tell the customer with some degree of certainty when that will appear. Marketing knows in advance when a product will be released (although they don't necessarily know in advance exactly what will be in it). Developers have a clear goal on what to deliver, and performance can be easily measured on a regular basis.

Each release has a lifecycle that gets it out on the release train. While obviously those processes can vary, there are some basic phases which I have given below:

  • Envisioning: This is the initial planning and R&D phase that begins each major release cycle. Features are planned for the release and broken down into user stories; UI mockups are developed and reviewed; any design or prototyping that needs to be done is covered.
  • Feature development: This is the standard sprint/iteration where features are developed and delivered. Care must be taken to ensure that this development is sustainable meaning that the testing effort can keep up with the development pace. Features should not be considered finished until they pass all their User Acceptance Tests which should be written at the time the story/feature is defined (and ideally automated).
  • Hardening: This is the end of phase when much more rigorous testing is performed, release engineering and packaging is performed and bug fixes are made to ready for release. If the feature development phase is done properly the bug fixing is going to be minimal, however there will always be some as testing becomes less confirming and more adverserial.

For example, suppose we want to develop a train schedule that allows for about 2 major releases a year, and allows for a minor release in the off quarters if required. This would require splitting the team into maintenance and research for about one quarter, before merging the development together. The train would look something like this:


At the end of every major release the team splits into two, with most people working on maintenance (bug fixes that didn't make the previous train, minor refactoring, automating tests etc), while a smaller group move into the envisioning phase for the next major release. In the second sprint, the minor release team moves onto minor features before hardening for a dot release in the third sprint. A fairly modest amount of work can be done in this amount of time so the focus is on improving quality and getting features that missed the last train. Meanwhile envisioning will take about 4-8 weeks after which time work on major features can begin. Depending on the resource needs there can be some drift between teams in this phase. If the needs of the minor release are modest more work can be done on starting the major features. If the minor release needs more polish/testing then resources can move on to this. At the end of the quarter the minor release should go out. Alternatively it may be decided that there is no pressing urgency to do a minor release and these fixes can simply go out in the next major release.

Now the major feature development begins in earnest. It is critically important at this stage that major features are correctly prioritized and that development is proceeding at a sustainable pace. The goal is to deliver only finished features, so that means not starting on features until others are finished in order to reduce the risk that in the hardening phase there will be an unsustainably large number of bugs.

There is a fair degree of flexibility in this release process. For example, a minor release can be all maintenance with no additional features, or not released at all. Envisioning may take only a short amount of time leaving more time for feature development, or it may take a full quarter meaning only a minor amount can be done. I have used a quarter as a unit of release, but six months, or an off number (say 7 or 9 months) may be more appropriate.

The only thing that needs to stay consistent are the release points. The reason for this is that if the tidal flow of the project stays consistent, then there will be much better predictability, a lot more happiness and much better results for customers and PM.

The train model has been well proven. I would argue it is a sign of maturity in most teams that they move to something like this more predictable process than the chaos that attends most software development. PM needs to be prepared to give up the fact that major releases will not have everything they want, but the train model allows them to get the things that are important out to customers sooner. I would argue that this delivers considerably more value to customers than shipping them features late that they may or may not need.

It also allows a much more agile response to the inevitable customer feedback you get as a result of releasing your product. If you can only do a major release once every 18 or 24 months then customers will die of boredom waiting for new features. If you can do it twice a year, with minor releases between for those things that are important but can't be delivered on time, your customers will love you.