把代码删光之后,证据反而更硬了
上游维护者说「这个 PR 只做合并」。覆盖没了,那个子类就什么都不重写了——于是整个导入器删掉。剩下的 PR 里一行生产代码都没有,而它的证据比之前更强。
八月二十四号往 NeoDB 提的那个 PR,核心是一个
DoubakImporter:继承他们自己的 NdjsonImporter,
只覆盖一个方法,为的是多一个「覆盖」模式。
理由是豆瓣特有的:豆瓣给一条标记盖的是「标记那天」,之后你改短评、改评分,
那个时间都不动。所以一个本来就在 NeoDB 上手动标记的人导入自己的豆瓣档案,
所有重叠的记录都会被跳过——本地那一行永远显得更新。
维护者先问了一句「为什么要加一个新导入器」,然后拍板:
let's make this PR for Merge only. Overwrite can be added later if users actually need it.
这两句合起来,答案就不是「把覆盖去掉」,而是把整个子类去掉。
NdjsonImporter 里所有「已有记录更新、跳过」的判断都走同一个方法,
子类覆盖的就是那一个——不做覆盖,它一个字都没重写。于是
doubak.py、两个数据库迁移、一个视图、一条 URL、一个上传表单,
全部删掉。
删完之后,证据反而变强了
这是我没预料到的部分。旧的 PR 描述里有一条必须写的注意事项:
那两次真实导入(40 条那份和全量 17305 条那份)走的都是现有的
NdjsonImporter,所以它们能证明的只是格式对,证明不了这个 PR。
把子类删掉之后,这句话没有了。因为现在这个 PR 记录的就是那条路径: 被验证过的东西和被交出去的东西,成了同一个东西。
可信度并非靠堆砌代码来增强。 它变强,源于「实际验证的路径」与「最终交付的路径」完全一致。 一旦两者出现偏差,中间的信任缺口就只能依赖阅读者自行弥合,而这往往并不可靠。
顺手撞上的一件事:进度是挂在类上的
放弃这个子类之前,我想留一样东西:数据页上单独一块进度显示。 导入几千条要很久,我希望用户能看见「豆瓣档案导到哪了」, 而不是跟别人的 NeoDB 备份混在同一个格子里。
查下来是不行的,原因很干脆: 进度挂在任务的「类型」上,而类型是从类本身推出来的。 「取这个用户最近一个任务」是按这个类型过滤的,前端轮询的那个网址也是拿这个类型拼出来的。 所以同一个类的两个区块,问的是同一个网址,拿回来的是同一个答案。
要硬造出两个区,就得去改所有导入器共用的状态模板和视图—— 波及面比刚刚被否掉的那个子类还大,换来的只是把一个队列拆成两个框。 何况那一页现在是反着来的:CSV 和 NDJSON 两种导入器合用一个状态区。 同一个类,本来就只有一个队列。
想知道界面上两样东西能不能分开,先看它们的状态挂在什么上。 挂在类上的东西,不换类就分不开——这跟界面怎么写没关系。
那 PR 里还剩什么
一块路牌。缺的从来不是代码——豆备产出的本来就是 NeoDB 自己的归档格式, 他们现有的表单一直就收得下,上面那两次真实导入走的就是它。 缺的是那一页上没有任何一句话这么说。
而且默认的猜法恰好是错的:一个拿着豆瓣档案的人,会去点那一节写着
「从豆瓣导入标记和评论」的——那一节收的是豆伴(Doufen)的 .xlsx,
把这个 zip 传上去只会被拒。看起来像「豆备的导出坏了」。
所以现在两边互相指:豆瓣那一节说明豆备的档案是 NDJSON、并链到下面的 「导入 NeoDB 备份」,那一节也加一句确认。 怎么用那一页、以及导出包里的《怎么导入》,都补上了同一句。
那些测试也删了,而且大半本来就是重复的
同一天维护者又回了一句:把测试也去掉,大部分是重复的;顺便把只改了行号的
翻译回退。第二件是纯事实——那 142 行变动的引用注释,
把 :行号 去掉之后两边完全相同,只差属于两条新字符串的 4 条。
第一件我先去核了再动手。
核下来他是对的:23 条里有 14 条在
test_ndjson.py 里已经被断言过。收藏单条目备注、私密可见性、
独立日记转 Article、笔记去重、未知记录类型的计数、未改动的重复导入、
缺 published、上传校验里的 4 条……都能一条一条指到已有的用例上。
其中一条值得单独记,因为我写的理由本身是错的。
那个测试类的说明写着:「导出再导入永远到不了 published 相同、
只有 updated 不同的形状。」实际上正好到得了——一条书评被编辑时
created_time 不动、edited_time 动,
而 test_ndjson_edit_replays_on_reimport 测的就是这个。
整个类赖以成立的前提,对它最核心的那条测试不成立。
「这些是别处测不到的」是一句需要去证的话,不是一句可以拿来当理由的话。 我按类别说服了自己——「导出再导入只能证明同一份代码的两半互相同意」—— 这句话本身没错,错在我没有对着那 35 条已有用例一条一条比。 按类别推理出来的空白,和真的空白,是两回事。
剩下 9 条确实没有对应:不被本实例识别的 catalog id 靠
external_resources 解析、缺 updated 时编辑被静默丢弃的对照组、
豆伴的 .xlsx 走到视图(它本身就是 zip,
is_zipfile 分不出来)、不认识的 format_type,
以及四条把同一个账号的 CSV 与 NDJSON 归档逐字段对比的。
但这个 PR 已经不改任何 Python 了,测它没碰的行为就不该放进来,
所以一并删掉,需要的话另开一个。
仍需强调: Letterboxd 和 Goodreads 这两路仍然没有做过真实往返, 它们能证明的只是「产出符合读源码、读文档读出来的格式」,不是「对方真的收」。