文件命名与文件夹组织的最佳实践与理论依据
命名是最便宜的文档,也是最先被放弃的那一种。一个取得好的名字,能让人不打开文件就猜到内容;一个取得坏的名字,会让整个目录在几个月后变成考古现场——你面对一片 新建文件夹(3)、final_v2、stuff_backup 的残骸,像一个考古学者面对失传已久的符号,已经想不起当初刻下它们的那个自己在想什么。
《易》曰「书不尽言,言不尽意」。命名却反过来,是用极有限的字,替未来的自己留下一个可追索的入口。它不是装饰,是约定——与协作者的约定,与工具链的约定,更多时候是与未来那个健忘的自己的约定。
一、操作层面的最佳实践
1. 字符规范
- 全小写 + 连字符:
user-profile.md。避免大小写混用——macOS 默认大小写不敏感,Linux 大小写敏感,跨平台协作时User.md和user.md会被视为不同文件或同一文件,制造难以察觉的冲突。 - 禁用空格和特殊字符:空格在 shell 里要转义,
&、:、?、#在 URL 里会被解释。文件名最终会被脚本、管道、URL 引用,留下这些字符等于埋雷。 - ASCII 优先:跨平台、跨工具兼容性最好。中文文件名在 git 日志、CI 日志、某些编辑器、部分旧版压缩工具里会出现乱码或无法追踪。
- 短而具体:控制在 50 字符以内。拒绝
stuff.txt、final_v2_really_final_修改版.doc这类自欺欺人的命名。
2. 分隔符的语义化使用
不同的分隔符风格承载不同的约定,同一项目内要统一:
| 风格 | 示例 | 适用场景 |
|---|---|---|
| kebab-case | api-integration.md | 文档、URL、静态资源 |
| snake_case | user_profile.py | Python 模块、数据库字段 |
| camelCase | userProfile | JS/TS 变量、方法 |
| PascalCase | UserProfile | 类名、React 组件 |
3. 日期与版本
- 使用 ISO 8601:
2026-04-17-meeting-notes.md。按字典序排序自动等于按时间排序,这是它的核心价值。 - 不要用
v1、v2、final、new、真的最终版。版本管理交给 git,不要让文件名承担它不擅长的职责。那些在文件名里堆叠版本号的人,多半也不信任自己昨天的判断。
4. 排序控制
- 数字前缀补零:
01-intro.md、02-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.ts、helpers.py、manager.go、handler.java - 好:
date-formatter.ts、csv-parser.py、rate-limiter.go
helper、manager、util 这类词是思维懒惰的信号——因为不知道这个东西是什么,所以起一个什么都可以往里塞的名字。结果就是半年后谁也不敢动它,因为不知道谁在用。一个沉默的 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 Disinformation:
accountList若不是 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/