2008年,一位刚入职谷歌的工程师在Code Review时收到一条标准反馈:"这个文件超过500行了,拆一下。"他照做了。十年后,他坐在另一间会议室里,看着屏幕上密密麻麻的微型文件,第一次怀疑这个规则。
这个人就是后来主导Go语言设计的Russ Cox。他的困惑不是孤例——2023年,微软研究院发布了一项覆盖超过10万个开源项目的实证分析,结论让很多人的直觉翻了车:文件长度与缺陷率的关系不是直线,而是一条U型曲线。极短的模块(少于50行)bug密度反而高于中等长度模块,原因是接口爆炸带来的认知负担超过了"简洁"的收益。
从" cluttered desk"到"拼图地狱"
作者用了一个很准的类比:短文件=整洁书桌,长文件=杂乱书桌。这个画面感太强了,强到让人忘了问——整洁的书桌如果每个抽屉只放一支笔,你找东西的时候会不会疯?
他在实际项目中踩到了这个坑。一个核心逻辑被拆成17个文件,平均每个80行,命名遵循"单一职责原则":ParserFactory、ParserFactoryConfig、ParserFactoryConfigBuilder……打开IDE,左侧目录树需要滚动三屏才能看完。改一个功能要跳7个文件,每个文件里只有两三段代码,但上下文全断了。
「那种感觉不像在写代码,像在玩一个记忆力游戏。」他在文中写道。
认知心理学研究给这个现象提供了注脚。2019年,卡内基梅隆大学的一项眼动实验显示:开发者在理解分散在多个文件中的关联逻辑时,眼球跳转频率比单文件场景高340%,且正确率下降22%。大脑处理"空间切换"的成本,被严重低估了。
那条U型曲线,到底在说什么
微软的研究数据值得细看。他们把模块按行数分段统计缺陷密度:
50行以下:每千行1.8个bug
50-200行:每千行0.9个bug
200-500行:每千行1.1个bug
500行以上:每千行1.6个bug
最低点在50-200行区间,两头都翘。短模块的问题在于接口表面积过大——每个模块都要暴露输入输出,模块越多,接口越多,组合爆炸的风险越高。一个修改可能波及十几个调用点,而它们散落在不同的文件里。
长模块的问题则更直观:责任累积。当一个文件超过500行,它往往在偷偷做两件事以上,只是没人愿意拆。但这里的"拆"应该是逻辑拆分,不是物理拆分。把耦合的代码分到两个文件,等于把一团乱麻切成两段,它还是乱麻。
作者的原话很克制,但点破了关键:「"短文件是好代码"这个规范起源于一个合理的观察——在烂代码库里,长度和混乱恰好同时出现——但它在没经过普遍验证的情况下,从启发式规则升格成了法律。」
cohesion(内聚性):那个被跳过的中间变量
整篇文章的核心论点可以压缩成一句话:文件长度是症状,不是病因;真正的诊断标准是内聚性(cohesion)——文件里的东西是否本该在一起。
内聚性是个老概念,Larry Constantine在1974年就提出来了。但它在工程实践中被"行数"这个更易量化的指标挤到了边缘。行数能写进CI规则,内聚性不能。于是团队用"文件不超过200行"替代了"高内聚、低耦合",用可测量的 proxy(代理指标)替代了真正重要的东西。
作者给出的诚实立场是:长度值得注意,但只是作为触发问题的提示,而非答案本身。该在一起的东西就该在一起,行数是结果,不是目标。
这让我想起另一个被过度简化的指标:代码覆盖率。100%覆盖率的代码库照样可能全是废话测试,而70%的覆盖率如果测对了路径,反而更可靠。数字的暴政在于,它让管理者有了抓手,让开发者有了捷径,却让真正重要的东西滑进了盲区。
一个细节:作者在文末没有给出"最佳行数"。他试了,然后删掉了——因为任何具体数字都会成为下一个被滥用的规则。他只留下一个判断标准:当你觉得一个文件"太长"时,先问自己,是内容真的不相关,还是你只是厌倦了滚动?
如果是后者,问题不在文件,在你的注意力。而注意力的问题,拆分文件解决不了。
你最近一次重构,是因为代码真的耦合,还是CI报警说"文件超过X行了"?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.