一次失控项目的目录整理复盘
这次整理面对的是一个在长期探索式开发中逐步生长起来的工作区。年前赶进度的那段时间,所有精力都花在功能推进上,新的实验不断往里加,旧的尝试没空清理,文档、数据、中间产物随手放在离代码最近的地方——"先跑通再说"。当时这样做是合理的,毕竟时间紧迫,整理是可以推迟的事。
但过完年再打开这个项目时,情况就不一样了。一个月的间隔足以让人忘掉大部分上下文:哪些目录是正在用的,哪些是废弃的尝试?这个文件为什么放在这里?那个脚本到底是主线的一部分还是某次调试的临时产物?目录结构已经从"反映当前项目边界"退化为"记录历史开发过程",打开项目看到的是一座小型屎山的横截面。面对这样的项目,过重的认知负担让人不知道从哪里下铲子,心里甚至产生了一种畏惧感。
现有结构已经开始拖慢实际工作,甚至阻碍了继续投入的意愿。这正是启动整理的直接原因。
整理过程
第一步:识别边界,而非急于搬迁
整理的起点是先弄清楚当前工作区里到底有几类东西、它们之间是什么关系。
在动手之前,先对所有内容做了一轮语义分类:哪些是正在开发的主线,哪些是曾经的实验但已经停止推进,哪些是辅助工具、哪些是数据源、哪些是生成出来的中间产物。这一步花了不少时间,但它决定了后续所有搬迁操作的方向,避免了反复挪动。
第二步:把"混合总仓"拆成独立项目
原来所有内容共用一个 Git 仓库,什么都往里扔,日积月累就成了一锅乱炖。一个工具的提交记录和主线研究的提交记录混在一起,不仅看不清历史脉络,也给回溯带来障碍。
拆分的原则很简单:如果两个东西的生命周期不一样、维护频率不一样、关心它们的人不一样,这次就不再让它们共用一个仓库。拆分时,旧仓库的 .git 目录被重命名保留而非删除,确保历史可追溯。每个新项目各自初始化独立的 Git 仓库,拥有自己的版本历史和忽略规则,互不干扰。
第三步:在主项目内部建立层级
仅仅拆分项目还不够,主项目内部同样需要分层。主线实现、实验性实现、已经冻结的旧实现、原始数据、说明文档被分别放到不同的位置,并且为每一层制定了明确的定位。
其中最有价值的一个区分是对实验内容的三级划分:仍在推进的、需要兼容保留的、已经冻结归档的。这种分类让人一眼就能判断某个目录的状态,不需要打开文件去阅读才能知道"这东西还活着吗"。
第四步:分离"人维护的"和"机器生成的"
在整理之前,手工编写的数据、自动生成的中间产物、运行输出的结果文件混放在一起。这带来两个问题:一是很难判断哪些文件需要手动维护、哪些可以重新生成;二是 Git 的提交历史中充斥着大量无意义的变更记录,真正重要的改动反而被淹没。
解决方案是建立清晰的流向:人维护的原始数据放在固定的位置,通过明确的转换步骤生成运行所需的配置文件,而运行结果则通过 .gitignore 排除在版本控制之外。这样,仓库里保存的始终是"源",而不是"果"。配合精心设计的忽略规则,少量需要长期保留的参考结果仍然可以被显式地纳入追踪,不会被一刀切地排除。
第五步:为归档内容设立标准
对于那些已经不再开发但仍有参考价值的旧实现,归档标准是明确的:归档内容必须能够独立运行,不依赖主线中随时可能变化的部分;必须有自己的入口说明和必要的参考结果。这样即使过了很长时间,想回头验证某个旧方案时也不需要考古式地拼凑运行环境。
收获的经验
整理不需要一步到位。 这次整理结束后仍有一些未完全收口的部分。重要的是建立起足够清晰的框架,让后续的收口工作可以在已有框架内渐进完成,而不是再来一次大规模重组。
记录整理本身。 整理过程中做了什么决策、为什么这样分、哪些事情还没做完——这些信息如果不记录下来,几周后就会遗忘,然后要么重复劳动,要么困惑于当初为什么这样做。整理工作的文档化和整理本身一样重要。
善用AI工具处理高密度的结构性工作。 这次整理全程借助AI编程助手完成,总共只花了两三个小时。项目整理这类工作的特点是:判断标准清晰但操作步骤繁琐——需要逐个检查文件归属、修改引用路径、调整忽略规则、补写说明文档。人负责制定分类标准和做关键决策,AI负责执行大量重复性的搬迁、检查和文档生成。这种分工让整理工作从"大半天的苦力活"变成了"两三个小时的协作流程",也大大降低了启动整理的心理门槛。
回头看,年前没有及时整理并不是错误——那时候赶进度是对的。但过了一个月再回来时产生的畏惧感提醒我:推迟整理是有利息的,间隔越长,认知负担的利息越高。屎山不是一天堆成的,但放着不管,它真的会越长越高。下一次,也许不必等到已经感到畏惧才开始。