Our Engineering Principles: How We Decide What NOT to Build
Direct answer: Our engineering principles start with what NOT to build — because the projects that nearly killed teams we've worked with weren't killed by bad code; they were killed by building things that shouldn't have been built at all, or built now.
At MarginTop Solutions, saying no is one of the highest-leverage decisions an engineering team makes. Here's the operating system we use to make it.
Why "what not to build" matters more than "what to build"
Fred Brooks' The Mythical Man-Month (1975) identified a pattern that's still true fifty years later: software projects fail less often from building the wrong thing the wrong way, and more often from building the right thing at the wrong time or scope. The classic software project failure mode isn't "we made a technical mistake." It's "we built 18 months of features before discovering the core value proposition was wrong" or "we built a scalable platform for 1,000 concurrent users when we had 20."
The same principle in modern form: a 2021 McKinsey analysis of software project outcomes found that 17% of large IT projects go so badly that they threaten the company's existence — not because of poor execution, but because scope was never controlled. The projects that succeed are the ones where someone with authority said "not this, not now" repeatedly.
The principles we actually use
1. Build for the problem you have, not the problem you imagine
The most expensive software we've seen was built to "scale to 10 million users" when the company had 200 active ones and no acquisition plan. Premature scale infrastructure costs 3–5× what infrastructure-for-now costs, delivers zero additional value until the scale arrives, and introduces complexity that slows down the feature work that would actually attract those users.
Our test: "If we had 10× the users tomorrow, which specific bottleneck would break first, and is that the problem we're solving today?" Usually the answer is "the database query on the dashboard" not "our inability to shard across five regions."
2. Commodity problems get commodity solutions
We've written about this in depth in the build vs buy framework, but the short version: if the problem is solved well by an existing SaaS or open-source package, the decision to build it custom is a tax on your engineering budget that rarely delivers unique value.
Examples of things we see teams build that they should buy: authentication systems, payment state machines, email delivery infrastructure, admin dashboards, feature flag systems, and internal analytics tooling. Each of these is genuinely hard to build correctly. None of them is a competitive differentiator for a product company.
3. Premature abstraction is the enemy of clear code
The YAGNI principle (“You Aren't Gonna Need It”) is nearly 30 years old and still regularly violated. We see it most often in the form of "generalized plugin architectures" built before there are two concrete use cases to generalize from, or "event-sourcing infrastructure" added before the team understands which events they care about.
Our rule: abstract when the third concrete case arrives and the pattern is obvious. Not before. The first two cases teach you what the abstraction should look like. Building the abstraction on the first case usually means rewriting it after the second.
4. Every new dependency is a long-term commitment
Adding a package or service to a production system means implicitly committing to: tracking its security advisories, keeping it updated, understanding its failure modes, and migrating away from it if it's abandoned. We evaluate dependencies by asking: "Are we prepared to own this relationship for three years?"
This doesn't mean avoiding dependencies — it means being honest about the ongoing cost. A well-maintained package with 10,000 GitHub stars and active releases is a different commitment from a two-year-old package with one maintainer who hasn't merged a PR in six months.
5. The feature nobody asked for twice isn't a priority
One request is a data point. Two independent requests is a pattern. Zero repeat asks after shipping a feature is a signal to stop investing in it. We track feature request recurrence explicitly — not just volume — because a loud minority can drive engineering priority in directions that don't serve the majority of users.
Concrete examples of what we said no to
| What was proposed | Why we said no | What we did instead |
|---|---|---|
| Custom auth system with "more flexibility than Sanctum" | Flexibility not needed; maintenance tax high; security surface unjustifiable | Sanctum + custom permission logic in domain code |
| Microservices architecture for a 3-person team's product | Distributed ops overhead would consume 1 FTE before product had signal | Modular monolith with explicit domain boundaries |
| Real-time analytics dashboard in month 2 of MVP | No users to analyze yet; would distract from acquisition features | Plausible — deferred until 500 active users |
| Internal "developer platform" with its own API gateway | 1 developer using it; platform complexity exceeded product complexity | Deleted it. Used the time on product features. |
How to actually say no (without becoming a blocker)
The skill isn't just deciding what not to build — it's communicating that decision without shutting down the conversation. A "no" that kills the discussion creates workarounds. A "no with clarity" creates better proposals.
Our format: "Not this, because [specific reason]. Here's what we'd need to see before reconsidering [clear criteria]. Here's what we can do instead that addresses the underlying need [alternative]."
That structure keeps engineers and stakeholders oriented toward outcomes rather than arguments about specific implementations. Related: cutting scope in the open.
Key takeaways
- The highest-leverage engineering decisions are often "don't build this" — McKinsey data suggests scope control is the primary differentiator between successful and failed large software projects.
- Build for the problem you have; abstract after the third concrete case; every dependency is a 3-year commitment.
- Commodity problems get commodity solutions. Build custom only where the capability is a genuine differentiator.
- Say no with specificity: reason, criteria for reconsideration, and an alternative that addresses the underlying need.
Want help thinking through what your engineering team should and shouldn't be building? Get in touch — this is one of the most valuable conversations we have in early engagements.