One of the hardest lessons to internalize in software engineering is the hidden costs of additional complexity. Sometimes, complexity is just inherent in the problem space. Matching passengers and drivers while adjusting prices to balance supply and demand is a complex and hard problem. So is routing questions and answers to the people most likely to answer and read them while scaling a community and maintaining quality. Or developing a rich document editor that works well across all devices and supports real-time collaboration. That’s the inherent complexity that we need to tame for the products to succeed.
But other times, the complexity that we wrestle with is complexity that we introduced ourselves. We wrote code in a new programming language that few people knew and now we have to maintain it. Or we added additional infrastructure because we wanted to try the new, hot technology stack that we read about on Hacker News, but it fails in ways that we didn’t initially expect. Or we introduced a feature that few people use but that consumes a disproportionate amount of our time through fixes and bug reports.
Replace “code” with whatever you build your own products from, and it’s still true.