技术与系统 2026-04-12

写给自己的小工具:为什么我不再追求“大而全”的通用软件

商业软件注定会走向膨胀,而一段只为解决自己一个微小痛点而写的两百行代码,就像家里自己动手做的晚餐,简单、适口,且永远不会背叛你。

几乎每一款我曾真心喜爱过的独立软件,最终都走向了相似的宿命:第一版轻巧锐利,只专注做好一件事;到了第三版,为了支撑商业化订阅与团队融资,它开始加入协作空间、内置聊天窗口、云端市场以及关不掉的新功能引导弹窗;到了第五版,仅仅是启动主界面就需要等待三秒钟的 Electron 空白加载框。

这并不能完全归咎于开发者的贪婪。当一款软件试图服务十万个背景截然不同的用户时,它就必须为每个人的边缘需求留出配置开关,最终不可避免地退化成一个臃肿的公约数。而身为一个每天都在与代码打交道的人,我渐渐意识到自己手里其实握着一项被忽视的特权:既然我不需要把这个程序卖给任何人,我完全可以只为自己写一个永远不需要“做大”的小工具。

一、“家常菜软件”的乐趣

作家 Robin Sloan 曾提出过一个迷人的比喻:有些软件像是工业化流水线生产的包装食品,保质期长、渠道广,但里面塞满了防腐剂与商业添加剂;而另一些软件则像是我们在自家厨房里为家人做的家常菜(Home-cooked Software)——它不需要考虑如何跨国冷链运输,也不需要设计精美的促销包装,只需要合乎自己与三两好友的口味。

“当你明确知道一段代码的唯一用户就是你自己时,软件工程里 80% 的防御性噪音都会瞬间消失:你不需要写多租户权限表,不需要接支付网关,甚至不需要图形界面。”

在我的 ~/bin 目录下,常年躺着十几个这样的小脚本与单文件编译程序。它们有的只有几十行 Shell,有的不过两三百行 Go 或 Python,却极其丝滑地接管了我日常工作流里最琐碎的缝隙。

二、三个陪伴我多年的百行小工具

举几个正在每天运行的例子:

  1. 胶片底片归档重命名工具(roll-pack):每次从冲印店拿到一整卷 36 张 TIFF 扫描件时,文件名往往是毫无规律的编号。我写了一个 140 行的命令行小工具,读取当前目录下的 roll.toml 元数据文件(记录机身、镜头、胶卷型号与拍摄日期范围),自动将图片按序号重命名、利用 exiftool 写入模拟的模拟相机 EXIF 信息,并批量生成适合博客发布的无损压缩归档。
  2. 稍后阅读纯文本抓取器(clip-md):厌倦了市面上稍后阅读软件动辄每年几十美元的订阅费与花哨的社交高亮功能后,我用 Go 标准库配合可读性正文提取算法写了一个 220 行的工具。在终端里输入 clip-md <URL>,它会直接拉取网页正文、剥离所有广告与样式脚本、转化为干净的 Markdown 文件,直接存进我的 ~/Notes/01-inbox/ 目录。
  3. 账单文本对账脚本(ledger-csv):每月月底把银行与移动支付导出的 CSV 账单拖进终端,通过一份自己维护了四年的正则映射表,三秒钟生成兼容纯文本复式记账(Beancount / Ledger)格式的月度流水,全过程没有任何一字节财务数据离开过我的本地硬盘。
#!/bin/sh
# 极简速记脚本 jot:在终端随时追加一行带时间戳的灵感至当月手记
NOTE_DIR="$HOME/Notes/02-journal/$(date +%Y)"
NOTE_FILE="$NOTE_DIR/$(date +%Y-%m).md"

mkdir -p "$NOTE_DIR"
if [ $# -eq 0 ]; then
  ${EDITOR:-vi} "$NOTE_FILE"
else
  printf -- "- **%s** %s\n" "$(date '+%Y-%m-%d %H:%M')" "$*" >> "$NOTE_FILE"
  echo "✓ 已记入 $NOTE_FILE"
fi

三、“完成”是一种难得的美德

在现代互联网语境下,如果一个开源仓库最后一次提交是在两年前,评论区往往会有人警惕地询问:“这个项目是不是已经死(Dead)了?”

但我始终觉得,一个软件能够进入“不再需要修改”的状态,恰恰是它设计得足够克制、边界足够清晰的最高褒奖。就像一把锤子或一只茶杯,只要需求没有改变,它就不需要每周推送一次固件更新。

我写的那个账单转换脚本最后一次修改是在 2023 年秋天;那个稍后阅读抓取器已经稳定跑了整整二十个月没有改动过一行代码。它们没有版本号焦虑,没有遥测埋点,只在我敲下回车的那几十毫秒里安静地完成任务,然后干净利落地退出内存。这种人与工具之间纯粹而笃定的契约感,大概就是写代码这件事最初带给我的快乐。