Ahead of its time in many ways, with some notable misses.
The book covers a lot so I'll address each chapter's thesis (each chapter is a
separate essay) and describe whether it holds up today, based on my experience, and
my thoughts on it (if any). Obviously with the widespread use of large language
models things may have changed significantly in this area, but how much things have
changed is still up to debate.
Chapter 1: The Tar Pit: This chapter essentially says that software
engineering will always take more time than you think, because it is a complex
process that balances the design, integration, and testing of components with
the productionizing of a system.
My thoughts: This is a pretty general point that holds up not just in
software engineering but probably in many fields (not that I am really familiar
with fields besides software). I would argue that not all software needs to be
productionized. Certainly lots of software that I have worked on is never
really productionized but rather, in the words of Macduff, "from [its] mother's
womb / Untimely ripped", and in the words of Richard III, "Deformed, unfinished,
sent before [its] time / Into this breathing world scarce half made up". In less
Shakespearean terms, a lot of the software I have written and have seen in the
wild is thrown together quickly and patched up later as needed. For the purposes
that Brooks is describing in his book, however, that's less acceptable, given he
is describing the software building process for an operating system rather than
yet another internal-facing reconciliation report without any real audit impact.
Chapter 2: The Mythical Man Month: This chapter discusses how men and
months are not interchangeable, or rather that they can be but that the mapping
is not linear but something closer to polynomial or exponential.
My thoughts: I haven't worked on a project of the scale Brooks describes
from start to finish, so I haven't really been able to see whether this works in
practice. These days I think software tends to be built more fluidly with sprint
cycles rather than large deliverables; at least, that's how it works for
internal-facing software. Even for external-facing software, like apps on an app
store, sprint cycles can be used because the Internet exists now and features
and fixes can just be pushed to people's devices automatically. This means that
the timeline of a software project is much more flexible, and the "deadline
pushback" of adding people to a project takes the form more of a vague
intermittent performance degradation in software update cadence as newcomers are
brought up to speed than anything else.
I do agree with Brooks on his point about bringing people up to speed though.
Without documentation or at least well-commented code it tends to be a little
more difficult. It's necessary for people with experience working on the project
to take time out of their day to do at least a brief knowledge transfer for the
parts of the project the newcomers will be working on. But again, given the more
drawn-out "indefinite-maintenance-mode" software development timelines,
newcomers have all the time in the world to slowly learn the ropes by being
assigned tickets that begin small and increase in scope over time as they get
used to the project.
Chapter 3: The Surgical Team: This chapter essentially says that one
person should have the entire responsibility for a component's architecture, and
that there should be a number of others around him that act as designated
assistants.
My thoughts: I don't think this holds up too well today. Rather than
having only one person own the architecture/design of a component, it's better
to have at least two owners so that there's coverage in case new features need
to be added while one is on vacation or otherwise unavailable, to prevent a bus
factor of 1. Additionally, some of the roles are obviously obsolete now, like
the (two!) secretaries, the editor, and the clerk. Most of the remaining roles
are replaced by organization-level teams, like a devops team, and the budget
management done by the administrator is also done at a higher level by the team
of a COO reporting to a the CTO or something similar.
The roles of language lawyer and toolsmith are pretty much obsolete as well,
because the tooling for modern programming languages is very polished and
uniform (IDEs with LSP support, autoformatting and smarter tools are pretty
ubiquitous now). LLMs help with this too.
Chapter 4: Aristocracy, Democracy, and System Design: This chapter argues
that the ratio of function to conceptual complexity should be as high as
possible - specifically that having too many functions in a piece of software,
to the point that it significantly increases its conceptual complexity, is bad.
My thoughts: I think that this is reasonable when discussing a single
component of a piece of software, but when software has many separate
components, I think it doesn't make sense to look at them in aggregate and
construe that their abundance of functionality is bad. Rather, the "ratio test"
should be used to determine when it's time to refactor a large component into
separate sub-components, or on a smaller scale, split a large module into
sub-modules or a large file into separate files.
Chapter 5: The Second System Effect: This chapter says that often, the
second system designed after the initial successful system is often too full of
features and loses the conceptual integrity and/or simplicity of the initial
system (it is over-designed).
My thoughts: I think this chapter is less relevant now, because we very
rarely do a full redesign of a piece of software and make a real "second
version". I actually think that lots of these chapters are more relevant to
fields like game design than modern software development, because of the
conceptual separation between different versions of a game when compared to,
say, the degree of conceptual separation between 2025's version of iOS and
2026's version of iOS. It's a common thing to see that indie games produced
after an initial success can succumb to feature bloat and extended timelines
(e.g., Hollow Knight: Silksong, Deltarune). Some games also finally reach a
version that people really like, but never manage to move on,like Skyrim and GTA
V. These games probably share the same motivations for feature bloat with those
of Brooks' pieces of software - a new version always has to outdo the previous
one, and the success of the previous version lends itself to a large budget to
make these new (possibly questionable) features that would otherwise not be
implemented. It's probably on video game design teams where the techniques
described in this chapter to nudge software designers away from feature bloat
are the most relevant (as seen in Hollow Knight: Silksong's development process,
where the publishing agent had to kind of fill this role).
Chapter 6: Passing the Word: This chapter describes the need for both a
formal description of how a system works, and a prose description for
comprehensibility.
My thoughts: I don't think this one holds up too well today.
Documentation is certainly useful, especially for large projects where there is
lots of code reuse, mostly in the case of common libraries. But formal
descriptions of how systems work don't really appear anymore (outside of the
formal programming language specification sphere), and are not as relevant
unless you're writing papers on some new cryptography system or blockchain idea.
Chapter 7: Why Did the Tower of Babel Fall? This chapter discusses how
communication and organization is required for software projects. It also states
that the entire software system should be transparent to all developers,
although Brooks says in his "Propositions of The Mythical Man-Month: True
or False?" chapter that he has been convinced otherwise, and that software
components should have their inner workings opaque to external users.
My thoughts: The idea of component opacity (the OOP term is
encapsulation) is now widely practiced in all languages, not just in OOP-centric
ones. Even non-OOP languages like C will expose function definitions and expect
users to take them at face value.
The communication and organization message of the chapter is important too;
there is some overlap in the organization part with the previous chapter on
documenting the system, but the bit about teams needing to communicate changes
to each other is definitely relevant. Software teams should have an idea of the
upstream and downstream dependency chain that their changes will impact, and
ensure that they inform those dependency owners well in advance of any API (or
database) changes so that the dependent teams can make the relevant changes on
their end so things work.
Chapter 8: Calling the Shot: This chapter says that as the scope of a
programming task increases, overhead increases at a rate higher than linearly.
It also says that using a high-level language can decrease this overhead
significantly, and that productivity gains are around 5x.
My thoughts: There's definitely more overhead as the size of a project
increases, because you need to account for more moving parts and more
dependencies even within your own project (let alone the upstream and downstream
dependency issues described above).
Also, I've been using high-level (by Brooks' standards, C and above are
"high-level", but I've been using mostly Python which is worlds above C in
whatever level hierarchy one wants to make up) programming languages for my
entire programming career. You don't need to look at the TIOBE programming
language index or the Stack Overflow developer survey to know that the so-called
low-level programming languages are really not used at all anymore. Brooks was
clearly right about this one.
Chapter 9: Ten Pounds in a Five-Pound Sack: This chapter discusses
keeping program size small so that it can fit into memory.
My thoughts: This chapter is completely obsolete because memory sizes are
now
colossal compared to program sizes.
Chapter 10: The Documentary Hypothesis: This chapter says that a small
number of documents end up being used to make most of the decisions by project
managers.
My thoughts: I think this chapter is a bit vague. I think that in many
cases, the documents needed for high-level meetings are created just-in-time by
the people who have worked on the system, and provided to project managers on
request. This makes the documents less relevant outside of their designated
meeting context but makes them immensely more accurate at their time of use. I
think this method is better, provided the software engineers are sufficiently
competent in document-creating or diagram-creating software to be able to
generate these documents quickly and effectively.
Chapter 11: Plan to Throw One Away: This chapter advocates for the use of
a beta version for software, which gets discarded or heavily refactored before
any version is shown to real users. It also describes how software maintenance
can take around 40% of the total time and/or resources invested in the initial
software development, and advises towards building systems that are easily
repairable.
My thoughts: With regard to the beta version item: as with many of the
other chapters, this is a good idea for
"one-and-done" pieces of software like games, where the initial release is the
most important time for the software, so that it can gain adoption. For internal
software and tools, however, I would argue that the initial release of the
software is a beta version, or at least serves that role, without
requiring a full rewrite, since adoption within an organization is necessarily
slow until the technology has reached some minimal level of maturity. In other
words, I don't think this is as relevant in the context of my experience and
current role.
For the software maintenance part: this is definitely relevant to my experience,
although I might go further to argue that software maintenance is more than two
thirds of the total software development cost (rather than just some percent of
the initial development cost). Building systems that are repairable is a great
idea, even if it costs you some amount of job security (the next guy will thank
you).
Chapter 12: Sharp Tools: This chapter emphasizes the importance of good
tools for software engineering, including dedicated machines for debugging, and
a performance simulator.
My thoughts: I don't think this one held up too well in the examples it
described, since debugging is always done on one's own machine and performance
is much less of a concern for people now (not that it shouldn't be more of a
concern, but that's how things have shaken out). But the general emphasis on
good tooling has definitely held up. If your tools are constantly breaking when
you're trying to work with them, it destroys your flow state and the impact to
your sprint timeline can reduce your credibility (and/or that of your team) with
end users.
Chapter 13: The Whole and the Parts: This chapter advocates top-down
design and structured programming as techniques to make designing complex
systems easier.
My thoughts: Both of these have become commonplace today, structured
programming especially (all programming languages support this method, maybe
aside from esoteric ones like Forth). The chapter cites Niklaus Wirth (creator
of Pascal) who was definitely ahead of his time as well; I didn't know that he
came up with the top-down approach idea too, I actually attributed structure
programming to him more than Djikstra (although Brooks cites Djikstra for this).
Chapter 14: Hatching a Catastrophe: This chapter states that large
project delays are caused by a series of small project delays which in
themselves may seem negligible but combine to create significant issues. It
recommends making milestones that are "so sharp [read: concrete] that [the
programmer] can't deceive himself;" and ensuring that if you miss one deadline,
you make the next one, to avoid a decrease in morale.
My thoughts: The statement about how small project delays combine to
create larger ones is a fact of life. I think the ways Brooks approaches solving
that issue are similar to the way "SMART" goals work: Specific, Measurable,
Achievable, Relevant, and Time-bound. Having individual contributors make these
Specific goals themselves forces the milestones to be "sharp", and to ensure
milestones aren't missed, you can tie these goals to manager feedback so that
meeting them has an impact on employee compensation. This has two wonderful
effects: (1) you put the onus on the employee to meet the goals in time rather
than being forced to help them achieve the goals on your own, and (2) it's a
great excuse to dock their bonus if they don't meet the goals they gave!
(Obviously I'm being facetious, I hate the method of making employees set SMART
goals for themselves for exactly these reasons,
even if they are effective from a managerial standpoint.)
Chapter 15: The Other Face: This chapter describes how programs are
typically interacted with in ways that are not anticipated by testers, and
therefore the number of bugs found by users increases rather than decreases as
adoption of the software package increases, eventually tapering off or
decreasing again. It says also that programs should be
self-documenting, and that programmers should make sure to write documentation
(and we should teach programmers to do so as part of their educations).
My thoughts: The first point is basically just this meme, which
is of course accurate. The next point is good, although depending on
how good the software developer team is, you may find that the rate at which
bugs are found never really tapers off. The point on documentation is of course
classic, you can't really get away with using single-character variable names in
your code unless they're really obvious, like for s in scenarios or
something similar, without having anyone who reads your code admonish you for
doing so. LLMs can be good at fixing these issues.
Chapter 16: No Silver Bullet - Essence and Accident in Software
Engineering: This essay argues that "there is no single development, in
either technology or management technique, which by itself promises even one
order-of-magnitude improvement within a decade in productivity, in reliability,
in simplicity."
My thoughts: The elephant in the room on this one is LLMs. There are lots
of people who probably claim that they can get (at least) one order of magnitude
of productivity improvement from the use of LLMs. And for one-shot tasks, where
code quality is less important than just completing the task, or for localized
refactoring work, or for a single-component change, they could be right - a
sufficiently good LLM could make the change in a couple of minutes with no
additional work needed from the prompter. But in aggregate, across large
codebases with significant complexity, I think Brooks' statement holds up today.
At least, until the next generation of LLMs rolls around, or we get some
AGI-adjacent agentic editing capabilities made widely available. For now though,
it seems like the bubble will burst long before that happens.