A software development project should end when all required features have been completed. The software is then said to be “feature complete”.

Unfortunately, before they are feature complete, many software applications are thrown in the trash after succumbing to the dreaded Project Death.

Project death? What’s that? Is it (a) dastardly plans for mass murder; (b) the most metal project ever; or (c) a process by which software applications become unsustainable?

That’s right. It’s (b).

I mean (c). 1

1. Don’t go. It will be interesting, I promise.

Charting Project Lifespans

To see how project death arises and how to avoid it, we’re going to look at the life of a software project using a type of chart that I call a Complexity-Time chart.

Finn the Human (from Adventure Time)

The X-axis (the horizontal one) will measure development time.

The Y-axis (the vertical one) will measure cumulative code complexity. Although hard to define in a measurable way, for a simple visualization of code complexity, think number of lines of code.

Complexity versus time

Developing features

Let’s imagine a project starts with the addition of a single feature A. There are perhaps as many ways to implement a feature as there are developers in the world 2..

2. for non-trivial features that is

Let’s plot some of the possibilities on our chart.

Possible implementations of feature A

If we were the developer tasked with adding feature A, which implementation should we choose?

The implementation we decide on will affect the application’s complexity. Our decision will also determine the time (and cost) to develop the feature.3

3. The seemingly obvious choice for cost minimization is the one that minimizes development time for that feature (i.e. which is A4 in the above chart). However, as we’ll see, this obvious choice may not be the best approach in the long term.

Complexity and the Life of a Project

As time passes an application’s complexity tends to increase. The more complicated software becomes, the more mental effort is required to implement any given feature.

Human brains are limited in the amount of complexity they can handle 4. This means that features take longer to implement as the application’s complexity grows.

4. just my brain?

Features take longer as application complexity increases

The Complexity Horizon

We can imagine, eventually, an application’s complexity becoming so enormous, that human minds can no longer handle it. At this point, new features cannot be completed, meaning that development times are effectively infinite.

Let’s call this the “Complexity Horizon”.

Development is limited by the Complexity Horizon

Theoretically, this is the ultimate limit on development. No project can progress beyond the Complexity Horizon, and, once the Complexity Horizon is reached, features take infinitely long to complete. The software is just too difficult to work with.

Practically, however, project death occurs long before the theoretical limit of the complexity horizon.

Comparing Development Approaches

To see why project death occurs before the Complexity Horizon, let’s compare two possible project lifespans for two polar opposite development approaches:

  • Hasty Development: In this approach, features are completed as quickly as possible, by choosing the solution that is quickest and easiest to implement. The complexity increases quickly, and, as complexity increases, so too does the mental effort required to move the application forward. The result is that the pace of development slows over time.
  • Complexity Minimizing Development: In this approach, features are completed with an emphasis on minimizing complexity, choosing the simplest (but not necessarily the quickest) solution to implement. Features are initially completed at a slower pace than the “Hasty” approach, but, due to the emphasis on complexity minimization, application complexity increases more slowly, and the mental effort to complete new features remains more constant over time. The result is that the pace of development remains more constant than in the “Hasty” approach.
"Hasty" development (A1-B1-C1) takes longer than "Complexity Minimizing" development (A2-B2-C2), in the long run

At some point, the progress of “Hasty” development, with its more rapidly growing complexity, will fall behind the more consistent progress of “Complexity Minimizing” development.

Steady pace wins the race

Cheaper to Rebuild - Project Death

Eventually, the application complexity associated with the “Hasty” approach becomes so great that the development time (and cost) to add new features exceeds the development time to completely rebuild the project using the “Complexity Minimizing” approach. 5

5. The availability of newer technologies can also present cheap rebuild opportunities.

Development time (T1) for later features using the "Hasty" approach is greater than the entire rebuild time using the "Complexity Minimizing" approach (T2)

This is when the project dies. Further development on the project built with the “Hasty” approach is simply not cost effective. It becomes cheaper to rebuild the whole application.

Keeping Project Death At Bay

At bluespot, we take the complexity minimizing approach in everything we do. Not only is it quicker over the long term, but it also minimizes the risk of project death.

I said earlier that application complexity tends to increase over the life of a project, but, this is not inevitable. Bluespot’s git contributions to mature projects are clear proof that complexity growth can be halted and even reversed. We regularly contribute features to mature projects without significantly increasing the number of lines of code.

Ben added 29,426 lines of code to this project but deleted a comparable 29,351 lines of code

And, sometimes, we even add features while (or by?) deleting code.

Iain added 64,021 lines of code to this project but deleted 208,800 lines of code

Minimizing complexity is important and takes deliberate effort by conscientious developers. Software principles and design patterns are all about finding the “right” abstractions and architectures for the current problem. The “right” abstractions are the ones that minimize complexity in the long run, and minimizing complexity cuts development time and cost and staves off project death.