There is a little something that most people who are in the business of creating software understand, but outsiders seldom know. It is this — in software development you cannot get things right the first time.
And I am not just talking about full products, but even tiny details. It is very rare in software to get things right the first time. In fact it takes multiple attempts before you can get anything to work as it should. Don’t believe me? Go out and ask people. Ask a product manager how sure he is that the feature he is designing would deliver value to the user. Ask a designer how sure she is that the UI she is designing would be as intuitive for the user as she is expecting. Ask a programmer how certain he is that his code would work as expected. Ask how many times have things worked the first-time as they expected vs. the number of times they have had to go back and change. And how many revisions does it take before they get stuff working as expected. If they tell you they get things right the first time, they are bullshitting. Or, you are speaking to a Ken Thompson, a Jeff Dean, a Jonny Ive — a rare genius, an exception who proves the rule.
Fail Fast, Fail Small, Fail Often
Given that the odds of getting software right the first time are low and multiple revisions would be required, how does one improve the odds of success? The answer is simple — tighten the feedback loop.
- Thin-slice features — break down features to the smallest atom that can be shipped — build features atom by atom and ship atom by atom.
- Validate Early — If you are a PM designing a feature, ask users if the feature is going to add value to their life? Would the user pay for the feature? How would the user put the feature to use in his life? Do this before picking up and prioritizing a feature.
- Test with Users — If you are a designer, create rough prototypes and get a sense of how it feels to use the interface. Show it around to some people who are not on the product team to get an outsider’s perspective.
- Write Tests — If you are a programmer, write some code and then test it before writing more code. The tests may be unit-tests, asserts, or just print statements — but put them in before adding more code.
- Ship Early — If a feature is half-ready, start sharing it around for people to try it out before taking it to finish.
As you do this, you will still not get things right first time. You will still make mistakes, except these are going to be smaller mistakes; you will discover them faster and fix them faster. The feedback loop would get tighter — you will iterate faster.
The best software teams in the world already understand this and are optimized for fast iteration speed. Facebook’s motto since a long time has been “Move Fast and Break Things.” In his first letter to investors, titled The Hacker Way, Mark Zuckerberg had this to say:
Hackers try to build the best services over the long term by quickly releasing and learning from smaller iterations rather than trying to get everything right all at once. To support this, we have built a testing framework that at any given time can try out thousands of versions of Facebook. We have the words “Done is better than perfect” painted on our walls to remind ourselves to always keep shipping.
Hacking is also an inherently hands-on and active discipline. Instead of debating for days whether a new idea is possible or what the best way to build something is, hackers would rather just prototype something and see what works. There’s a hacker mantra that you’ll hear a lot around Facebook offices: “Code wins arguments.”…Moving fast enables us to build more things and learn faster. However, as most companies grow, they slow down too much because they’re more afraid of making mistakes than they are of losing opportunities by moving too slowly. We have a saying: “Move fast and break things.” The idea is that if you never break anything, you’re probably not moving fast enough.
Google has a similar approach — Google Chrome was first released towards the end of 2008 and within 2 years was the best browser in the market. They maintain multiple release channels — a daily release called Canary and a weekly release called Dev. The releases to regular users go on a 2–3 week cycle. Their philosophy:
Release early, release often. We think that’s the best way to develop software that delights people. With Google Chrome, we want to release fewer features more often instead of making you wait 12 months for the next Major Dot-Oh Release Jam-Packed With Features. We can get your feedback faster, fix things faster, and release new improvements as soon as they’re ready. We want Google Chrome to stay nimble so it can keep pace with changes in the sites and web apps you use.
Android is also developed on similar lines. Check the Android version history to see the pace at which they release. Facebook and Google are not unique — the best software teams in the world today build software in small, rapid iterations.
It’s the People, Stupid
So if faster iterations are the best thing since sliced bread, why are more software organizations not optimizing for iteration speed? That’s because increasing iteration speed is not easy. The first step itself — admitting that you will not be able to build things right upfront is hard to internalize for most people, especially business stakeholders who are not familiar with software development.
- Even if the business stakeholders get comfortable with the idea of building through making mistakes, they have to realize that in software everyone must be allowed to make mistakes. You need to trust the product team to make the right decisions. If you insist on checking and approving each change, you will block the process and not get iteration speed.
- If the designers and the PM suffer from hubris and come up with features and design interfaces without taking user feedback, they will discover issues late and not get iteration speed.
- If the devs find writing tests a chore and believe that it will slow them down, they will end up spending time towards the end finding and fixing bugs and not get iteration speed.
All these issues are common enough that it is not surprising how often teams and processes are optimized for building things right and not building things fast. Of course in such a setup, your feedback loop is long and you run the risk of
- Solving the wrong problems
- Taking on unnecessary complexity early
- Discovering mistakes late — when they are bigger and more expensive to fix
How to Iterate Faster
A single individual can increase his own personal productivity but increasing iteration speed of a team requires buy-in across all levels, changes in organizational culture, processes and investment in people and tooling:
1) Hire smart people: Well, you always want to hire smart people. What is so special about hiring smart people to increase iteration speed? Two things:
- The 10x programmer: There is a lot of research that indicates that the best programmers are an order of magnitude more productive than the worst programmers. Check Fact 2 from Facts and Fallacies of Software Development for references.
- Brook’s Law: According to Fred Brooks, adding manpower to a late project makes it later. The corollary is that there is an incremental person who when added to a project makes it take more, not less time. This is because of communication overheads and people taking time to gain context.
Put the two together and you realize that the most productive teams are small teams of smart programmers. But you don’t need just programmers to be smart — everyone on the team needs to be smart. The problem is it is quite hard to find smart people, and in the face of mounting pressure, it is easy to give-in and hire average people. That is a mistake. Hire only smart people — an open position is a problem for a few months, but a bad hire is a problem for years.
2) Decentralize decision-making: To increase speed you need to make decisions fast and not get blocked. Ideally, people who are building things should be allowed to take decisions. If decisions are being taken by someone who is not involved in “building” the decision, you have a problem.
In fact, if you do not give autonomy, there is no point hiring smart people — you are not benefiting from their smarts anyway, and eventually they will get frustrated and leave.
3) Build Less: The reason you want to iterate fast is to spot and fix mistakes early. If you add complexity to the software, your ability to spot issues reduces, you have more variables to deal with and you get slowed down. Moreover, you increase complexity for your users. They now have to deal with more choices, which makes it harder for them to work with your software. Building more hurts everyone. Go in the reverse direction — build less.
4) Automate Operations: Since you want to release fast, you have to necessarily invest in automated deployment, functional tests, alerts, capacity provisioning, etc. This not only increases development speed, but also reduces chances of human error and allows you to scale faster.
5) Increase Test Coverage: To get builds out faster, you need to invest in continuous integration and fast unit tests that get run on every build. This reduces regressions, keeps quality consistently high and improves design. Without this, you would not have the confidence to change code quickly, you would want to get things tested after every change, and these tests would be manual.
6) Measure Everything: Even if you have all the infrastructure to build and release rapidly, you will still not get iteration speed. After all, iteration speed is not just about releasing fast. It is essentially about making mistakes quickly and fixing them quickly. But how do you know whether you have made a mistake? You need data for it. What can be measured can be improved and what cannot be measured cannot be improved.
Doing all this is not easy — you have to spend more energy upfront — but once the virtuous cycle of rapid iteration begins, it pays off big and you would never go back to the older approach of building big and slow.