昨晚十一点半,我打开一个三个月没碰的仓库,准备给它加登录。
为什么要加?说不清。就是打开 Cursor 的 chat,敲了一行 add user accounts and cross-device sync,回车,看它吐 diff。diff 很长,写得挺像回事——文件建得整整齐齐,schema 看着都对。
我盯了一分钟。Ctrl+C。
画外音:一个我每周自己用两次、只干一件事的小工具,正被它的作者亲手推进"需要长期维护的软件"这个坑里,理由是"顺手就做了"。
这个月早些时候刷 dev.to,看到一个叫 Jessica Doering 的发帖,问的就是这个——一个项目什么时候算真正做完,"完成""放弃""搁置"是不是三件事。帖子下面 12 条评论。我本来打算划过去的。
有一条把我钉住了。大意是:如果一个新功能需要数据库,它可能已经属于另一个项目了。
(原话我记不清了,就记个意思。)
我对着这句话坐了很久。它好在哪?它不问你"该不该做",它问的是"这笔账是不是已经变了"。账号、持久化、用户数据,这三样一进来,你签的就不是一张功能票,是一张值班合同。合同上白纸黑字写着:以后这东西坏了,你半夜得起来。它爆了,你在别人面前背锅。
跟具体功能没关系。加个导出按钮,量变。加个登录,质变。
还有一条更狠,来自 build996,大意是:判断下一项改动是为了工具本身,还是为了想象中的用户。修一个自己真撞上的 bug,属于前者;因为"别人可能想要"而加账号,属于后者。
这条比数据库测试难执行得多,也准得多。
因为"想象中的用户"现在是最便宜的东西。
我让 Claude Code 三十秒生成过一份"用户可能会想要的功能"清单——格式漂亮,优先级排好,每条还带理由和实现难度估计。它看上去像需求。实际上是我的模型在替我做梦。
这半年我最警惕的不是它把代码写错。写错有测试兜着,最坏多跑两遍。我最警惕的是它把我脑子里一个"也许",整理成一份带编号的路线图。文档一旦有了编号,就开始对我产生权威感——我会觉得不做点什么,对不起这份排得这么整齐的东西。
这周期的实习生特别擅长这个:把"也许"润色成"计划",把"顺手"包装成"里程碑"。
以前拦着我的是摩擦力。想想加账号意味着什么:schema 迁移、密码哈希、邮箱验证、忘记密码流程、用户数据丢了怎么办,还有一堆我根本没认真想过的边界情况。这一串干完,一天没了。一天的成本,足够让大部分"也许有人想要"自然死掉。
现在这条链路被压成了一句 prompt。摩擦力消失了,接替它的只剩你自己的判断力——而判断力这东西,没法外包。
写到这儿我得推翻一下自己前面那句话。我前面说"停下的成本变高了",不准确。停止的成本从来没变过,它一直是"承认这东西就到这儿了"。变的是继续的成本,它跌到接近零。
以前有个东西替我按停止键,那个键叫"太贵了"。现在没人按了,键被工具本身拿走,剩下的只有你自己手动去按。
所以"什么时候算做完"这个问题最近被很多人问起,原因不在方法论,在成本结构。当"再多做一个功能"的价钱从一天变成一句话,唯一还拦着你的就是判断。
我的做法很土。现在每个项目,README 最上面一行写死一个状态:
# log-to-table
STATUS: done (last real change: 2026-06)
四个词里选一个:done / active / parked / dead。不许留空,不许写 WIP。
这行字不是给别人看的,是给我自己看的——省得三个月后再打开它时,还要重新判断一次"这算什么东西"。每次实质改动之后重写一遍。五秒钟的事。
抄来的,抄得理直气壮。build996 说把"这是完成,不是遗弃"写进 README,免得沉默被别人当成疏忽。我看到的时候想的是:这条对我最大的价值不是对外沟通,是对内。
一个仓库挂着 WIP,它在我脑子里就有一个常驻进程,隔三差五吃一点内存。
我干过一件很蠢的事:一个早就该宣布死掉的小工具,我让它挂着"未完成"的状态,挂了很久。后来突然有人提了个 issue,我花了一整个周末把它修好,然后——然后再也没打开过。修它那两天不算浪费,真正的浪费是前面那些日子里,它一直以"未完成"的身份占着我一个位置。这笔成本不进任何一张账单,但它每天都在扣。
另外一个我抄来的东西是"功能停车场"。Christoph 在那条帖子里说的,大意是拿一张清单专门收留那些非核心的新想法,让脑子安静下来,别打断现在手上的事。
我改了改:新开一个 PARKED.md,一行一个想法,不许写理由。加了理由,它就变成需求了;需求是有重量的,一行字的想法可以躺着不管。
- 导出成 CSV
- 加个 CLI 参数
- 支持 .gz 输入
这三条在我那个仓库里躺了三个月,没有一条让我损失什么。
Jessica 在回复里承认,她常常在建前三个功能的时候想到十个新功能。这我也一样,而且我怀疑这是所有自己捣鼓东西的人的默认状态。区别只在于你想出来的那十个,最后变成十条 parked 记录,还是变成十张 issue 和一份路线图。
扯远了,回正题。
评论区有人问,是不是大家都有一个装满未完成项目的坟场。我的回答可能不太合群:有坟场很正常,我也不打算去清理它。
真正的区别不在坟场的规模,在你有没有能力给每一座坟立一块碑。挂着 WIP 不动的,是债;写着 dead 或者 done 的,是记录。同一份代码,一行都没改,两种状态。
我对"每个项目都必须做完"没什么执念。我做的小工具里有一半是三天热度——学到想学的东西,拿到想要的功能,然后停在那儿。这没有任何问题。有问题的是那些停在那儿、还假装在生长的东西。它们会一直朝你要东西,而你其实早就不想给了。
顺便说一句我挺烦的东西:那种"项目生命周期管理最佳实践"清单。什么阶段做什么事,什么情况下该归档,什么情况下该开源——脱离具体项目上下文,这些清单九成是正确的废话,剩下那一成是让人把时间花在给项目分类上,而不是花在项目本身。我宁愿用那四个词,土但能执行。
这里要说清楚一点,免得被误读成"所有项目都别长大"。项目该长的时候得长,我自己也有从一个小工具长成正经东西的项目。分界线在于:这个功能是我想加的,还是我在替一个想象中的人加的。前者是你在做你想做的东西;后者是你在上班,而且还没工资。
这条线只有你自己能划。工具不会替你划——它只会非常配合地实现你选定的任何一个方向,包括你根本没想清楚的那个。
所以给自己立的那条规则,一句话:新建仓库的第一件事,不是写 README 的标题,是在第一行写死那四个状态里的一个,每次实质改动之后重写。成本五秒钟,能替我干掉脑子里一半的常驻进程。
至于那些已经躺了三个月、状态栏还空着的仓库——老实说,我到现在也没想好其中一个该叫 done 还是 dead。这周挑一个出来,强行写上去。写上去那一刻大概会有点肉疼,就当缴一次智商税了 😅。
