文件命名与文件夹组织的最佳实践与理论依据

命名是最便宜的文档,也是最先被放弃的那一种。一个取得好的名字,能让人不打开文件就猜到内容;一个取得坏的名字,会让整个目录在几个月后变成考古现场——你面对一片 新建文件夹(3)final_v2stuff_backup 的残骸,像一个考古学者面对失传已久的符号,已经想不起当初刻下它们的那个自己在想什么。

《易》曰「书不尽言,言不尽意」。命名却反过来,是用极有限的字,替未来的自己留下一个可追索的入口。它不是装饰,是约定——与协作者的约定,与工具链的约定,更多时候是与未来那个健忘的自己的约定。

一、操作层面的最佳实践

1. 字符规范

  • 全小写 + 连字符user-profile.md。避免大小写混用——macOS 默认大小写不敏感,Linux 大小写敏感,跨平台协作时 User.mduser.md 会被视为不同文件或同一文件,制造难以察觉的冲突。
  • 禁用空格和特殊字符:空格在 shell 里要转义,&:?# 在 URL 里会被解释。文件名最终会被脚本、管道、URL 引用,留下这些字符等于埋雷。
  • ASCII 优先:跨平台、跨工具兼容性最好。中文文件名在 git 日志、CI 日志、某些编辑器、部分旧版压缩工具里会出现乱码或无法追踪。
  • 短而具体:控制在 50 字符以内。拒绝 stuff.txtfinal_v2_really_final_修改版.doc 这类自欺欺人的命名。

2. 分隔符的语义化使用

不同的分隔符风格承载不同的约定,同一项目内要统一:

风格示例适用场景
kebab-caseapi-integration.md文档、URL、静态资源
snake_caseuser_profile.pyPython 模块、数据库字段
camelCaseuserProfileJS/TS 变量、方法
PascalCaseUserProfile类名、React 组件

3. 日期与版本

  • 使用 ISO 86012026-04-17-meeting-notes.md。按字典序排序自动等于按时间排序,这是它的核心价值。
  • 不要用 v1v2finalnew真的最终版。版本管理交给 git,不要让文件名承担它不擅长的职责。那些在文件名里堆叠版本号的人,多半也不信任自己昨天的判断。

4. 排序控制

  • 数字前缀补零01-intro.md02-setup.md。不补零的代价是到第 10 项时 10-xxx.md 会排到 2-xxx.md 前面——字典序不讲人情。
  • Johnny Decimal 系统10_Projects/20_Library/30_Chronicle/。按区间预留扩展空间,个人知识管理常用。

5. 语义结构

按领域组织,而非按类型。

反模式:

components/
  profile.tsx
  order.tsx
tests/
  profile.test.tsx
  order.test.tsx
styles/
  profile.css
  order.css

好的结构:

user/
  profile.tsx
  profile.test.tsx
  profile.css
order/
  index.tsx
  index.test.tsx

相关文件聚集在一起,修改时不用在三个目录之间来回跳。这是手艺人的工具箱,不是博物馆的陈列柜。

名字描述内容,不描述位置或类型:

  • 反模式:utils.tshelpers.pymanager.gohandler.java
  • 好:date-formatter.tscsv-parser.pyrate-limiter.go

helpermanagerutil 这类词是思维懒惰的信号——因为不知道这个东西是什么,所以起一个什么都可以往里塞的名字。结果就是半年后谁也不敢动它,因为不知道谁在用。一个沉默的 utils.ts,最后往往成为项目里最危险的那间黑屋子。

二、理论依据

命名不只是风格偏好。它背后站着几个不同学科,各自给出了自己的证词。

1. 信息架构:LATCH 原则

罗森菲尔德(Rosenfeld)和莫维尔(Morville)在《Information Architecture》中提出,信息只能按五种方式组织:

  • Location(位置)
  • Alphabet(字母)
  • Time(时间)
  • Category(类别)
  • Hierarchy(层级)

文件命名本质上是在这五个维度上做取舍。日期前缀是 Time,领域目录是 Category,编号前缀是 Alphabet,目录嵌套是 Hierarchy。理解这点后,就不会再纠结「应该用日期还是编号」——那是在问「优化哪个检索维度」,而非风格选择。

2. 认知科学:Miller 定律(7±2)

1956 年米勒(Miller)的经典论文《The Magical Number Seven, Plus or Minus Two》指出,人类短期记忆大约能同时处理 7 个 chunk。目录单层不宜超过 10 项,超过就要分层。这是 Johnny Decimal 系统的生理学基础,也是为什么 src/ 下塞 50 个文件会让人头皮发麻——不是审美问题,是大脑装不下。

3. 软件工程:Clean Code 原则

马丁(Robert Martin)在《Clean Code》中给出几个适用于文件名的原则:

  • Intention-Revealing Names:名字应回答三个问题——它是什么?做什么?怎么用?
  • Avoid DisinformationaccountList 若不是 List 类型就是误导。user-service.ts 里如果不是 service 也是误导。
  • Searchable Names:短到无法 grep 的名字(如单字母 e)是反模式。同理,utils.ts 这种在大项目里可能有几十个同名文件的名字,也很难精确检索。

4. 领域驱动设计:统一语言

埃文斯(Eric Evans)在《Domain-Driven Design》中提出 Ubiquitous Language——代码、文档、文件夹都应使用业务领域的词汇,让结构本身成为文档。

orders/fulfillment/services/module-a/ 信息密度高得多。后者需要打开文件读代码才能理解,前者扫一眼目录结构就能猜到业务流程。好的目录结构,应当像一部体例严谨的史书,读目录就知道大致经纬。

5. Unix 哲学

  • Everything is a file:文件名是 API 的一部分。它会出现在脚本、URL、日志、备份、压缩包里,每一处都是潜在的坑。
  • Write programs that work together:避免空格、特殊字符、非 ASCII,是为了让管道、glob、shell 能够无缝组合。一个带空格的文件名,会让你的 find ... | xargs ... 链条在某个周五晚上崩掉——而通常没有人会在那时读日志。

6. 信息论视角:可预测性与熵

好的命名系统让你不看目录就能猜到路径

  • src/features/auth/login.ts——可预测
  • src/stuff/new-thing-v2.ts——不可预测

可预测性等于低认知负荷,等于高信息熵压缩率。你不需要把每条路径都记在脑子里,因为系统本身是自洽的,可以通过少量规则推导出来。一个好的命名系统是一种压缩算法,用结构替代记忆——而记忆,是人身上最不可靠的那一部分。

三、一句话总结

命名的本质是在精确性、简洁性、可预测性三者间做权衡。精确到能消除歧义,简洁到能快速输入和阅读,可预测到不需要打开就知道里面是什么。

这三者经常冲突:最精确的名字往往冗长,最简洁的名字常常模糊。调和它们的办法是分层——让目录承担上下文(Category),让文件名承担细节(Intention),让排序承担优先级(Alphabet/Time)。每一层各司其职,名字才能又短又清楚。

说到底,命名是一种对抗熵增的努力。文件会在硬盘里堆积,目录会在时间里膨胀,而记忆会褪色。你今天为某个文件多花的十秒钟,是在为明年的自己留一盏灯。写下一个好的名字,近乎一种微小的、不被奖励的诚实——没人会因此表扬你,但几年之后,你会在某个深夜打开一个叫 2023-09-11-auth-migration-rollback.md 的文件,然后由衷地感激当初那个多按了几下键盘的自己。

参考

  • Rosenfeld, L., & Morville, P. Information Architecture for the World Wide Web.
  • Miller, G. A. (1956). The Magical Number Seven, Plus or Minus Two.
  • Martin, R. C. Clean Code.
  • Evans, E. Domain-Driven Design.
  • Johnny Decimal System: https://johnnydecimal.com/