The Enemies of Excellent Engineering 卓越工程之敌

The Enemies of Excellent Engineering: Evil Reuse, Abused Defaults, Silent Failures, Fake Refactoring

卓越工程之敌:邪恶复用,滥用默认,静音失败,虚假重构 (中文版请跳至文末)

a_fumo_is_reading_deep_understanding_of_computer_systems

I’ve written a lot of Python across my current and former companies—everything from distributed ML to financial business logic—from beautifully maintained “god-tier” code to mountainous piles of tech debt (some of which I built myself). Along the way, a few reflections feel worth recording and sharing. Avoiding these simple yet slightly counter-intuitive mistakes can push ordinary engineering toward excellence and make projects easier to maintain as they grow.

1) Evil Reuse

Wrongheaded reuse is “evil”—it only multiplies branches and options until maintenance collapses. Two pieces of code may look identical at first, but as requirements evolve, they inevitably diverge. If you force them to share one function, that function’s branches will keep ballooning until it becomes unreadable. The maintenance cost will outweigh the time you “saved” at the start. Don’t obsess over eliminating incidental duplication; allow it to exist so each copy can evolve with its own requirement trajectory—eventually the duplication will disappear naturally. This paradox in architecture—reuse as beauty vs. reuse as evil—is discussed in The Paradox of Reuse in Architecture and was one of my favorite reads in 2024.

“Two pieces of code may be very similar or even identical, yet they will change for different reasons—we call this ‘accidental duplication.’ Accidental duplication should not be forcibly removed. Let them evolve separately and the duplication will disappear.” — Robert C. Martin, Clean Craftsmanship

2) Abusing Default Parameters

Most default parameters are born from “I want to add an argument but don’t want to change other people’s call sites.” The best time to eliminate this side effect is exactly when you add the parameter—none of the existing callers depend on it yet, so you can review them and fill the argument explicitly. Even if functionality doesn’t change in that moment, this makes every call site consciously acknowledge the new parameter. Future maintainers are more likely to notice and account for it.

If you hide the change behind a default, the signal disappears—until one day a production incident forces a painful debug session. The cost will dwarf the time saved by adding a default. Use defaults sparingly; prefer updating all call sites explicitly.

The only exception is user-facing backward compatibility (developer-facing doesn’t count): the function is a public API, you follow semantic versioning, and you document the parameter thoroughly. If any of these three is missing, don’t add a default lightly.

debugging_for_5_hours_can_save_your_5_minutes_of_reading_documentation

3) Silent Failures

If an input is invalid, fail fast the moment you detect it—panic loudly. Some people sprinkle “fallbacks” to keep legacy code working. In doing so, they waste the best chance to retire legacy paths and plant countless traps for future readers. In weakly typed languages like Python, future maintainers can’t infer value constraints from types alone.

A right error beats a wrong success—at least you see it and can fix it. If you truly must fallback, gate it behind a switchable mechanism like a STRICT_MODE env var. CRASH LOUD—if you’re going to crash, make it obvious.

Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. — The Zen of Python

4) Effective vs. Fake Refactoring

Effective refactoring is grounded in deep understanding of requirements. Don’t design or refactor without it. Good refactoring separates core from non-core, essence from accident—and then truly splits them apart. Afterward, the boundary between important and unimportant should be crisper.

Fake refactoring is like zoning a “poop mountain” into tidy districts: you can write nice docs and abstractions, but without prioritizing what matters, nothing essential changes. The same goes for pattern-level refactors—switching from “object small talk” to Visitor, adding a Chain of Responsibility, etc. If it isn’t driven by requirements, it’s probably fake.

“God, grant me the serenity to accept the things I cannot change, courage to change the things I can, and wisdom to know the difference.” — Serenity Prayer


In my view, the gap between excellent engineering and garbage engineering is just one perspective shift: settle the full account—evaluate software through the lens of shifting requirements and the entire lifecycle.

Excellent engineering gets easier to write over time: even as features multiply, maintainability improves.

“Settling the full account” means thinking in lifecycle terms. When technical debt emerges (say, a growing pile of messy code), time pressure may prevent immediate cleanup, but at least recognize the debt clearly and manage it deliberately.

And “readability” isn’t just naming conventions or thorough documentation. It means you can confidently predict a function’s behavior by reading it—without running it—ultimately yielding maintainability. You can write perfect docs, but if readability doesn’t produce maintainability, its value approaches zero. When someone opens the code, odds are they’ll have to modify it. As for how to raise true readability in Python—I think I’ve got a few new ideas…

I_ve_suffered_enought_10_years_engineering

卓越工程之敌:邪恶复用,滥用默认,静音失败,虚假重构

在东家、前东家、前前东家、前前前东家写了不少 Python 代码,各种类型的都有,从分布式机器学习到金融业务逻辑,从维护良好的神代码到超级屎山,写过不少让同事和同学都无语的程序,也亲手堆起过一些“屎山”。一路走来,有些反思值得记下,也与你分享。避免这些简单但有点反直觉的错误,能让你的普通工程向卓越工程迈进,项目越写越好维护。

邪恶复用

错误的复用是“邪恶”的——它只会不断增加分支和选项,让代码越来越难维护。也许两段代码最初看起来一模一样,但随着需求演化,它们终将走向不同的方向。如果复用一套函数,函数里的分支只会越来越多,直到彻底丧失可读性。这些维护成本最终会超过当初节省的那点时间。不强求代码的意外重复清除,允许代码重复,他们随着需求各自演化,重复自然消除。 此事在 架构设计的悖论,复用是美好的还是邪恶的 亦有记载,这也是2024 年我最喜欢的文章之一。

“两段代码可能非常相似甚至完全一样,但它们会因为不同的原因而改变——我们称之为‘意外重复’。意外重复不该被强行消除。允许它们各自演化,重复自然会被消除。” —— Robert C. Martin 《Clean Craftsmanship》

滥用默认参数

大多数默认参数的产生,都是因为“我想加个参数,但不想改别人的调用”。而消除这种“副作用”的最佳时机,恰恰就是新增参数的时候——这时所有先前调用都不依赖这个参数,你可以逐一Review并显式地填写。在此刻,或许功能上没有区别,但是随着软件的演化,这将提醒每处调用的维护者:这里有了一项新的参数。软件的其他维护者在编写新功能时,更容易注意到并考虑这处新参数。如果直接使用默认参数,这个改动将被隐藏,直到某次线上事故时再花时间慢慢调试。这里的成本远超当初使用默认参数节省的时间。慎用默认参数,尽量手动修改所有的调用。

唯一例外是面向用户的向后兼容 (面向开发者的不算):这个函数是面向用户的 API,并且你遵循语义化版本(semantic versioning),并且详细记录了参数含义。三者缺一,就别轻易用默认参数。

debugging_for_5_hours_can_save_your_5_minutes_of_reading_documentation

静音失败

如果输入参数有误,请在发现错误的那一刻直接 panic。有人喜欢在代码里做“fall back”,目的为了兼容老代码。这样做,却错失了淘汰 legacy 的最佳时机,还给后来人埋下无数坑。尤其是像 Python 这类弱类型语言,后来人无法通过代码实现推断输入的性质。一个正确的错误好于错误的正确,因为我们至少知道他的存在,并且有机会修改它。如果因为各种原因,不得不 fall back,至少加一个能关闭它的环境变量,比如 STRICT_MODE。CRASH LOUD——要崩溃,就哭大声点。

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

即使实用比纯粹更优,错误绝不能悄悄忽略,除非它明确需要如此。

——Python 之禅

虚假重构

有效的重构 vs 虚假的重构。有效的重构建立在对需求的深刻理解之上,没有理解需求就不要轻易设计和重构。有效的重构能够区分核心与非核心、本质与非本质的代码,然后把它们彻底分离。有效重构之后,重要与不重要的界限会越来越清晰。虚假的重构,就像给屎山划分“功能区”,或许我们可以写出详细的文档,不错的函数抽象,但如果缺少对于重要与非重要的思考与分离,前后没有本质区别。我们并没有将问题简化。那些技术层面的重构也一样——把 object small talk 换成 visitor pattern、引入责任链……如果不是从需求出发,那大概率也只是虚假的重构。

主啊,请赐予我平静,去接受我无法改变的;赐我勇气,去改变我能改变的;赐我智慧,分辨这两者的区别。——宁静祷文

最后

在我看来,卓越工程和垃圾工程之间,其实只差一个视角:算总账,用需求不断变化的视角看待软件,着眼于软件整个生命周期。

卓越工程会越写越轻松,尽管功能变多,代码却越来越好维护。

“算总账”,着眼于软件的整个生命周期。当技术债出现时(比如屎山形成),也许迫于时间压力不能立刻清理,但至少能清醒地意识到债务的存在,并且有方法地管理它。

而“可读性”也不只是变量名称的格式,也不仅仅意味着文档的详实程度。它意味着仅凭阅读代码而不实际运行,就能自信地预测函数的行为,最终带来可维护性。我们可以尽管将文档写得完美,但如果代码可读性不能带来可维护性,那代码的可读性接近于为零,有人开始读代码时,便大概率需要修改他了。如何提升Python代码的真可读性,我似乎又有了一些思考…

I_ve_suffered_enought_10_years_engineering




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • The Paradox of Software Architecture 架构设计的悖论
  • All Watched Over by Machines of Loving Grace