The Art of Subtraction in Software Engineering
Why removing code, features, and complexity is often more valuable than adding them. A reflection on building simpler, more maintainable systems.
The Addition Bias
As software engineers, we’re wired to solve problems by adding things. A new feature request? Add a module. Performance issues? Add caching. User complaints? Add configuration options. This “addition bias” is deeply ingrained in how we think about building software.
But here’s the uncomfortable truth: every line of code is a liability. Every feature is a commitment. Every configuration option is a decision users must make. The more we add, the more we maintain, debug, document, and explain.
Lessons from Removing I18n
Yesterday, I removed internationalization (i18n) support from my personal blog. It was a feature I spent considerable time implementing—translation files, language detection, URL routing, UI toggles. It felt sophisticated. It felt professional.
But I noticed something over time:
- I only wrote content in English
- The Chinese pages sat empty, collecting dust
- The build times were slower
- The navigation was cluttered with a language toggle I rarely used
- The codebase was significantly more complex
Removing it took about 30 minutes. The immediate result? 18 pages instead of 40+. Cleaner URLs. Faster builds. Simpler mental model.
The kicker? I don’t miss it at all.
When to Subtract
Subtraction isn’t about being minimalistic for its own sake. It’s about being honest about what actually delivers value. Here are signals that something might be a subtraction candidate:
1. The Maintenance Tax is Too High
Some features cost more to maintain than they’re worth. Ask yourself:
- How often is this used?
- How often does it break?
- How long does it take new team members to understand it?
If the cost-to-value ratio is skewed, consider removing it.
2. It’s a “Just in Case” Feature
We all have them. The export-to-CSV functionality that one user requested three years ago. The dark mode toggle on an internal dashboard. The plugin system for a product with no plugins.
“Just in case” is often just “never.” Be ruthless.
3. There’s a Simpler Path to the Same Goal
Sometimes we build complex abstractions when simple solutions exist. That fancy state management library when URL params would suffice. The microservices architecture that could be a monolith. The custom build pipeline when a simple script would work.
Complexity should be earned, not assumed.
4. It’s Technical Debt in Disguise
Legacy features that don’t align with current architecture. Code that “we’ll refactor someday.” Workarounds that became permanent.
These are subtraction opportunities masquerading as maintenance burdens.
The Psychology of Removal
Removing code feels risky. It feels wasteful—“I spent time building that!” But this is sunk cost fallacy in action.
The code you remove today is:
- Time saved in future debugging
- Cognitive load lifted from developers
- Build minutes given back
- Documentation that doesn’t need writing
- Tests that don’t need running
Deletion is productivity.
Practical Subtraction Strategies
Feature Flags for Sunset
Don’t yank features immediately. Use feature flags to gradually sunset them:
- Ship the feature with a flag
- Default to on, allow opt-out
- Default to off, allow opt-in
- Measure usage
- Remove if metrics support it
The “One Month” Rule
If a feature hasn’t been used in a month (by you or your users), seriously question its existence. This applies to:
- Browser extensions
- IDE plugins
- CLI tools
- Dashboard widgets
- Code modules
Dependency Audits
Regularly review your dependencies. Each one is code you didn’t write but must maintain. Ask:
- Are we using more than 20% of this library’s features?
- Could we replace it with native APIs?
- Is it actively maintained?
- What’s the bundle size impact?
Documentation-Driven Removal
If you struggle to explain why a feature exists or how it works, that’s a red flag. Good features document themselves. Complex features require manuals.
Case Studies in Subtraction
Basecamp: No Real-Time Chat
Basecamp deliberately doesn’t have real-time chat. Instead, they have message boards with deliberate async communication. This “missing” feature is a feature—it reduces interruptions and preserves deep work.
Apple: Removing Ports
Controversial, but Apple’s removal of ports (USB-A, headphone jack, eventually physical SIM) forces simplicity. Yes, it requires adapters initially. But it also pushes the ecosystem forward and reduces hardware complexity.
My Blog: English Only
Removing i18n didn’t limit my audience—it focused my energy. Writing one language well beats maintaining two languages poorly. The blog is better for it.
The Subtraction Mindset
Adopting a subtraction mindset means asking different questions:
| Instead of… | Ask… |
|---|---|
| ”What else can we add?" | "What can we remove without impacting core value?" |
| "How do we support every use case?" | "What’s the 80% use case we should optimize for?" |
| "What features do competitors have?" | "What can we do differently by doing less?" |
| "How do we make this configurable?" | "How do we make this decision for the user?” |
When Addition is Appropriate
Subtraction isn’t the only tool. Sometimes you genuinely need more:
- When user feedback consistently points to missing capabilities
- When complexity is inherent to the problem domain
- When the addition enables significant new use cases
- When removing would break core promises to users
The key is intentionality. Add because you’ve earned the complexity, not because it’s the default.
Conclusion
Software engineering is often described as building—crafting structures, assembling components, constructing systems. But equally important is the art of unbuilding.
Every deletion is a declaration: This doesn’t serve us anymore. We choose simplicity over possibility. We prioritize maintainability over feature count.
The best code is the code you don’t write. The best feature is the one you realize you don’t need. The best system is the one that’s understandable, maintainable, and focused.
Subtract more. Build better.
Written after removing 900+ lines of i18n code and feeling surprisingly good about it.