完美并非过度设计
Perfection is not over-engineering

原始链接: https://var0.xyz/posts/perfection-is-not-over-engineering.html

业界常将“完美”与“过度设计”混为一谈,导致开发人员对高标准避之不及。然而,过度设计并非源于追求极致,而是因为试图解决错误的问题。 “完美”的解决方案确实存在,它是明确需求与严苛限制下必然产生的成果。当你深刻理解产品需求时,设计思路便会清晰可见。反之,当团队为不存在的假设性问题(如极端规模化)而进行开发时,就会造成不必要的复杂性和运维负担,这便是过度设计。 归根结底,技术系统也是产品。如果不先定义明确的需求,就不可能构建出正确的解决方案。当目标模糊时,你所有的勤奋开发都只是在为错误的目标服务。通过收集更好的需求并认清现状的特定约束,理想的解决方案便会成为唯一合乎逻辑的选择。完美并非敌人,模糊的需求才是。

这篇 Hacker News 讨论聚焦于“追求软件完美”与“不要让完美成为优秀的敌人”这一常见准则之间的张力。 辩论主要归纳为几个关键观点: * **定义过度设计:** 参与者认为,过度设计不仅仅是“投入过多精力”,更具体地是指“解决错误的问题”,或增加了与用户需求不符的复杂性。许多人指出,微服务的滥用是这种无益复杂性的典型例子。 * **“足够好”的谬误:** 许多用户反驳“不要让完美成为优秀的敌人”这一说法,认为这是一种敷衍的陈词滥调,被用来为交付低质量、难以维护的“面条式代码”辩护。另一些人则认为软件必须“正确”——尤其是在安全性方面,而“足够好”往往会导致技术债务。 * **约束与权衡:** 有人建议,如果能明确定义约束条件,“完美”实际上是可以实现的。然而,许多人指出需求很少是静态的,这使得“完美”成为一个不断移动的目标。 * **交付的现实:** 实用主义者强调 80/20 法则的重要性,指出过度关注边缘情况会导致进度停滞;而其他人则强调,“优秀”是相对于项目的长期业务目标而言的。
相关文章

原文

"We don't want to do perfect." "We don't want to build the perfect solution." I've heard versions of that line more times than I can count, delivered as if "perfect" were a dirty word. And I understand the caution — over-engineering burns teams, and people have learned to treat anything that smells like perfection as the same risk.

It isn't. The industry has quietly conflated the two.

Over-engineering is solving the wrong problem. That's the whole definition. Not "caring too much." Not "making it too good." Solving the wrong problem. Often with good intentions, and almost always with a growing pile of incidental complexity.

There is a perfect solution

I believe a perfect solution exists. With one big caveat: you need a very clear set of requirements. Every constraint on the table. Tighten those enough and something interesting happens, you end up with only one possible solution. And that solution is, somewhat ironically, the perfect one. It's perfect because it's the only one that fits.

Start a new project. Every language, every tool, every hosting model available. You pick serverless. Python is a strong choice: no compilation step, upload your files to Lambda, ship. For someone else it's the wrong choice, they don't know Python, or they need to optimize for a different set of requirements, such as performance. Different constraints, different answer. Same problem space, different "perfect."

Or you chose Python and you're building a web app. Django or Flask? You can reach similar results with both. They're still different tools with completely different philosophies. Which one wins? It depends. Set clearer requirements, set stricter constraints, and the solution follows. That solution is the perfect one for you, for that case.

Systems are products

When a system is over-engineered, the cause is almost always requirements. And I mean requirements in the product sense, not just the technical one.

A library, an API, an internal tool... we like to pretend these are "purely technical," that they somehow sit outside the idea of a product. They don't. You have users. Those users have needs. You need to understand those needs well enough to address them properly.

Maybe what they need is a service. Or maybe it's better served by a library than by an HTTP call. Instead of handing them an API, maybe you hand them a package. The shape of the solution only becomes obvious once you treat the system as a product and define the requirements honestly. Then the solution follows.

How you can tell

The clearest tell that something is over-engineered: you start asking why are things built the way they are? and the answers don't hold.

Classic example. A team of three people maintains five microservices. The services share data among each other. Is it over-engineered? Figure out which problem they were trying to solve. Most likely you'll conclude they were solving the wrong ones (or several of them at once).

Look at what the split actually costs. What used to be a hard reference in a database, a foreign key the engine enforces for you, is now a loose string id sitting in a field. Data integrity is gone. One service can delete a record and the other has no idea; it just keeps a dangling reference and finds out later, the hard way. Why all this ceremony between services when it's all part of the same domain? Why give up those integrity checks?

What did you gain in exchange? Usually: not as much as you lost. Independent deploys, sure, but was that a problem you actually had? Three people, one domain. You solved for a scaling and ownership problem that wasn't on the table, and paid for it with distributed inconsistency, operational overhead, and a system that solves multiple problems partially, none of them completely, while introducing a bunch of problems you wouldn't have had otherwise.

That's the signature. Not elegance. Not thoroughness. And it's not that these solutions are bad, usually they're the correct answer to the problems that were proposed. The problem is that those were problems you never had.

Gather the right requirements

So the diagnosis is simple, even if the work isn't. Over-engineering is a failure of requirements gathering. Call it product engineering if you want. It's the consequence of collecting the wrong requirements, and then engineering diligently against them.

Perfection was never the enemy. Ambiguous requirements were. Get those right, get every constraint on the table, and the perfect solution stops being a fantasy. It becomes the only thing left standing.


I made a video version of this argument, if you'd rather watch it: Perfection is not over-engineering.

Thanks for reading.

联系我们 contact @ memedata.com