Losing races to skyscrapers
What it would take to compare the complexity of a skyscraper and a software product, and why the comparison ends somewhere uncomfortable.
Directly outside of my office window, a six-story luxury condo building climbs into existence. My proximity to the work means that I can see human hands set individual components of this building into place. Eventually, a building stands where there was none before. Foundation, steel frame, concrete pour, windows, and then usually a brick facade, at least on my block. Meanwhile, the software team I'm on languishes and churns. Floor after floor seemingly printed by the construction crew out my window while I chase stakeholder alignment. I found it funny, then sad, and finally embarrassing. Surely software can't be "harder" than construction. But what other explanation? Maybe this is a skill issue? Have we been mystifying software as uniquely difficult while the better explanation is incompetence? I think the place to start is a framework for comparing complexity across projects.
Counting parts
To compare complexity across domains, we need a unit. For a building, the "part" is easy and familiar: bolts, valves, wire segments, and so on. This is going to be a point of contention, but a software analog might be a function. Think of a unit of logic that could be replaced independently. This doesn't exactly work because a function can have conditional branches and much higher complexity than a bolt. This is back of the envelope, order-of-magnitude reasoning, and I'm open to revising if anyone has better ideas for these or the other generalization I'm making. Enough preamble, let's dig in.
How many parts in a large skyscraper? Thankfully, we have documentation for the Empire State Building: 10 million bricks, roughly 1.5 million rivets, 6,514 windows, 473 miles of electrical wiring, 70 miles of water pipe, and 2.5 million feet of electrical wire. That's more than 11 million countable parts from just a few categories. That doesn't include structural steel, pipe fittings, ductwork, light fixtures, elevators, or ceiling materials. Modern buildings also need data cables, HVAC zoning, security systems, and indeed, software. Tens to hundreds of millions of parts feels defensible, with the largest buildings likely to exceed that range.
For reference, I think there are physical objects with way higher complexity than skyscrapers, with cruise ships specifically standing out. Royal Caribbean's press materials for the Oasis of the Seas claim 500,000 steel structural parts alone, not counting any mechanical, electrical, plumbing, or interior systems. A bit more is known about that ship: it has six generators, a water treatment plant, and a hospital. Though the number of parts is strictly on the order of 10s to low 100s of millions, the requirements are stricter, the plans less templated, and the complexity is higher. I think it's important to show how part counts can be both useful and incomplete.
Turning to my potentially skill-limited domain of technology. Published figures for codebases are measured in lines of code, not functions so I'm going to use a rough conversion of one function per 10–20 lines. Google's monorepo held 2 billion lines of code across 9 million source files, in 2016. On the other hand, the Linux kernel that underlies most of the world's servers, phones, and embedded systems, only hit 40 million lines in January 2025. A more typical large tech company's proprietary codebase is probably in the range of 5–50 million lines. This is roughly comparable to the Empire State Building's countable parts, before we've done anything unfair.
Now let's do something unfair. The dependency tree, third-party code your application pulls in, is the software equivalent of a ship's supplier-provided components. According to a deps.dev analysis published in ACM Queue in 2024, the average npm project has over 85 direct and transitive dependencies. A modern enterprise web application averages over 1,200 transitive packages. The npm registry itself hosts over 3.5 million packages. If each dependency averages a few thousand lines of code, then a large application's full dependency tree can easily contain tens of millions of lines.
All three land in roughly the same neighborhood on raw part count. Tens to low hundreds of millions, give or take. But construction time varies and I think complexity does as well. We can draw two conclusions so far:
- Software can have as many parts as physical projects
- Complexity varies immensely even within projects that have roughly the same number of parts
Some reasons buildings are easier to construct
Perhaps the answer isn't in parts. A skyscraper is the same floor repeated, so maybe templatization explains the difference more cleanly. Sure the mechanical systems vary from floor to floor, but the ratio of unique designs to total floors is low compared to cruise ships and especially technology products.
Buildings also exist in a slower-changing environment. It's not a static environment, but the rate of change is measured in years. Contrapose this with cruise ships battered by waves and technology in a sea of shifting vulnerabilities.
Buildings act as nodes in a network, leaning on infrastructure like municipal utilities and roads. Likewise technology products have to lean on common infrastructure like cloud hosting, DNS servers, and ISPs. Cruise ships are uniquely atomic in their functionality out of need. Each ship must generate, route, and deploy everything from within.
Complexity may be associated with part count, but it seems to also be associated with uniqueness of parts, deployment environment, and integration. As the dimensions of complexity open up, maybe software is harder because of its complexity along different axes.
Some reasons software is harder to construct
The market punishes convergence. In construction, you want the same elevator as every other building because it's proven, cheap, and built to comply with building codes. In software, functionality is overwhelmingly bespoke. Redundant invention is everywhere in software. Open source is an exception to this, but the closer you get to the value proposition of most organizations, the more is built from scratch.
The dependency chain is unvetted. When a cruise ship installs an engine, it's been certified. When an application pulls in a package maintained by a single volunteer, there is no certification. The trust surface grows massively with the codebase too. A large enterprise app might depend on code touched by >10,000 individuals, none of whom owe that enterprise anything. Post-Heartbleed investments in open-source security have improved the situation, but they're voluntary, fragmentary, and nothing approaches the level of assurance that physical supply chains demand.
No physics to bound the design space. This may be counterintuitive but constraints can be an advantage. The yield strength of steel eliminates vast regions of possibility that would otherwise have to be explored. Software has no equivalent natural constraints. There is a processing tax on every decision because the problem space is so much larger.
The building is done. The codebase is never done. A skyscraper gets a certificate of occupancy that marks it as finished (for some definition of finished). Software gets deployed (sometimes) but it's fundamentally expected to be mutable. The software environment also shifts quickly. APIs change, and security threats evolve, and vendors sunset services. Most physical construction projects contend with conditions that change more slowly.
Combinatorial state space. Tech products often exist in multiple states simultaneously. Twenty-five feature flags, a few hundred permission sets, a dozen services. The state space becomes unfathomably large so fast. Software bugs live in unexpected interactions between states that nobody anticipated. No obvious comparison in physical construction.
Failure is illegible. There can be immediate visual feedback within physical systems. A part cut wrong might not fit. Software rot can be near-silent and bugs can be non-deterministic. There are pernicious issues in physical construction, and legible errors in software. But it is easier for failure to hide in software.
The physical substrate isn't zero. A major cloud platform operates millions of servers across hundreds of data centers on six continents. Each a warehouse-scale building with its own power substations and cooling plants. They're targets of nation-state warfare. The combined physical footprint rivals a mid-sized country's industrial base. Even a product that's "only on AWS" sits on that physical layer. The abstraction hides the physicality but doesn't eliminate it.
The two-axis view
Plot physical complexity on one axis and software complexity on another and a pattern emerges. The bottom-right is traditional large-scale construction where engineering standards and regulations have had centuries to develop. Think skyscrapers, cruise ships, submarines. The upper-left is software territory with similar levels of absolute complexity (though along a different access) but no equivalent institutional scaffolding. The upper-right, high on both axes, is nearly empty. The ISS and Boeing 787 sit nearby.
If you imagine a temporal component you'll note the drift is all vertical. Cars, aircraft, medical devices, and even buildings are gaining software complexity while physical complexity stays flat. A premium car now runs roughly 100 million lines of code. The Boeing 787 runs 6.5 million lines of avionics code. Physical objects are stretching up the software complexity axis.
The third dimension
But there's a hidden axis that the two-dimensional view compresses. Call it criticality, or the consequence density per part. When you add it, systems cluster by category in a way they don't on the other two axes.
The ISS, nuclear submarines, commercial aircraft, and MRI machines all cluster at high criticality regardless of where they sit on physical or software complexity. The cruise ship, despite extreme physical complexity, drops to moderate criticality because the more complex parts of the machine aren't likely to kill someone.
This clustering also reveals an engineering principle:
The complexity of a system is limited by its consequence density.In practice, this means: if you're building at the extremes of complexity, you are exposing yourself to more risk than a highly-contingent environment can tolerate. Extreme complexity leads to unverifiable systems, and unverifiable systems cannot be trusted with severe consequences. The objects we think of as the most impressive engineering, like planes, submarines, and space stations, are actually middling in complexity. Because they have high criticality, they can't afford to have extreme complexity. The ISS's flight software is only 1.5 million lines.
A premium car's 100 million lines of code span everything from braking to the seat heater. But the safety-critical software, the braking, steering, and powertrain is only a small fraction of that code. That small fraction of the code is certified to the highest safety integrity level. The solution to increasing software complexity in higher criticality environments is in partitioning components by criticality and keeping the high-consequence partitions small enough to verify.
Software isn't low-criticality
There's an implicit assumption baked into software culture that software failures are economic, not mortal, and that this lower consequence density licenses the extreme complexity in tech products. But that assumption is increasingly wrong.
Medical devices and autonomous vehicles are obvious cases where software failures kill. But subtler is that economic impacts, at scale, become physical impacts. When a major cloud platform goes down, hospitals lose access to patient records. A payroll system bug means people don't get paid on time and someone gets evicted. The further down the chain you follow a major outage, the more the consequences resemble what safety-critical engineering was designed to prevent.
In 2024, a faulty update to CrowdStrike's Falcon security agent, a tool most end users didn't know was running on their machines, bricked something like 8.5 million Windows machines. Airlines grounded flights. Hospitals postponed surgeries. Emergency 911 services went down. Because of a dependency update.
I started off unsure of whether software was complex enough to warrant the way we wrestle with it. Now I'm nervous we're ill-equipped to curtail the spiralling complexity of tech products regardless of their increasingly critical nature.
Regulation? Say it ain't so.
I started this by trying to test the intuition that building a complex technology product shouldn't be as hard as building a skyscraper. Direct comparison is difficult, but I feel comfortable saying that many complex tech products are more complex along their axis of complexity than a skyscraper is on its axis of complexity. The skyscraper went up faster because it's genuinely a simpler problem.
But the more interesting thing is that our most consequential software systems—the cloud platforms that hospitals, financial systems, supply chains, and government services depend on—are simultaneously at the extreme end of complexity and consequence scales.
I think the safety-critical engineering teams of the physical world would call this configuration impermissible. Our most critical tech products are too complex for their importance. Much of the complexity is essential, genuinely load-bearing, the product of solving hard problems at scale. But accidental and market-induced complexity intermingles with essential complexity over time and increases the likelihood of a major tech incident causing a human catastrophe.
I didn't set out to write an essay that points at regulation. I set out to understand why a building went up faster than a website. But the question kept answering itself one layer deeper than I expected, and here we are. I came to this exercise embarrassed by a skyscraper. I'm leaving it worried about something else entirely.
Appendix: Back-of-the-envelope part counts
These are the estimates used throughout, with sources where available. All are rough. The point is order-of-magnitude comparison, not precision.
| System | Physical parts (est.) | Software (lines of code) | Key sources |
|---|---|---|---|
| House | ~50,000 | Negligible | General construction estimates |
| Highway bridge | ~500,000 | Negligible | Structural engineering estimates |
| Skyscraper (50+ stories) | 5–10 million | Minimal (BMS/HVAC controls) | Inferred from MEP scale |
| Automobile | ~30,000 | ~100 million (premium) | Industry consensus; IEEE Spectrum |
| Commercial aircraft (737-class) | 2–4 million | 4–7 million | Boeing, industry reporting |
| Boeing 787 | 2–4 million | 6.5 million (avionics only) | Green Hills Software; FlightGlobal |
| Nuclear submarine (Virginia-class) | Tens of millions (est.) | Classified | Displacement/system extrapolation |
| Cruise ship (Oasis-class) | Tens of millions (est.) | Moderate | Royal Caribbean: 500K steel parts alone |
| ISS | Millions (est.) | 1.5M flight / 3M ground | NASA Facts & Figures |
| Complex tech product | Near-zero direct; substantial via infra | Millions own + tens of millions in deps | Varies widely |
| Major cloud platform (AWS-scale) | Millions of servers, hundreds of facilities | Hundreds of millions+ | Industry reporting |
