全部笔记

把技术笔记当作代码来维护

用内容集合约束元数据,用 Git 留下修改记录,让写作与发布保持简单。

假设一篇笔记写着「给页面加上 draft: true 就不会公开」,实现却只在首页列表过滤草稿。读者仍可能直接访问文章路由,RSS 也可能包含全文。这类文档问题不只是措辞不精确,而是说明与程序行为已经分离。

把技术笔记当作代码维护,重点不是让写作拥有更多工具,而是让每个重要承诺都有明确的消费者、版本和验证方法。本文使用 Astro 内容集合与本站的私人草稿工作流作为例子,说明结构检查能保护什么、保护不了什么,以及如何在修改后仍然知道文章可信到哪一层。

1. 一篇可维护的笔记要保存决策输入

只有最终代码的笔记,通常无法解释下一次修改。比如「我们使用静态生成」没有记录页面是否个性化、内容更新频率和运行时依赖,后来加上登录功能的人就可能错误沿用原方案。记录结论时,应同时保存促成结论的约束。

可以用一个具体问题组织正文:待解决行为是什么,哪些输入影响它,候选方案在哪些条件下成立,最终如何验证。不要把所有背景都写进去;读者需要的是足以重建判断的证据,而不是项目事件流水账。未知条件也要标出,例如某段代码没有经过多实例测试,就不要写成已经解决集群协调。

技术版本是输入之一。API 在哪个版本存在、默认行为是否变化、例子依赖什么运行环境,都影响能否复用。写「Spring 支持这个注解」比写清框架基准更容易过期。版本说明不必占满开头,但应在读者复制示例之前出现,并与参考文档对应。

2. 元数据字段应该有明确消费者

一份文章头部可以很小:

---
title: "让草稿过滤覆盖所有内容出口"
description: "用列表、路由与订阅源的反例验证发布边界。"
date: 2026-10-11
tags: [Astro, 内容工程]
draft: true
---

标题是正文承诺,摘要帮助读者判断是否值得进入,日期影响排序,标签用于筛选,草稿标记参与公开选择。每个字段都有页面或工具消费,因此修改语义时需要同时查看消费者。没有用途的字段会增加维护成本,不能因为其他 CMS 拥有它就自动照搬。

日期也需要约定。首次发布日期、最近修改日期和测试执行日期回答不同问题,把它们都塞到一个 date 字段,排序和历史会变得难解释。本项目目前只有文章日期,没有实现独立更新日期;因此不能让页面暗示所有技术结论都在显示日期当天重新验证过。

文件名与 slug 是公开链接的一部分。改标题通常可以保留路径,改文件名却可能让旧链接失效。发布后的路径修改应考虑跳转与订阅者已有链接,而不是只确认新页面能打开。私有稿件则应在首次公开前稳定身份,避免发布日志把同一意图误认为两篇文章。

3. Schema 验证结构,不验证事实

本站使用的集合形态如下,省略其他不相关配置:

import { defineCollection } from 'astro:content';
import { z } from 'astro/zod';
import { glob } from 'astro/loaders';

const writing = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/writing' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.coerce.date(),
    tags: z.array(z.string()),
    draft: z.boolean().default(false),
  }),
});

这种约束能发现类型不符合预期、字段缺失或无法转换的日期,却不能保证标题非空、摘要准确、标签体系一致。需要更强要求时,应在适用字段增加约束,而不是把「schema 通过」当作所有编辑规则通过。本例保持与当前项目配置一致,展示的是现有保护范围。

更重要的是,结构验证不理解技术含义。一个声称「事务失败会自动撤回邮件」的段落,即使字段齐全也可能错误。事实审核需要核对数据库与外部系统的边界、API 文档和故障窗口。形式检查可以自动化,但不能代替这种判断。

把一句结论拆成可以核对的断言

假设草稿写着“缓存驱逐后所有请求都读到新数据”。这句话至少依赖数据库提交已完成、缓存范围覆盖全部读取者、没有旧读迟到写回、授权没有在缓存命中时被跳过等前提。逐项拆开后,很可能发现实际代码只证明了更新方法成功调用一次驱逐。文章应该据此收紧结论,而不是在“所有”前加一个“通常”就结束审核。

可以为重要断言保存一份小记录:原结论、适用版本、必要前提、官方依据、验证夹具和未覆盖范围。记录无需进入公开页面,但写作者据此组织正文,能知道哪里需要展开。例如官方文档说明默认行为,最小程序展示编译约束,双实例夹具观察竞争,三者回答不同问题;不能引用其中一个就把另外两层也写成已证明。

引用应贴近它支持的具体机制。文档首页有一个框架名字,不表示它支持文章中关于取消或事务的全部推断。优先寻找对应版本、具体 API 和错误行为,保留引用检索时的上下文。来源发生更新后,先确认原结论是否仍成立,再决定修改文章或补版本限定,不能只把失效链接换成能访问的新首页。

每增加一条自动规则,都应该有拒绝它的反例。比如要求标签非空,就用空数组证明检查确实失败;要求日期合法,就加入非法值夹具。只有正常文章通过,无法证明规则在边界输入上有效。规则变更还应解释对历史内容的影响,避免批量迁移时默默改变语义。

4. 用一个公开选择函数约束多个出口

公开列表、文章路由、RSS 和 sitemap 不应该各自猜测什么算发布。本站通过一个内容读取入口过滤草稿,再按日期排序:

export async function getWriting() {
  return (await getCollection('writing', ({ data }) => !data.draft))
    .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
}

共享这个入口能减少过滤遗漏,但仍需检查消费者确实使用它。某个新的搜索索引如果直接读取整个集合,就会重新引入泄漏路径。架构图里只有一条公开入口,不代表所有代码都遵守了图;测试应该覆盖实际生成结果,而不是仅检查辅助函数返回值。

对敏感私人稿件,文件根本不参与公开集合更稳妥。本项目把完整草稿放在 .drafts/,只有选定文章才复制到公开目录。draft: true 是内容状态,不是访问控制产品;如果文件位于会被打包的目录,或者另外被上传,状态字段无法阻止访问。

测试可以同时设置公开正例与私有负例。构建后正例路由存在,负例标题、路径与文件名不出现在文章 HTML、RSS、sitemap 或搜索数据中。负例应使用容易区分的内容标识,避免与公开文章共享词语造成误报,同时保留直接 URL 访问检查。

5. 草稿审核与发布应该是两个状态变化

「我看过这篇文章」与「这篇已经公开」不是同一状态。审核记录确认的是某份具体正文;发布记录确认的是某个选定批次的公开结果。如果审核后正文改变,原结论就不能无限延续,尤其是代码示例、权限和操作命令发生变化时。

本站使用内容指纹记录已审核稿件。指纹不是自动事实检查,它只证明当前文件与审核时的字节内容一致。更换一个字也会让原审核失效,而原本就错误的内容不会因为指纹匹配变正确。理解这两层职责,才不会把哈希校验当成质量认证。

新增库存也不应偷偷改变已有发布队列。正在编辑的研究稿可能缺少例子或复核,若目录新增文件就自动排期,写作者会失去安全的准备空间。本站因此分开管理全部私有稿与当前审核集合,让待排期内容可预览,但没有自动获得发布资格。

审核完成后,发布还要经过构建、隔离检查和线上验证。失败恢复应继续原批次,而不是临时挑另外两篇掩盖错误;否则读者看到的顺序、每日限额和维护者的判断都可能脱节。文章内容与发布状态各自保存,才能解释部分失败。

同一文章身份下的不同修订

发布前的内容指纹可以帮助发现变化,发布后的更正还需要说明变化含义。修改标点、补链接和纠正不安全命令,对读者的影响不同。若曾推荐一个会破坏数据的操作,更新正文后不宜只留下没有解释的新版本;应让读者知道旧建议有问题、哪些场景受影响,以及已经执行的人应如何安全核查,而不编造一条保证恢复的命令。

文件名保持不变可以维持公开路径,Git 差异保存代码层面的修订,但已下载、转载或订阅缓存的旧文章不会自动同步。更正通知的范围依据风险选择,不能承诺网站修改会撤回所有副本。对正常增强细节的修订,也可以解释新增验证范围,避免读者把文章原发布日期理解为最新检查日期。

重新审核时先列出受影响消费者。正文更换了前提,摘要、示例命令和结尾建议可能仍沿用旧结论;搜索摘要也可能把已经删除的断言保留下来。要沿同一身份检查这些输出,确认读者从列表进入和直接访问时得到一致承诺。只审新增段落,而不回读与它冲突的旧段,是长文章维护中常见的失误。

6. 示例代码要说明完整性与副作用

一个省略业务类型的接口片段,可以帮助解释设计,但不能标成可直接运行。一个能编译的程序,也可能没有验证断网、并发或部署条件。文章应该区分示意代码、可运行最小例子、已执行测试和推荐读者执行的夹具。

命令尤其需要说明目标。ALTER TABLE 可能取得锁,EXPLAIN ANALYZE 会执行受支持查询,恢复备份可能覆盖数据。写「在测试环境执行」还不够,最好描述如何确认连接指向隔离库、预期影响是什么、失败后如何检查残留状态。危险操作不应被藏在看似便利的一键脚本中。

同样要审查异常路径。连接清理中的 finally 并不天然安全,恢复自动提交可能改变活动事务;JWT 验证成功也不等于对象授权通过。例子里最值得展开的,往往不是正常路径多调用一次方法,而是某个隐含前提失效后会发生什么。

对代码的事实判断,可以链接对应版本的官方 API,并为关键断言保留小型验证。没有实际运行数据库,就写清 SQL 经过文档核对而非实例验证。克制的证据范围比一句「生产可用」更能帮助读者决定是否适合自己的环境。

7. 文章长度是预算,不是深度证明

约十五分钟的文章需要足够信息,也需要有明确主线。把简短稿件拉长时,优先补一个完整案例:初始数据、执行步骤、失败位置、观察结果和修复后的验收。随后解释替代方案为什么不适用于当前约束,而不是重复开头的结论。

阅读时间只能估算。本站按照汉字和英文词数量计算,无法理解读者是否停下来运行代码、查看图表或查资料。页面显示十五分钟,是篇幅提示,不是承诺每个人都能在相同时间完成。大量链接、冗长命名或无关代码也可能抬高数字,因此长度达标后仍需人工检查信息密度。

一个实用编辑检查是给每节写一句职责:这一节增加了哪条机制、哪个反例或哪份证据。两节职责相同,就考虑合并;某节只是说问题很重要,就换成具体场景。深度来自对读者疑问的有效回答,不来自标题数量。

案例也要有可辨认的起点与终点。例如讨论事务失败,先给两条相关记录和预期不变量,再标出每个提交点,最后检查失败后的持久事实。突然出现一个异常类、随后直接宣布“用幂等解决”,缺少的是协议推导,不是段落数量。读者应能指出谁登记身份、谁裁决竞争、哪里仍可能产生未知结果。

技术、产品与设计都可以采用这种检查。产品案例明确参与者、任务和决策条件,设计案例保存输入状态、可见反馈及验收依据。不能用未经验证的转化率作为结论装饰,也不能把一个漂亮截图称为可访问性测试。没有实际观察时,用假设场景展示判断方法,并明确哪些测量应在真实用户和环境中完成。

8. 版本管理保存修改,而不是自动保存私人内容

公开文章可以与代码一起评审,让实现变化和说明变化出现在同一差异中。审查者不仅看错别字,还应核对例子是否跟随当前 API、旧结论是否仍成立、链接修改是否改变依据。修改记录帮助解释为什么变了,但不会自动证明新内容正确。

私有草稿没有进入 Git,就不能依赖远端仓库备份。需要另行安排适合自己的加密备份与恢复检查。反过来,一个秘密曾经提交进 Git,后来加到 .gitignore 也不会抹去历史;处理泄漏要考虑已传播副本和凭证轮换,不能只删除工作区中的一行。

生成的 HTML、依赖目录和截图通常不需要进入源码历史,锁文件则用于重现依赖解析。根据文件职责决定是否跟踪,比用「自动生成的都忽略」这种统一规则更准确。发布工具、内容源与私人资料的边界,应在 README 中让未来维护者看得懂。

9. 把验证放在真正的阅读页面

Markdown 源文件整齐,不代表渲染后可读。长行代码可能撑开手机屏幕,标题层级可能跳跃,链接可能指向错误版本,图片说明也可能缺少必要上下文。至少检查一篇长文章和一篇包含代码的文章,确认页面宽度、行距、代码滚动和目录导航正常。

正文修改后还要看列表摘要和主题筛选。标题强调了新主线,摘要却仍描述旧内容,会让读者误判文章价值。阅读时间变化则应来自实际正文,不手填一个固定数字,让后续增删内容仍能得到合理提示。

无障碍检查同样属于内容验收。标题应该形成可扫描的结构,链接文字说明目标,不能让读者只能靠颜色理解提示;代码片段需要周围文字解释输入与输出。搜索和筛选能否键盘操作属于页面交互,但文章组织本身也会影响辅助技术用户的理解成本。

长文需要检查定位和返回成本

十五分钟正文中,读者常在案例、官方文档和前提说明之间往返。章节名称应稳定指向职责,不能连续几节都叫“注意事项”;引用文字也应该让人知道将离开页面查看哪个依据。若增加目录或章节锚点,需要检查实际生成 ID、重复标题与返回位置,不把目录存在本身当成导航可用。

代码块的可滚动范围与页面宽度分开测试。窄屏可以让长代码在块内滚动,却不应让整篇正文超出屏幕;复制操作也不能因为视觉折行偷偷改动源文本。普通段落中的类型泛型应作为代码格式处理,避免 Markdown 将尖括号识别为 HTML,导致屏幕上显示的示例与源文件不同。

最后使用一篇包含中文、英文长标识、链接和多级标题的实际文章检查,而不是只用短占位段落。放大文字后,固定导航是否遮挡标题、焦点是否可见、代码是否仍能查看,需要观察真实页面。视觉检查能发现呈现错误,但不能替代技术事实复核;两类验收应分别留下范围,避免一张无溢出的截图承担它不能证明的正确性。

负例标记要证明检查真的读取了目标产物

草稿哨兵没有被搜索到,也可能是审计程序查错目录。为检查器准备独立夹具:一份产物故意含有哨兵,必须失败;另一份只有公开样本,必须通过。两份都通过时,先修复审计,不把结果解释成隔离完好。测试夹具不上传真实私人正文,检查器的证据与被检查的内容证据分开保存。

10. 用修改后的一个反例结束审核

提交审核时交付四项内容:一条准确结论、使它失败的输入、修复后的预期观察,以及实际验证范围。事务文章可以给出部分写入后异常的持久结果,缓存文章可以对照两种权限身份。只有测试计划而未执行,就标为待验证,不把预期结果改写成实验记录。

再沿这条结论检查标题、摘要、示例和最后建议。正文已经收紧到单机条件,摘要仍写“保证集群安全”,审核就尚未完成。引用链接、检查时的版本与渲染页面共同保留;下一次实现变化时,维护者能从这份证据定位需要重新审核的段落,而不必把整篇文章的可信度压成一个通过标签。

参考资料