A classic. I was just getting started, when he wrote that, and that kind of thinking informed a lot of my personal context, throughout my career.
I feel as if a lot of multipliers have happened that he didn't anticipate, but I also feel as if the culture of software engineering has kind of decomposed, since his day.
We seem to be getting a lot of fairly badly-done work out the door, very quickly, these days.
To add to this, I think that in the past decades, the rise of large software ecosystems (e.g. around Python, Java, Windows, AWS, Azure), have had both positive and negative effects on accidental complexity.
On the one hand libraries and platforms save developers from reimplementing common functionality. But on the other hand, they introduce new layers of accidental complexity through dependency management, version conflicts, rapid churn, and opaque toolchains.
This means that accidental complexity has not disappeared, it has only moved. Instead of being inside the code we write, it now lives in the ecosystems and tools we must manage. The result is a fragile foundation that often feels risky to depend on.
Before advanced AI, "essential complexity" was a bottleneck and Brooks was right that there couldn't be continuous exponential gains in software productivity. However advanced AI will handle essential complexity as well, which can end up making it 10x or 100x faster to develop software. We still need humans currently, but there's no area that one can point to and say we'll always need people for this aspect of software development. The latest coding agents are already reasoning with requirements before they write code, and they will only improve...
Every year or two I like to re-read my 25th Anniversary Edition of Mythical Man Month (which included No Silver Bullet). Every time I pull out something different.
I think that the willingness to rely completely on OSS libraries has fundamentally changed SWE practices from 2004 when I earned my first paycheck. We all just agreed that it's okay to use this library where you don't know who wrote it, there is no contract on it, and everyone just accepts that it will probably have massive security holes, and you hope the maintainer will still be around when those are announced. This was not true in 1986, and it mostly wasn't true in 2006, but it feels like every week we get more announcements on new CVE's that it turns out half the internet- very much including products people paid real hard currency for- were using. And we just accepted it.
And yeah, mostly the ability to CD a new deployment immediately- plus force a download of a patched version- meant we could get away with it, but it trained us all to accept lower quality standards. And I feel it in my bones, that the experience of using software is markedly worse than in 1996 or 2006, despite vastly more CPU, RAM, and disk.
It's always humbling to re-read Brooks. His central thesis—that the real difficulty is the "essential complexity" of fashioning conceptual structures, not the "accidental" complexity of our tools—has held up for decades. As many in this thread have noted, it feels more relevant than ever.
Brooks masterfully identified the core of the problem, including the "invisibility" of software, which deprives the mind of powerful geometric and spatial reasoning tools. For years, the industry's response has been better human processes and better tools for managing that inherent complexity.
The emerging "agentic" paradigm might offer the first fundamentally new approach to tackling the essence itself. It's not a "silver bullet" that magically eliminates complexity, but it is a new form of leverage for managing it.
The idea is to shift the role of the senior developer from a "master builder," who must hold the entire invisible, complex structure in their mind, to a *"Chief Architect" of an autonomous agent crew.*
In this model, the human architect defines the high-level system logic and the desired outcomes. The immense cognitive load of managing the intricate, interlocking details—the very "essential complexity" Brooks identified—is then delegated to a team of specialized AI agents. Each agent is responsible for its own small, manageable piece of the conceptual structure. The architect's job becomes one of orchestration and high-level design, not line-by-line implementation.
It's not that the complexity disappears—it remains essential. But the human's relationship to it changes fundamentally. It might be the most significant shift in our ability to manage essential complexity since the very ideas Brooks himself proposed, like incremental development. It's a fascinating thing to consider.
However, things have actually changed since then. A lot.
Here is Brooks at a "20 year retrospective" panel[1] at OOPSLA '07:
"When ‘96 came and I was writing the new edition of The Mythical Man-Month and did a chapter on that, there was not yet a 10 fold improvement in productivity in software engineering. I would question whether there has been any single technique that has done so since. If so, I would guess it is object oriented programming, as a matter of fact."
Large-scale reuse, which was still a pipe-dream in 1986, and only beginning in 1996 is now a reality. One which has brought its own set of problems, among them the potential for a lot of accidental complexity.
We now use 50 million lines of code to run a garage door opener[2]. I can declare with some level of confidence that the non-essential complexity in that example is more than the 90% that Brooks postulated as a safe upper limit. Five million lines of code is not the essential complexity of a garage door opener.
And while that is an extreme example, it seems closer to the normal case these days than the comparatively lean systems Brooks was thinking about.
I have a hypothesis as to how much of this happens. There's a seemingly paradoxical idea: simplicity requires complexity while complexity can be achieved with simplicity.
I think a lot of this complexity happens with everyone's efforts to make things simple. The problem is actually in that there's multiple ways to define simple. I have a good example of this that happened just last week. I have some Papa John's gift cards from Costco, and was ordering a pizza with a friend. So we put in the gift card amount and find out it is just short of the order. No problem, we'll pay the difference with another card. Problem is... that's not possible. We had to edit the order so we could bring the price down. In fact, I think we see things like this happen with pre-paid Visa/MasterCard cards. The problem was that the programmer made too simple of an assumption: customers only need one gift card. How would we fix this? Well now we should probably write a method that allows an arbitrary number of gift cards and credit cards. Our method would need to allow this arbitrary splitting and the question then is how much we'd want to expose to the user (do we want them to split a purchase with two credit cards?).
I think all of us can hear a likely conversation in our head about implementing such a payment system. Some person is going to say that we're over complicating the problem. Especially when we're talking about credit cards, it probably is a safe assumption to make that the order will be completed with a single card. Except it's fucking pizza. How often do you end up venmoing your buddy after you order a pizza? You didn't actually make the things simpler, you just moved the problem elsewhere and actually added complexity. It's definitely more complex to have a whole other app to facilitate a second transaction than it is to just allow arbitrary payment cards.
I see this happen in code all the time and I think Unix Philosophy[0] can be really beneficial. You try to make your functions to very basic things and then put them together. I try very hard to write flexible code because the only thing I know is that the code is the goals of the code are going to change over time. So you don't write just to get a specific problem solved, you write to get your problem solved and for others to be able to use your building blocks. And your building blocks should just allow things to be modifiable. How many of those 50 million lines of code are redundant? I'd wager a fair amount![1] Not hard, you just use very minimal abstraction. Like if you write a function to calculate tax you don't fix the value of sales tax even though your business only operates in <state of your choosing>, you just expose the variable. Extrapolate this out. This is technically more complex if we're viewing the function in isolation, but it is simpler if we are viewing the program as a whole (and viewing it over it's progressive lifetime). Of course, you can go too far with this too and striking that balance is difficult. But typically I see code that is inflexible rather than too flexible.
[1] I hear people say they get a lot of utility from coding agents because it takes care of boiler plate and repetition. I think that says something. If you're doing something over and over (even with a bit of variation) then there's probably a better way to do this. Problem is that if you're just rushing to finish Jira tickets you'll probably never have the time to figure that out. If your manager just measures your performance in number of tickets completed they'll never care how many tickets your code created. Sometimes to go fast you gotta slow down. IMO the most time consuming parts of writing code are the planning and debugging (analyzing, rethinking, rewriting, not just...
11 comments
[ 4.8 ms ] story [ 34.0 ms ] threadI feel as if a lot of multipliers have happened that he didn't anticipate, but I also feel as if the culture of software engineering has kind of decomposed, since his day.
We seem to be getting a lot of fairly badly-done work out the door, very quickly, these days.
No Silver Bullet with Dr. Fred Brooks (2017) [video] - https://news.ycombinator.com/item?id=40233156 - May 2024 (1 comment)
No Silver Bullet (1986) [pdf] - https://news.ycombinator.com/item?id=32423356 - Aug 2022 (43 comments)
No Silver Bullet: Essence and Accidents of Software Engineering (1987) - https://news.ycombinator.com/item?id=25926136 - Jan 2021 (9 comments)
No Silver Bullet (1986) [pdf] - https://news.ycombinator.com/item?id=20818537 - Aug 2019 (85 comments)
No Silver Bullet: Essence and Accidents of Software Engineering (1987) - https://news.ycombinator.com/item?id=15476733 - Oct 2017 (8 comments)
No Silver Bullet (1986) [pdf] - https://news.ycombinator.com/item?id=10306335 - Sept 2015 (34 comments)
No Silver Bullet: Essence and Accidents of Software Engineering (1987) - https://news.ycombinator.com/item?id=3068513 - Oct 2011 (2 comments)
"No Silver Bullet" Revisited - https://news.ycombinator.com/item?id=239323 - July 2008 (6 comments)
--- and also ---
Fred Brooks has died - https://news.ycombinator.com/item?id=33649390 - Nov 2022 (211 comments)
On the one hand libraries and platforms save developers from reimplementing common functionality. But on the other hand, they introduce new layers of accidental complexity through dependency management, version conflicts, rapid churn, and opaque toolchains.
This means that accidental complexity has not disappeared, it has only moved. Instead of being inside the code we write, it now lives in the ecosystems and tools we must manage. The result is a fragile foundation that often feels risky to depend on.
https://futureofcoding.org/episodes/062.html
I think that the willingness to rely completely on OSS libraries has fundamentally changed SWE practices from 2004 when I earned my first paycheck. We all just agreed that it's okay to use this library where you don't know who wrote it, there is no contract on it, and everyone just accepts that it will probably have massive security holes, and you hope the maintainer will still be around when those are announced. This was not true in 1986, and it mostly wasn't true in 2006, but it feels like every week we get more announcements on new CVE's that it turns out half the internet- very much including products people paid real hard currency for- were using. And we just accepted it.
And yeah, mostly the ability to CD a new deployment immediately- plus force a download of a patched version- meant we could get away with it, but it trained us all to accept lower quality standards. And I feel it in my bones, that the experience of using software is markedly worse than in 1996 or 2006, despite vastly more CPU, RAM, and disk.
Obligatory XKCD: https://xkcd.com/2347/
Brooks masterfully identified the core of the problem, including the "invisibility" of software, which deprives the mind of powerful geometric and spatial reasoning tools. For years, the industry's response has been better human processes and better tools for managing that inherent complexity.
The emerging "agentic" paradigm might offer the first fundamentally new approach to tackling the essence itself. It's not a "silver bullet" that magically eliminates complexity, but it is a new form of leverage for managing it.
The idea is to shift the role of the senior developer from a "master builder," who must hold the entire invisible, complex structure in their mind, to a *"Chief Architect" of an autonomous agent crew.*
In this model, the human architect defines the high-level system logic and the desired outcomes. The immense cognitive load of managing the intricate, interlocking details—the very "essential complexity" Brooks identified—is then delegated to a team of specialized AI agents. Each agent is responsible for its own small, manageable piece of the conceptual structure. The architect's job becomes one of orchestration and high-level design, not line-by-line implementation.
It's not that the complexity disappears—it remains essential. But the human's relationship to it changes fundamentally. It might be the most significant shift in our ability to manage essential complexity since the very ideas Brooks himself proposed, like incremental development. It's a fascinating thing to consider.
However, things have actually changed since then. A lot.
Here is Brooks at a "20 year retrospective" panel[1] at OOPSLA '07:
"When ‘96 came and I was writing the new edition of The Mythical Man-Month and did a chapter on that, there was not yet a 10 fold improvement in productivity in software engineering. I would question whether there has been any single technique that has done so since. If so, I would guess it is object oriented programming, as a matter of fact."
Large-scale reuse, which was still a pipe-dream in 1986, and only beginning in 1996 is now a reality. One which has brought its own set of problems, among them the potential for a lot of accidental complexity.
We now use 50 million lines of code to run a garage door opener[2]. I can declare with some level of confidence that the non-essential complexity in that example is more than the 90% that Brooks postulated as a safe upper limit. Five million lines of code is not the essential complexity of a garage door opener.
And while that is an extreme example, it seems closer to the normal case these days than the comparatively lean systems Brooks was thinking about.
[1] https://www.infoq.com/articles/No-Silver-Bullet-Summary/
[2] https://berthub.eu/articles/posts/a-2024-plea-for-lean-softw...
I think a lot of this complexity happens with everyone's efforts to make things simple. The problem is actually in that there's multiple ways to define simple. I have a good example of this that happened just last week. I have some Papa John's gift cards from Costco, and was ordering a pizza with a friend. So we put in the gift card amount and find out it is just short of the order. No problem, we'll pay the difference with another card. Problem is... that's not possible. We had to edit the order so we could bring the price down. In fact, I think we see things like this happen with pre-paid Visa/MasterCard cards. The problem was that the programmer made too simple of an assumption: customers only need one gift card. How would we fix this? Well now we should probably write a method that allows an arbitrary number of gift cards and credit cards. Our method would need to allow this arbitrary splitting and the question then is how much we'd want to expose to the user (do we want them to split a purchase with two credit cards?).
I think all of us can hear a likely conversation in our head about implementing such a payment system. Some person is going to say that we're over complicating the problem. Especially when we're talking about credit cards, it probably is a safe assumption to make that the order will be completed with a single card. Except it's fucking pizza. How often do you end up venmoing your buddy after you order a pizza? You didn't actually make the things simpler, you just moved the problem elsewhere and actually added complexity. It's definitely more complex to have a whole other app to facilitate a second transaction than it is to just allow arbitrary payment cards.
I see this happen in code all the time and I think Unix Philosophy[0] can be really beneficial. You try to make your functions to very basic things and then put them together. I try very hard to write flexible code because the only thing I know is that the code is the goals of the code are going to change over time. So you don't write just to get a specific problem solved, you write to get your problem solved and for others to be able to use your building blocks. And your building blocks should just allow things to be modifiable. How many of those 50 million lines of code are redundant? I'd wager a fair amount![1] Not hard, you just use very minimal abstraction. Like if you write a function to calculate tax you don't fix the value of sales tax even though your business only operates in <state of your choosing>, you just expose the variable. Extrapolate this out. This is technically more complex if we're viewing the function in isolation, but it is simpler if we are viewing the program as a whole (and viewing it over it's progressive lifetime). Of course, you can go too far with this too and striking that balance is difficult. But typically I see code that is inflexible rather than too flexible.
[0] https://en.wikipedia.org/wiki/Unix_philosophy
[1] I hear people say they get a lot of utility from coding agents because it takes care of boiler plate and repetition. I think that says something. If you're doing something over and over (even with a bit of variation) then there's probably a better way to do this. Problem is that if you're just rushing to finish Jira tickets you'll probably never have the time to figure that out. If your manager just measures your performance in number of tickets completed they'll never care how many tickets your code created. Sometimes to go fast you gotta slow down. IMO the most time consuming parts of writing code are the planning and debugging (analyzing, rethinking, rewriting, not just...
Though I recommend a full read, for those who want a gloss, I made a mind map that identifies the major questions posed by the essay, with summary answers and supporting rationale: https://app.gwriter.io/#/mindmap/view/b52b7d35-4d8d-4164-ba5...
1. The internet with its forums, nowadays best represented by StackOverflow. 2. LLMs coding capabilities.
All other things: languages, tools, IDEs, techniques, libraries, are marginal improvements.