How to deal with a sad reality.
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?
– Brian Kernighan
It has always been easier to break things than to make things. Software is no different. If anything, software has made it explicit. We can prove There are an infinite number of valid software programs. How many of those actually do what we want, without bugs?
Far less (yet amusingly, still infinite).
Even if you ignore all of the bugs that software engineers create themselves, software engineers comprise only about 0.3% of the world’s population. Mother Nature and the other 7.7 billion people aren’t sitting idle. Yes, many of those other folks are solving problems without software, and certainly not all of the problems people create can be solved with software. Yet as companies far and wide try to use technology to solve the world’s ills, they grapple with an inviolable truth: there will always be more problems than engineers.
That has consequences. Kernighan was focused on software design. Simple designs lead to more maintainable software. When software is easier to maintain, it causes fewer (and smaller) problems. But there are larger, more widespread consequences outside of a strictly technical domain:
Companies obsess over their work backlogs. They see all of these problems and respond by hiring entire teams of project managers to build and prioritize the hell out of some enormous Jira board. But when you realize that you’ll always have more problems than engineers, optimizing a backlog makes no sense. When you’re overwhelmed with problems, ordering them isn’t the most important skill, filtering them is. The most valuable prioritization skill is simply saying “No. I’m not going to solve that problem right now.”
Too often, teams take the opposite approach. They catalog all of the features and bugs and customer requests and tech debt and nice to haves. They try to build a complete picture of all the work so things can be estimated and estimated and ordered — even though software tasks rarely have a quantifiable value. The list of work for your team could do is far larger than they ever will do during their lifetimes. Enumerating that list is folly.
The bigger challenge is that even if you manage to do all of that, most of your problems still won’t be in the backlog. Which brings us to consequence number two:
Most problems are not big problems. They aren’t building some API or optimizing some algorithm. They aren’t fixing some bug or testing on the 9000 flavors of Android. Most problems are tiny. Stuff like “What should I name this variable?” or “Should this be a list or a map?” or “Does Bob need to know about this?” — problems so small that it is impractical to have a meeting every time they come up.
How do engineers prioritize those tiny problems? Haphazardly, if we’re being generous. Software engineers don’t get training in prioritization skills. They rarely get coaching in workload management. There’s no great feedback loop for engineers to know if their choices are improving. Alone these tiny problems don’t matter much, but combined they represent a huge part of software’s success or failure.
Deliberately valuing and investing in engineers’ work management skills is a good first step in improving engineers’ effectiveness. It will keep them from being overwhelmed with problems, and ideally help them focused on the valuable ones. But it is not enough. Knowing what problems are valuable and what problems to say “no” to requires context. When all engineers have a user story with an estimate, they don’t get that context. All they know is an acceptance criteria and an estimate — what to do and when to do it. They don’t get why to do it, or what tradeoffs they should favor when doing it, or what they could be doing instead.
Yeah, software engineers aren’t great at prioritization. It is hard work to coordinate everyone making their own tradeoffs. But the solution isn’t to take the prioritization out of engineers’ hands! They’re usually the ones closest to the problems! The solution is to put them in a situation where they’re more likely to succeed. Get them some context. Build good abstracts so teams can safely ignore most problems. Help them grow the skills needed to deal with their own unavoidable mountain of problems.
Everyone loves it when a plan comes together. We love when an intricately designed heist ends with the good guys simply walking out of the casino, loot in tow. We love it when the universe is saved by some rookie flying down a canyon of laser turrets so that they can finally use their history of animal abuse for good. We love seeing those 1 to 14,000,605 longshots (and 22 movies’ worth of investment) pay off.
Some lucky fools doing the impossible is great fantasy, but these are all terrible plans.
They are all intricate, with multiple (unlikely) things that have to happen just right for the heroes to succeed. This makes them fragile. If one part of the plan encounters a problem, then the entire thing starts to fall apart. People scramble to keep it together, and usually make rash decisions responsible rather than be the one for destroying the Big Plan. You are going to have more problems than engineers. Your plans will need to accommodate that.
Let’s consider a movie with a good plan. At the beginning of Ronin, Sam is going into a cafe to meet with some dangerous strangers. Lots of things could go wrong. He observes the cafe ahead of time, and makes a plan. Behind the café he stashes a gun. As he enters the café, he asks for the toilets and uses it as an excuse to unlock the back door. If any number of things go wrong, now he has a quicker exit and the gun ready if needed.
The thing is, Sam didn’t have to execute the plan. The meeting went smoothly. Everyone walked out the door peacefully and he retrieved the gun. Most companies see this as waste. Work spent on something that didn’t provide value? That’s something to clean up! Something to optimize away!
But this is the sort of plan that companies need to embrace. Good plans increase your options, even if you don’t always need them. When things go south (and they will), that unlocked door or stashed gun means that you have more paths to victory. You shouldn’t plan for every possible problem. There’s too many of them anyways. Focus on the big and likely ones. Give yourself options, so that you can choose the best option when you finally find out which problem is going to show up this time.
Imagine that you have a list of chores to do. Clean the house, mow the grass, pay your bills. You don’t really want to do them, but you’re a mostly responsible adults, so you do them. A day of hard work later, you finish all your chores only to look up and find out the list is bigger! Now you need to fix the car and walk the dog and make some dinner and schedule that doctor’s appointment and… ugh.
This is software engineering in a nutshell.
As your team solves problems, the company succeeds and grows. Now it has more, harder problems for your team to solve (in addition to maintaining the stuff you already built). For people that focus on problems, it can seem as though things are never getting better. All that work, and there’s still all of these problems. They’ve run for hours but didn’t get anywhere.
Since there’s always going to be more problems, engineers’ sense of accomplishment needs to come from elsewhere. Some folks have it easy. They love solving problems. The never-ending stream of problems is like the world’s largest game for them. As long it stays fun (usually by striking the right balance of difficulty and variety), it doesn’t really matter if they’re not getting anywhere — the journey is enough for them.
Others have it harder. They need to see changes. And that doesn’t work when there’s always going to be more problems to solve. You can spend your entire life making your corner of the world a better place, and still have lifetimes of work to do. That doesn’t mean that you didn’t accomplish anything. Quite the opposite! But the only way to see that is to look backwards.
The better way to measure progress is to ignore the problems and think about what we’ve built. What things can we do today that we couldn’t yesterday? What things are easier now? What would have fallen into ruin if we weren’t there. Those things do change. We can look back and see how things are better now than they were. Yes, new software brings with it new problems.
There’s always going to be more problems.