Most software development teams break work down into four distinct phases: Analyze → Develop → Test → Release. As projects grow in scale, traditional development teams grow each of these phases without changing the sequence or frequency. Each phase happens once and only after the previous one is completed. This model has worked for generations for building physical goods and people just assumed it would work for software as well. It didn’t.
Then came Agile and teams changed that to N x (analyze → develop → test) → Release. Release in most cases still happens after a number of iterations have gone by. This means that important path-to-production work ends up being delayed until a deadline is near. Given that going live is one of the few sure things in most projects, not getting started as soon as possible is just postponing the inevitable.
The case for early valuable working code in production
When modern development teams gather to start working on a project, they always seem to start with the same script: “Set up a build pipeline. Set up an integration environment. Put a testing framework in place”. Teams do this because they've learned this is what one has to do, so they start doing it right away, no questions asked. What’s missing in all this is actually delivering the value.
The issue is that no two projects are alike. By doing all this ahead of time, you lock things down only because that’s the way it is always done. Yet, these things may not contribute to have valuable working code in production.
People may question what is the value of having simple functionality and untested code live in production. What is often not recognized is the lack of value of a large application held in a staging environment waiting for a release train. No matter how little value the former generates for the actual users, the later does not generate any until it sees production. Having a small increment at least allows you to receive valid feedback earlier.
By going to production first, you'll learn what it takes to do it. Layers of complexity will be added incrementally to the process, instead of all at one time. You will know earlier if that integration which was 'supposed' to work will really work when you need it to. It will allow you to reconsider poor architectural decisions before you commit to them.
Being able to perform 1-click deploys is great, but being able to perform a deploy at all should come first. If you will not have a full time quality engineer manually testing code, you may not need a testing environment. You may not need a staging environment if you use feature toggles.
By building a complex pipeline from the start, you put effort in activities that haven’t been proven valuable in your context. You may believe that it will save work, but it may also lead you to spend time trying to do something you didn't need to.
A playbook for a production first approach
Starting a project this way requires a shift from what one is used to and requires some changes in the way work is set up. The advantage is that there’s much less need for upfront analysis, and the team may be able to deliver code in production on the first few days of a greenfield project.
So what does “going to production” means? Does one need Continuous Integration to do Continuous Delivery? Here is a quick guide to get started:
Start by identifying the absolutely minimal feature that could be valuable to a real user of the system. How minimal? Think a page telling “something is in the works - come back [a given date] for more, check out this video about us in the meantime” or maybe a form to sign up to receive further information in future. This is more useful than a blank page, but not by much. It is exactly what you want.
Then build a ‘walking skeleton’ for that very simple feature. This is the absolute minimum required to have a working system. The faster this is up and running, the faster value can be realised. Make as many compromises as possible to make it minimal. Maybe you don’t need testing. Maybe a big chunk of it can be hard coded. Maybe it will not load as fast as it could.
Finally, create a production environment for this walking skeleton. It may be that the first time you push to production, it happens via a script from a developer’s box. Be frugal in your automation. Production-first development doesn’t preclude automation. It just makes work small enough that automation itself is not a distinct piece of work.
Note there are a few things you don’t do. You don’t build an integration environment, for instance. You only do it when you absolutely need to. If you only have one stream of work, you may never do it, if you have many streams of work, you do it when the second one needs to merge code with production. You only put effort into doing something when there is a compelling reason to do so.
If you think releasing something as crude as this will hurt your brand, don’t worry. This page doesn’t have to be indexed by google, or you could put it behind a password or a firewall. This way you can control the people that see it, but still have it live. Then you can test it with the users you want, with the peace of mind that you know what you should do to change things in production.
Start sooner to deliver faster
Perhaps the biggest impact this approach can bring is render “Big Up Front Analysis” a thing of the past. Once goals are shared, the team can look for the simplest thing that would help validate an assumption and put it together in the quickest way possible. This means developers would wait very little for analysis, if at all.
This, in turn, means that the analysis effort will grow as complexity grows, helping teams avoid overthinking a feature. Once code is in production, the next thing to do becomes obvious. The business proposition and feedback based on the actual site will determine the next piece of work that needs to be done. In our experience, this means less waste and a more motivated team.
Why not give it a try for your next product or feature and tell us how it worked out in the comments?
Many thanks to Toby Clemson and J.K. Werner for the ideas and concepts behind this post.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.