Most people masturbate. Masturbation is often celebrated as a nearly universal pastime. It’s so widely accepted that you might feel like an oddball if you don’t partake. Research (yes, you can Google it) even suggests that masturbation is beneficial for health — it reduces stress and anxiety, keeps men meek, and offers pleasure with no side effects. “No side effects,” they say. Well… while I could go on about the perils of masturbation and pornography, this post is not about that.
Let’s talk about architectural masturbation in software engineering. I define architectural masturbation as:
Overcomplicating simple problems and implementing overly elaborate solutions, often driven by a desire to showcase technical prowess rather than addressing the actual needs of the hour.
I get it — everyone loves solving hard problems because it gives their brain a satisfying challenge. Tackling a tough problem not only deepens your understanding of the ecosystem but also buys you more time on a project, boosts your ego, and provides bragging rights. The proposal for an architecturally over-engineered solution often seems well-intentioned — it comes across as a gesture of ownership and is usually aimed at the long-term stability of the system. The motivations behind these initiatives, however, are more often than not, just personal. They’re mostly done to show off technical prowess, ride the wave of trends and buzzwords, and create the illusion of high performance.
I’ve encountered many architectural masturbators in my software journey, but there was one individual who was an absolute master at this art. They were tasked with integrating our frontend app with a third-party analytics tool (heap). This task was as simple as including a <script>
tag in the HTML, something like:
<script block-all-attributes={true} allowed-tracking-attributes="id,data-analytics-id,key">
That was it. We could have shipped the analytics integration with a single script tag and started deriving value from it in a day. I wasn’t involved in the planning of this project because I wasn’t part of their team, but I was asked to review the implementation. Initially, I pushed back lightly because I didn’t think such a simple review needed my attention, but I reluctantly agreed and set aside an hour at the end of my day to go through it. When I opened the pull request, I was completely taken aback — this person had submitted a PR with 165 files changed.
This was my first encounter with “architectural masturbation.” They had created an abstract <Analytics>
component that would inject data-analytics-id
into its child components. They then wrapped every single component in the codebase with their <Analytics>
component and added a name to each one. This was apparently aimed at making the analytics module extensible and vendor-agnostic. While I admire their hard work and the solution itself wasn’t inherently bad, was it the right solution at that point? I don’t think so. Product engineering is about solving problems with usability and affordability in mind. While their solution was certainly usable, having a senior engineer spend multiple weeks on this made it anything but affordable.
The cost of architectural masturbation is especially high in startups and fast-moving teams, where growth is essential for survival. It’s easy for senior engineers to promote ego-driven projects to their “hands-off” manager or stakeholder, particularly when these leaders aren’t well-versed in tech. Some common symptoms of architectural masturbation include:
- In these projects, there is a lot of feature creep, justified by hypothetical scenarios or extreme edge cases.
- Custom-built solutions over established tools and practices.
- Extreme emphasis on “doing things the right way” or implementing a “long-term solution.”
- Overemphasis on scalability -— the project is designed to handle a scale far beyond current or foreseeable needs, leading to wasted resources and time.
- Major refactors without any quantifiable gains.
It’s important to note that all of us can fall into this trap. Even the best engineers might occasionally indulge in over-engineering when faced with uninspiring tasks. Recognizing these tendencies in ourselves and others is key to avoiding unnecessary complexity.
A good way to avoid these kinds of projects is to have a stakeholder or leader who is well-versed in technology. However, a more fundamental fix is to ensure engineers are challenged with meaningful problems. Engineers are problem solvers at heart, and they often resort to architectural masturbation when their work lacks intellectual stimulation. I don’t advocate for “creating” hard problems just to keep engineers busy, but I strongly believe that solving even seemingly simple problems can demand deep, thoughtful consideration.
Going back to my definition of product engineering — Product engineering is about solving problems with usability and affordability in mind. Balancing both usability and affordability is inherently challenging. Consider a simple REST API handler, for instance. Usability must be assessed from various perspectives—how easily it can be integrated by the frontend, consumed by other APIs, utilized by AI agents, and managed in terms of error handling, logging, and alerting. Affordability also encompasses several factors—acceptable latency, cost, rate limits, tech debt, and the time required for delivery.
Simple problems are often not as simple as they seem. If engineers are truly inspired by the deeper meanings of usability and affordability, they won’t feel the need to indulge in complex, unnecessary architectures. Instead, they’ll find the challenge in solving these problems well, which naturally curbs the tendency to over-engineer.
In the end, the goal of good engineering is not to create intricate solutions for the sake of complexity but to deliver effective, efficient, and elegant solutions that address real needs. By focusing on simplicity and purpose, engineers can avoid the pitfalls of over-engineering and contribute to building more sustainable and pragmatic systems.
Good engineers simplify complicated problems, not complicate simple ones.