“There are two hard problems in computer science: cache invalidation, naming things, and off-by-one errors.” — Leon Bambrick
In 1986, computer architect Fred Brooks published a paper called “No Silver Bullet,” in which he observed that software engineering wasn’t producing the same productivity gains compared to hardware engineering.
Brooks argued that when it comes to making software, there were two major barriers to overcome: accidental complexity and essential complexity.
Accidental complexity refers to challenges that developers unintentionally make for themselves as a result of trying to solve a problem. (Fortunately, this kind of complexity can also be fixed or improved by developers.)
Essential complexity is just the nature of the beast you’re trying to tame. The example Brooks uses is, if users need a program to do 30 things, then those 30 things are essential; you can’t simply take out a few of them to make the software less complex. Whenever you’re solving a problem, there are just some areas of complexity that can’t be whittled down.
While Brooks was referring to complexity and how it relates to crafting and changing code, it applies to the end product, too.
Sales forecasting, weighing the probabilities of leads closing within a pipeline, and analyzing the behavior of your funnel are all essential to a CRM. On the other hand, hard-to-read charts, mental math, or reports that don’t instantly update in real time are all examples of accidental complexity.
When I think about the software we create at Nutshell, I often ask myself: How much of it is essential to the problem we’re trying to solve, and how can we remove any accidental complexity? How can any of the hurdles to writing the software — and using it — be avoided?
Your Code Is Your Organization
Conway’s Law states that “Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.” In other words, the software code that you’re writing will basically mirror how your company is laid out.
I’ve harped on this point so much that my team is probably sick of hearing it, but I believe that creating the right organizational environment is one of the most important things you can do in order to produce effective code.
To me, that comes down making the team more flat and open, so there aren’t any barriers to talking to other members of the team, or updating and improving the code. Ultimately the goal is to increase velocity, reduce knowledge silos, and improve the end product.
The challenge that huge companies like Google or Facebook have is that they have all these teams — sometimes even competing with each other on the same product — with varying levels of bureaucracy, process, and trickier channels of communication.
Now it comes with trade-offs, since the value and scale these products provide is unrivaled, but the complexity overhead has its costs, and insulating your architecture from it is a significant struggle for software development teams.
No Place for Heroes
Another way to reduce accidental complexity is to limit the number of “team heroes” as much as possible.
Sometimes you’ll have one rock star on the team who, when something breaks, they’re like, “Whatever, I’ll just go fix it.” That’s a common dynamic in a lot of software teams, but having these pockets of hero worship can be very harmful to knowledge sharing.
Maybe you’ve heard of the “bus factor” — how big of an impact would it be to our company if this guy got hit by a bus? That could apply to any department in a company, but it’s particularly felt in software development. Due to the number of moving pieces in software development, that high-bus-factor hero can go undetected, and suddenly you have a hidden single dependency that if lost will ripple unfortunate surprises. Now that’s some accidental complexity!
We’re not as risky as that at Nutshell, thankfully, but it’s something I try to be aware of. We perform code reviews, hold lunch and learns, and build upon tried-and-true techniques in effort to keep the tech stack approachable. Because reducing that “bus factor” is not only about immediate risk mitigation but improving our collective team knowledge, which leads to a better product.
The Power of Focus
There are a lot of tactical things you can do to push simplicity and reduce complexity, from the way you write code to the way you ship it. For example, we like to release things in small, incremental, iterative chunks so there’s not this big switchover that could create a lot of problems we’d need to react to.
But the thing we do that has the biggest impact is simply narrowing in on what’s most important.
As Fred Brooks noted, essential complexity is created when the user says there are 30 things the software needs to do, and there’s no way around it. But I would say, well, how can we whittle down the list to the 30 functions that are actually necessary?
One of Nutshell’s core values is focus. In my role, that means finding the broadest overlap of the essential things the software has to do and saying “no” to the things that fall outside of it.
We can’t try to execute every single feature request that comes in, because every marginal input potentially has an exponential reach of complexity. You have to have the audacity to say, “Well, we’re just not going to do that for the product.”
Think of how you would market a company: Your messaging isn’t supposed to resonate with absolutely every human being out there — you have to choose the target markets and personas that are most likely to use and benefit from your product.
I look at product development the same way. You have to choose some personas for each feature, and that inherently means that you’re going to exclude others.
Narrowing down what you’re trying to do will allow you to polish up the things that matter, and apply the right effort at reducing complexity. It’s not just a “nice to have” in good software, it’s essential.