十五天:三次推翻、一次堆量,和几个被砍掉的功能
十五天:三次推翻、一次堆量,和几个被砍掉的功能
10 月 24 日到 11 月 8 日,十五天。六个项目,近两百次提交,三次把已经写好的东西推翻重做。
这篇不是项目介绍——每个项目的 README 都比我能写得清楚——只记那些没进 README 的决定。
一、先学会砍:x-video 从「什么都能看」退到「只看本地」
10 月 30 日开工,48 次提交,现在版本号是 v2.0.0-alpha.6。中间最大的一次动作不是加功能,是换定位。
旧版(v0.4.x)跨 macOS / Linux / Windows,内嵌 axum HTTP 服务,把 TVBox、网页解析、JS Spider、IPTV、聚合搜索全塞进去。2.0 直接砍成 Windows 单平台、本地文件、mpv 唯一内核,Tauri IPC 替掉 HTTP 中间层——只删掉一层”中间商”,播放链路上就少了一种失败可能。
被移出范围的东西我一条都没删,全列在 docs/DESIGN-v2.md 里,标注「保留扩展位,不实现」:在线点播源、IPTV 直播、网页解析、JS Spider 沙箱、聚合搜索、投屏、录制、云同步。
为什么舍得?因为那些功能的维护成本是按天收利息的:每条网页解析规则都可能下周失效,每个源都可能变成 404,而我修它们的时间,全部来自「播放器本身能不能把 4K60 HDR 播顺」这一件事。一个播放器,播放不稳,其他都是装饰。
砍完之后反而有了余量:容器从 MP4 一路开到 RMVB、M2TS,音频能啃 APE 与 DSD,字幕分内嵌轨(PGS / ASS / VobSub)与外挂模糊匹配,硬解优先 D3D11VA、失败自动回落软解。这些是看着不酷、但决定你愿不愿意拿它看片的部分。
判断一个功能该不该砍,我的标准是:它的失效频率是不是按周计。是,就砍;不是,再谈。
二、第二次推翻:不是换库,是承认自己选错
x-notepad 10 月 27 日开工,十二天里从 0.1.0 走到 0.16.1,17 个版本号、44 次提交、约 1.37 万行。
大纲里写的方案是「Tauri + Scintilla(Rust 绑定)+ wasmtime」。落地改了三处,第一处最疼:Scintilla 换成 CodeMirror 6。
理由并不复杂:scintilla-sys 只有裸 FFI 绑定,更新停在 2025 年,塞进 Tauri 窗口要给 Win32 / Cocoa / GTK 各写一套挂载代码,React 那层 UI 还得给它让位。而 CM6 是视口渲染,语言包按需 import(),一百多种语言的懒加载是现成的。
第二处更难看:我把性能目标从「启动 <0.3s、内存 <50MB」改成了「<1s / <120MB」。不是优化失败,是这两个数字和 WebView 路线物理冲突——WebView2 初始化本身就 300ms 起,50MB 只有自绘原生 UI 才做得到。承认这件事的当天我就把 README 里的目标改了,没留「以后再说」的余地。
第三处是插件:原本打算 TS 接口、同时兼容 .js,后来全部改成纯 WASM(Component Model,接口用 WIT 描述,v1 核心模块走兼容层)。原因很直白——WebView 里跑的 .js 插件能拿到 invoke,沙箱形同虚设。既然要给插件开能力,就得同时给边界:后来陆续补了 plugin.json 权限声明(装之前先告诉你它要什么能力)与 Ed25519 签名(内容摘要对不上直接拒装)。
换库不丢人。丢人的是在错误的底座上继续加功能,然后每加一个功能都先还一次债。
三、同一时期的两条路:x-note 与 x-notepad
10 月 24 日先把 x-note 推到 v0.4.0:Tauri 2 + React 18,功能表一路补——双向链接、反链面板、关系图谱、标签、版本历史与 diff、可装可更新的插件中心(官方插件里有 Gist 备份、AI 写作助手、全库待办看板)。
三天后又从零开了 x-notepad。两个笔记应用同时在长,功能清单高度重叠,但取舍几乎处处相反:
| 维度 | x-note | x-notepad |
|---|---|---|
| 起点 | 先把体验补齐 | 先把地基打对 |
| 编辑器 | 自研 Markdown 实时预览 | CodeMirror 6,100+ 语言懒加载 |
| 插件 | 目录动态加载,生态优先 | 纯 WASM + 权限声明 + 签名,边界优先 |
| 搜索 | 常规搜索 | SQLite FTS5,中文按字切分 |
| 节奏 | 0.1.0 → 0.4.0,功能驱动 | 0.1.0 → 0.16.1,一天一到两版 |
同时写两个笔记应用不是因为精力过剩。一个在回答「用户要什么」,一个在回答「如果再给我一次机会,我会怎么搭」。这两个答案经常不一致,而只有都写出来,才看得见差在哪。
四、唯一一次堆量:两天 508 个工具
toolsbox 是这批里最不「体面」的项目:11 月 7 日建仓,两天,9 次提交,508 款工具、9 个分类,代码加模板约 3.77 万行。
它能堆起来靠的不是勤奋,是把约束提前钉死:
- 纯前端、零依赖、不用框架、不打包,
index.html双击就能跑 - 所有计算在浏览器本地完成,一个字节都不上传
- 部署目标只有一个:Cloudflare Pages,构建命令留空
约束一钉死,「加一个工具」就变成几乎不需要决策的事:一段 HTML、一个纯函数、一条注册项。反过来,如果没有这三条,第五百个工具会先把我拖进构建配置和依赖升级里。
第四批上线时发现 4 款与旧工具功能重复,直接替换掉,没留着凑数。数量本身没有意义,数量只有在每一条都能独立站住的时候才有意义。
五、小东西也要认真收尾
- xfmpress:11 月 3 日到 4 日,
0.3.0。零运行时依赖的 Node 静态站点生成器,命令叫xfm。一千篇中文文档冷构建 4.4–5.5 秒,单页热重建 2–7 毫秒。这一版补上了真正的分类索引页与归档页——在此之前模板里链着/tags/<name>/,但没有任何东西生成它,每篇文章底下的标签链接其实都是 404。 - whois:一个 Cloudflare Workers 单文件,域名 / IP / ASN 的 RDAP 查询,走 RDAP.org 自动路由,中文结构化展示。没有后端,也没有服务器账单。
- X-Note-Plugins:把官方插件中心单独开仓,插件从这里发版、从这里更新,而不是散在笔记软件本体里。
六、这十五天学到的三件事
- 推翻的成本要在开工前算,而不是写完再算。 三次推翻里,两次发生在「已经能跑但不好用」的阶段——那是最便宜的时机,再晚一点就变成沉没成本。
- 诚实的指标比漂亮的指标有用。 把
<0.3s改成<1s那天,我并没有变强,只是不再自欺。指标写错,后面每个决定都在为它圆谎。 - 约束就是产能。 508 个工具不是两天写完的奇迹,是「不许用框架、不许联网、不许上传」这三条红线换来的。
十五天过去,版本号加了十几二十个,能拿得出手的其实只有一句话:
知道什么该砍,比知道什么该加更难,也更值钱。
评论