"It Builds" Is Not the Same as Well-Designed

I was upgrading Vite on an old project last week and opened the config file. It was longer than the entire business logic. Fifteen plugins, a sprawl of aliases, and a handful of lines I could no longer explain to myself. The build passed. Lint was clean. CI was green. Everyone said there was no problem. But what that config file actually was, was a graveyard of accumulated decisions nobody dared revisit — it just happened to still compile.

That’s the defining trap of the JS ecosystem at scale: once the toolchain reaches a certain complexity, “it runs” becomes the only metric anyone bothers to check, and the question “is this design actually correct?” quietly disappears. A React project with six Babel plugins, TypeScript in strict mode with a dozen overrides, ESLint config inheriting three layers of shared rules — each addition feels like progress, like you’re being responsible and thorough, right up until you realise you’re spending half your energy keeping those tools from fighting each other. The build passes. You no longer know what happens inside it.

Then something breaks. And the instinct is never to question the design. Bundle error? Blame the bundler. Type inference gone sideways? Blame the compiler. SSR hydration mismatch? Blame the framework. The question that rarely gets asked is the one that actually matters: did I get the data flow wrong, or did I choose the wrong abstraction? Tool worship externalises the blame onto the ecosystem and substitutes switching tools for rethinking the design. Switch to Turbopack, switch to Bun, switch to the thing that came out this month — the complexity goes nowhere. It just hides inside the honeymoon period.

I’m not saying tooling choices are irrelevant. Vite is genuinely faster than Webpack. Bun’s startup time is a real improvement. But those tools solve tooling problems. They cannot clarify a component that has four different responsibilities, and they cannot fix an API design that was overfit to one use case from the start. “It builds” means your config files don’t contradict each other. It says nothing about whether the design makes sense.

I’ve made my peace with 1,200 packages in node_modules. What I can’t make peace with is treating that as normal, rather than as a signal worth questioning.

Key Takeaways

  • A passing build only proves your toolchain config isn’t contradicting itself; it says nothing about design quality.
  • When your config file is longer than your business logic, that’s a signal worth pausing on.
  • When something breaks, interrogate your assumptions and design first before blaming the ecosystem.
  • Switching tools moves complexity around; it rarely eliminates it.
  • Tools handle tooling problems. Data flow, responsibility boundaries, API design — those are yours to own.

Sheng’s take, drafted with Claude · part of the 2026-06-13 blog renovation, paint still drying.