注册并分享邀请链接,可获得视频播放与邀请奖励。

搜索结果 ReFa
ReFa 贴吧
一个关键词就是一个贴吧,路径全站唯一。
创建贴吧
用户
未找到
包含 ReFa 的推特
OpenAI 和 worklouder 合作的这个小键盘正式发布了,实际上是现有产品的换皮联名版,原版定价 174 美元,Codex 版 230 美元。 差价换来的比较有意思的地方是为 Agent 运行状态设计了一个专属的状态指示灯,每个 Agent Key 用 RGB 实时显示 Codex agent 的状态——思考中、运行中、等待、完成,不切窗口就知道哪个 agent 需要你。 摇杆触发 skills:review PR、debug、refactor 这类常用工作流一拨即发。 以及 Codex 内置的各种专用命令键:accept、reject、push-to-talk、新建对话等高频操作各占一颗实体键 还有个独立的实体 Reasoning 旋钮:转动旋钮实时调节模型推理深度,简单任务调低求快,重活儿调高 但作为被 worklouder 小厂品控坑过一次的用户,心情是急需一个有真正供应链品控管理的键盘品牌来做个同类竞品。
显示更多
0
43
27
1
转发到社区
小米 6 月 11 日开源 MiMo Code,MIT 协议。 没绑硬件、没要求注册手机号、直接 MIT。 持久记忆系统跨会话保留,3 周前讨论过的代码方案,今天接着继续。 「无限上下文」压缩策略支持百万级 token。 Agent 协同模式同时跑代码生成 + 单测 + 重构 + Code Review 四个 sub-agent。 独立开发者周末测出来:MiMo Code 在多文件 refactor 比 Cursor 强,单文件补全 Cursor 还是顺手。 Cursor + Claude Code 体系第一次被国产 MIT 协议挖出一个口子。 要不要先 fork 一份周末试一试?
显示更多
🔥 用 AI 写代码最烦的不是 AI 不会写,而是它一上来就乱写! 需求没问清、术语不统一、测试没反馈、架构越改越乱。 最近发现一个神级项目,Matt Pocock 把自己每天做真实工程的 Agent Skills 整理成了开源仓库。 GitHub: 1️⃣ /grill-me 和 /grill-with-docs 开工前先追问需求,减少 Agent 理解偏差。 2️⃣ /tdd 🧪 引导 Agent 走 red-green-refactor,用测试约束输出。 3️⃣ /diagnose 🐛 按复现、最小化、假设、插桩、修复、回归测试的流程排 bug。 4️⃣ /improve-codebase-architecture 🏗️ 定期检查代码结构,避免越写越像泥球。 5️⃣ /to-issues 和 /to-prd 📋 把想法拆成更适合执行的 PRD 或 issue。 6️⃣ 一键安装支持 ⚡ 支持通过 npx skills@latest add mattpocock/skills 安装到不同 Coding Agent 里。 如果你已经在用 Claude Code、Codex 或其他编程 Agent,这个项目很适合作为工作流参考。
显示更多
Karpathy 发布了一个github开源项目,狠狠让我惊艳到了 这个项目叫 andrej-karpathy-skills,GitHub 13 万+ star,我愿称之为2026 最有用的 AI 工程项目 它解决的问题极其精准:让 Claude Code 不再瞎写代码 这个项目到底有多厉害? 先说结论:一个 4KB 的文本文件,让 AI 写代码的错误率暴降 90% Karpathy 自己说,他现在 80% 的代码都让 Claude 写,但 AI 经常犯几个典型错误: 不问就瞎猜需求 过度设计,写一堆用不上的抽象 改 A 顺手把 B、C、D 也重构了 代码能跑就行,不管目标达成没有 这个项目就是专门给 Claude Code 戴上guardrails,用 4 条行为准则约束 AI 的编码行为 核心亮点:4 条准则改变一切 整个项目就是一个 CLAUDE.md 文件,里面只有 4 条规则,但每一条都直击 AI 编码的痛点 1. Think Before Coding - 先思考再动手 AI 最大的问题是“太听话”,你说啥它就写啥,从不质疑 这条准则要求:明确说明假设、权衡 tradeoffs,不确定就直接问 不再是“我猜你想要这个”,而是“我理解你的需求是 A,但 B 方案可能更合适,你要哪个?” 2. Simplicity First - 极简实现优先 AI 天生爱炫技,你要一个登录功能,它给你写个完整的 OAuth 2.0 + JWT + 刷新令牌 + 权限系统 这条准则强制:只写刚好能解决当前问题的最小代码 不搞 speculative abstractions,不写未来功能,不过度工程 一个用户反馈:用了这条规则后,代码 diff 从动辄几百行缩减到几十行,review 轻松太多 3. Surgical Changes - 手术式精准修改 这是我最爱的一条 AI 有个恶习:你让它改个 bug,它顺手把整个文件的命名风格、缩进、注释全优化了 这条准则要求:只改用户要求的部分,严格匹配原有代码风格 不碰无关文件,不顺手 refactor,不加“看起来更好”的改动 有开发者实测:启用这条后,git diff 从“满屏红绿”变成“3 行精准修改” 4. Goal-Driven Execution - 目标驱动执行 AI 经常写完代码就交差,但代码能跑 ≠ 任务完成 这条准则要求:把任务转化为可验证的目标/测试/成功标准,然后 loop 执行、验证、迭代 直到真正达成目标才停止 这让 AI 从“代码生成器”变成“问题解决者” 真实效果:社区反馈炸裂 X 上这个项目刷屏了,开发者反馈高度一致: 代码质量飞跃:diff 更紧凑、干净,overbuild 和 side changes 大幅减少 错误率暴降:有人实测从 41% 掉到 11%,继续优化后低至 3% 中文社区评价:“必备 skills”“Claude/Cursor 实用技能 Top1”“直接扔项目里就完事了” 很多人直接 @ 朋友推荐:“把这个 CLAUDE.md 放进去,Claude 立刻像换了个人,写代码更靠谱、不乱改、不瞎猜“ 使用方式:简单到离谱 这是我见过最简单的 AI 工程优化方案: 方法一:直接 curl 把 CLAUDE.md 下载到项目根目录 curl -o CLAUDE.md 方法二:用 Claude Code / Cursor 的 plugin 一键安装 支持 Claude Code、Cursor 等主流 AI coding 工具 完全开源(MIT 协议),拿来就用 作为产品经理出身的开发者,我看到的不只是 4 条规则,而是对 AI 编码行为的深刻洞察 Karpathy 做的事情本质上是:给 AI 建立编码的第一性原理,他把他对于AI编程的理解写入了文件中 不是教 AI 怎么写代码(它已经会了),而是教 AI 什么时候该问、什么时候该停、什么时候该简化 这 4 条准则就像产品经理给开发团队定的 PRD 原则: 需求不清楚? 先问 功能够用就行? 别过度设计 改需求? 只改需求相关的 做完了? 先验证目标达成没有 它能帮到我们什么? 如果你是独立开发者或小团队,这个项目能直接提升你的 AI 协作效率: 减少返工:AI 不再瞎猜需求,写出来的代码更符合预期 降低 review 成本:改动精准,不用在一堆无关修改里找真正的变更 提升代码质量:极简实现意味着更少的 bug、更好的可维护性 加速迭代:目标驱动让 AI 真正解决问题,而不是生成代码 对于中大型项目,这是让 Claude Code 真正“生产可用”的关键一步 我的使用体会 我在自己的几个项目里部署了这个 CLAUDE.md,最直观的感受是: AI 变聪明了 以前它是个听话的实习生,你说啥它做啥,经常做错 现在它像个有经验的同事,会主动问“你确定要这么做吗? 我有个更简单的方案” 代码 diff 变干净了 以前一个小需求能改几十个文件,现在精准到只改 3-5 行 我的工作重心变了 以前 60% 时间在 review AI 的代码、修 bug 现在 80% 时间在思考产品逻辑,AI 真正成了生产力工具 最后 这个项目被誉为 2026 年 AI coding 领域的“现象级”黑魔法工具 小文件,大作用 如果你在用 Claude Code / Cursor 写代码,强烈建议直接把这个 CLAUDE.md 扔进项目根目录 GitHub 地址: 试过的人基本都是“已全项目部署”的状态 作为一个天天和 AI 协作的开发者,我的建议是:别犹豫,直接用
显示更多
0
41
487
92
转发到社区
决定代码复杂度的东西不在代码里,在写代码的人的脑子里。LLM 碰不到它。 这是 软件工程师 Pol Alvarez Vecino 读完 Peter Naur 1985 年的论文后得出的结论。 为什么 LLM 没法让你的代码更简单 本文最初发表于 Medium( tl;dr:Peter Naur 的《Programming as Theory building》指出,真正的程序——他称之为 Theory,大写的 T——存在于工程师的脑子里。代码和文档只是下游的(因而不完整的)产物。我对 LLM 最大的抱怨之一,就是它写出来的代码有多啰嗦、复杂度是怎样到处蔓延的。我一直抱着一丝信念:也许我们可以用 LoC 或者独立代码路径数量之类的指标来约束它们。然而,读完 Naur 之后我意识到,我们想降低的那个复杂度是 Theory 的复杂度,不是代码的复杂度,而这方面没有任何可用的度量,因为它非常主观。 我最近读了 Peter Naur 那篇精彩的论文《Programming as Theory building》( LLM 能做什么、不能做什么的看法,也改变了我对如何给它们写提示词、当前 agent 系统的主要局限,以及结对编程为何如此有效的看法。 今天我只聚焦它和代码复杂度的关系。 如果你还没读过这篇论文,我真的建议你读一读。说实话,我写这篇文章的主要目的,就是让一些人去读原论文。它值得花这个功夫。这也是练习(或学习!)在 Solveit 里做精读的绝佳机会,因为在 Solveit 里这要容易得多:你可以在阅读过程中随时提问,钻进任何你感兴趣的兔子洞,或者直接让 Solveit 帮你把语言讲清楚。关于精读的更多信息见这篇博文( fork 我的对话记录快速上手( 话说回来,如果你还是决定不读,这里是论文的 tl;dr: 程序是构建和维护它的人所持有的 Theory:一种理解——程序如何与现实世界的问题相关联,哪些约束和权衡塑造了它,它为什么能工作,以及哪些改动符合它的设计。代码和文档是这套 Theory 的下游产物,永远无法完整地承载它。 工程师通过经验发展出这种理解:与用户交谈、观察故障、学习领域知识、观察系统在真实世界中的表现。这种理解指导着对相关性、相似性、简洁性和良好设计的判断。 LLM 不太擅长持续学习,不擅长和用户交谈,也不擅长在真实世界里体验事物。但这和复杂度有什么关系呢? 我想我们都同意:LLM 总体上倾向于让代码库的复杂度上升,如果没人管的话。原因有很多:它们没意识到某个方法已经存在,于是又写了一遍;它们写过度防御的代码,比如为不可能发生的边界情况做防护;或者过早地过度优化。顺便说一句,大多数前沿实验室从你消耗的 token 里赚大钱,所以它们多少有动机去推广 token 最大化。总而言之,LLM 很少遵循 KISS 原则。这个问题在你不看输出、纯 vibe-coding 的时候最严重。但即使你会审查代码,要想让程序保持简洁,也需要主动付出努力去尽量削减复杂度。 在我天真的日子里(大约两周前),我曾以为我们早晚能爬出这个复杂度的大坑。前沿实验室只需要在 RL 训练里加一些复杂度惩罚就行。他们可以用总 LoC 作为最小化的指标,但我们都同意,有时候一行代码比两三行更复杂。另一个选项是圈复杂度(cyclomatic complexity),它衡量独立代码路径的总数。读完 Peter Naur 之后我意识到,这些东西无法真正解决问题(也许能稍微缓解一点)。我们来看看为什么。 为什么代码复杂度是错的指标 在下面这个(我编的)例子里,我们想支持调用 OpenAI 和 Anthropic。假设所有的消息准备和重试逻辑完全一样,只有请求体参数略有不同,于是我们有两个不同的方法 call_openai 和 call_anthropic。 在第一个朴素版本里,我们有两个不同的类,带重复的样板代码(即 prepare 和 with_retries)。 分开 —— 指标会发现重复 class OpenAIClient: def complete(self, prompt): msgs = prepare(prompt) # 公共样板代码 y = call_openai(msgs) # 唯一不同的一行 return with_retries(y) # 公共样板代码 class AnthropicClient: def complete(self, prompt): msgs = prepare(prompt) y = call_anthropic(msgs) return with_retries(y) 一个直接的 refactor 是创建单个类,做到 DRY。按很多指标看这都是更好的实现:行数更少、Halstead 容量更好(V=N×log2(n),N 为程序长度,n 为词汇量)、可维护性指数(Maintainability Index)也更好。 合并版 —— 按指标看确实更好:DRY,行数更少 class LLMClient: def __init__(self, provider): self.provider = provider def complete(self, prompt): msgs = prepare(prompt) y = call_openai(msgs) if self.provider == "openai" else call_anthropic(msgs) return with_retries(y) 一般来说,第二个版本(或者类似减少 LoC 和重复的版本)复杂度更低。但是,如果我告诉你,下个月我们很可能就停止支持 Anthropic 了呢?在那种情况下,我更倾向于让它们保持分开,这样到时候我只要删掉包含 AnthropicClient 的那个文件就行。 当然,这种简单的例子很容易解决,尤其是现在 LLM 可以帮你写代码。但如果你的目标不是 2 个供应商,而是像 LiteLLM 那样支持 165+ 个供应商呢?那种情况下,直接用 LiteLLM 就行。但那样你就把 120 多万行 Python 代码放到了你和最终供应商之间。值得吗? 设计良好的 API 是抽象复杂度的绝佳方式。你有清晰的契约,不需要理解背后发生了什么。即使 LiteLLM 是一个庞大的包,它也可能不计入你的 Theory 总复杂度。LLM 推理端点早期的日子就是这样:「文本进,文本出」。然而,当契约不再可靠时,这一切就会崩塌。原因可能是它有 bug,可能是 API 背后藏着大量你拿不到的状态,也可能仅仅是你不确定某个新供应商特性是否被支持。 每当你被迫窥视 API 抽象层背后的深渊时,那份复杂度就成了你的问题。这个问题正变得越来越普遍。像 OpenAI 和 Anthropic 这样的供应商,越来越多地把数据藏在服务端,比如加密的压缩数据或推理 token(更多讨论见 如果你在快速推进、只用基础功能、想尝试很多供应商,那么 LiteLLM 或类似的库可能值得用。反过来,如果你看重控制力、调试和对技术栈的理解,那可能就不值得。不存在「正确的」复杂度(虽然我非常偏好第二种选择)。 进入 Theory 决定走哪条路的信息不在代码里。这些信息属于 Naur 所说的程序的 Theory 的一部分。迄今为止,LLM 几乎接触不到这些信息,因为它们活在人的脑子里。它们可以从 IM、邮件或其他书面文档里得到一些线索,但那些永远只是局部的(最好的情况下)。 其中一些信息可以作为上下文提供给 LLM,比如业务优先级、预期的产品变化、运维约束,以及早期决策背后的原因。这样做也许能改善它的选择,但这些仍然只是 Theory 的产物。它们无法完整地传递团队发展出这套 Theory 所依赖的经验和判断。 这些都很好,但如果我全身心投入 vibe-coding 和 token 最大化、完全不在乎代码呢?那样的话,这篇博客后面的内容说服不了你。如果你处于两者之间,我来描述一个我们在 亲身经历的真实情况,关于 Solveit 的计费系统。 剧透警告:在 最初的计费系统 Solveit 是一个平台,你可以在里面用 AI 在一个类 notebook 的环境里工作。环境是持久化的,所以我们对 LLM 用量、CPU、磁盘、内存和带宽收费。 最初的计划是向用户收月度订阅费(比如 5 美元)。这笔月度订阅费变成当月可以消耗的积分(credits),如果全部用完,下个月之前就得充值。我们先在一个更小的项目里测试了这套方法来验证它。 这套方法后来证明比我们想要的更复杂。第一,积分 + 订阅的机制会把人(比如我自己)搞晕。第二,它让代码在多个层面上更复杂。你得处理「先消耗月度订阅积分、再消耗普通积分」的所有逻辑,以及剩下的积分怎么办。在 Stripe 这一侧,它有两个不同的代码路径:手动充值和订阅服务。 对不熟悉的人来说,Stripe 订阅是一个全托管服务。Stripe 管理整个生命周期(扣款周期、发票、重试全在他们那边)。 你大致只需要这样创建订阅: stripe.Subscription.create(customer=cust_id, items=[{"price": "price_5usd_monthly"}]) 然后监听他们的 webhook,在订阅状态变化或付款到达时更新你的数据库(还有很多其他事件可以选择)。 直接收款则需要你启动一个 checkout session,让用户跳转到 Stripe 的域名填卡。这需要你提供一个 customer ID。那应该在什么时候创建 Stripe customer?用户注册时?他们尝试付款时?还是别的时机?全都是合理选项。 stripe.checkout.Session.create(mode="payment", customer=cust_id, line_items=[{"price": "price_5usd", "quantity": 1}], success_url="") 到目前为止还好吧?如果你对 Stripe 或支付没有太多经验,很可能你已经感到吃力,没法把这一切全装进脑子里。也许你设法把它简化成了: • 订阅 → 交给 Stripe 订阅服务管理 • 充值 → Stripe checkout 一个不明显的问题是:使用 Stripe 托管服务意味着你有重复的数据。一半数据在 Stripe 的后端,而你必须保证本地数据库和它同步。另一个问题是,调试的时候,你既要查 Stripe 的服务,又要查自己的数据库。比如,一笔付款没到账,是 Stripe 没发 webhook(「他们的错」),还是我们没把它存进数据库(「我们的错」)? Stripe 订阅服务很棒、很容易上手,但它是为支持海量用例而设计的。这意味着,即使设计得很好(它确实很好),这个 API 抽象最终也相当复杂。在这种情况下,你在用「卷起袖子自己写代码的复杂度」交换「学习 Stripe API 的复杂度」。 LiteLLM 和 Stripe 在不同规模上展示了同一个权衡:只要契约成立,外部抽象能极大地简化你的 Theory;但每当你需要调试、修改或超出契约去推理时,它隐藏的复杂度就变成你的了。 AAI 的做法 在 经过很多天的探索和讨论,我们最终定下了一个简单得多的系统。 首先,我们只做积分(credits),按用量收费。这是一个超级简单的模型(和 Theory!):充值积分,用多少付多少。 订阅一去掉,我们就可以删掉一大块用来保持同步的代码。剩下的付款路径只有两条:手动充值和自动充值。要做自动充值,你需要能保存客户的信用卡,以便随时扣款。而 Stripe checkout 不会保存信用卡,你只是让 Stripe 在他们的 UI 里处理这次付款。 长话短说,我们最终发现最简单的办法是:用户一注册就保存他们的信用卡。卡一旦在档,用户可以用它手动充值,也可以设置成自动充值。因为全部是我们自己处理的,同步问题几乎为零。我们只监听支付成功事件(没有订阅了!)。 结果就是,我们支付系统的 Theory 可以用一句话概括: 客户注册时添加信用卡,之后我们对该卡扣款——要么手动(充值),要么在余额不足时自动扣。 手动充值和自动充值现在走同一条支付路径。我们整个支付技术栈——拆在 Solveit 和 faststripe 之间——大约 300 行代码。 结果是非常低的复杂度,但这是数小时的探索、尝试和讨论换来的。我这里的解释充其量只是触及皮毛。 印度登场 那么上线那天发生了什么?一切顺利吗?没有。上线后我们发现,印度信用卡不支持你想什么时候扣就什么时候扣的 off-session 扣款。手动充值属于 on-session,仍然可以工作,因为用户会在我们的 UI 里看到一个类似 3DS 的验证流程;但自动充值不行。 在寻找解决方案时,我们发现 Stripe 托管订阅在印度确实能工作。为什么?因为 Stripe 替你绕开了所有这些复杂度。他们提前一天创建并持有 off-session 的支付意图(payment intent),这样银行就能在实际扣款前向用户发送预扣款通知或认证请求。 我们迁移出托管订阅时,就失去了这个特性。我问了一个前沿 LLM——我记得是 GPT-5.5——我们该怎么处理这个问题。你猜它给出的方案是什么? 用回 Stripe 订阅来处理 这个 LLM 提议的正是我们刚刚迁移出来的方案。读到这里,你会怎么说?你的意见是什么?我们应该迁回去吗? LLM 列出了两个选项:要么同时支持两套系统(随时可以开工,你一句话就行!),要么完全迁回旧的系统。我们做了什么?什么都没做。我们非常看重 Theory 复杂度,于是我们决定:让印度用户手动充值就好了(抱歉了各位!),换来一个更简单、更健壮的平台。 如果你不同意我们的选择,反思一下为什么不同意。真的,现在就停下来想一想。 这个问题没有正确答案,而这篇博客的目的之一,就是帮你看清你的答案来自哪里。你的论据是什么?更具体地说,它们是从哪里来的? 有很多场景下 Stripe 托管服务是更优的选择。举几个例子: • 公司收入最重要,手动充值的额外摩擦可能会让我们损失一些印度销售额,那我们应该迁回去(或者同时支持两套) • 销售团队用 Stripe Dashboard 的 UI,所有支付信息都放在我们自己的数据库里并不理想,因为他们没法在那里管理 我的观点是:你的代码的复杂度,真的取决于一大堆和代码无关的因素,而那些信息不在代码里。 隐藏的优势 那么为什么不干脆让 LLM 全权处理这些事呢?在我看来,最妙的答案是:我们的工作方式揭示了一个可能的商业机会。印度不支持 debit mandate(借记授权)的方式和世界其他地方不一样。Stripe 试图解决这个问题,但远远不是一个完整的解决方案。 在理解和简化流程与 Theory 的过程中,我们学到了产品之外有价值的东西。在我看来,这类洞察是可以转化为竞争优势的。 努力去理解,本质上就是一个简化 Theory 的过程。如果你放任 LLM 在复杂度上为所欲为,你可以很快产出大量代码。选择简化路线更长、更费劲,但长远来看我认为它是值得的,而且你可能会在路上发现隐藏的宝石。 原文: #LLM# #编程# #代码复杂度#
显示更多
推荐这篇文章,作者在 Google 和 Microsoft 都写过设计文档,他把设计文档的每个部分拆解到极其具体——每节都有示例、反例和"你需要回答什么问题"。如果你们团队的设计文档写得稀烂,这篇直接拿来当模板。 怎么写一份有效的软件设计文档 一份好的设计文档可以省下你数年的开发时间。写设计文档迫使你在浪费时间在错误实现上之前,先想清楚重要的决策。它也是协调团队和合作团队之间设计决策的最佳方式。 下面是我创建有效设计文档的方法,以及什么属于设计文档,什么不属于。 什么时候应该写设计文档 项目越复杂或风险越大,写设计文档的价值就越大。问这些问题: • 会有多人协调工作来实现这个设计吗? • 项目会超过三个月的全职开发工作吗? • 实现会在生产环境中跑几年吗? • 项目涉及跨团队协作吗? • 项目的目标和需求模糊吗? • 存在设计时可以预防的灾难性风险(比如安全漏洞、法律风险)吗? 如果对任何一个问题回答"是",可能值得写。对两个以上,"几乎一定"值得。 设计文档中应该投入多少 设计文档可以是简单的一页纸,也可以是 50 页需要五个不同团队签字的文档。没有通用规则规定你应该在设计文档上花多长时间,就像没有规则规定代码应该测多少。正确的投入取决于团队的目标、风险、截止时间和文化。有时候,正确的投入是零。 什么属于设计文档 一个简单的经验法则:如果我在这件事上错了,代价是什么? 不是所有设计决策同等重要。有些选择比其他选择灵活得多。如果你用 C++ 写了一个 web 应用,20 万行后发现 Ruby on Rails 才是更好的选择,你卡住了。另一些设计决策微不足道:比如一个"加载更多"按钮,如果你选错了,用户反馈几小时就能修复。你不会因为这件事在文档里写满你的思考过程,更不该浪费审查周期争论它。 设计文档的组成部分 标题 人们会在对话中用标题来指代你的项目,所以要有这些品质:简短(容易口头说出)、独特(让人清楚指的是哪个项目)、有画面感(概念上代表你的项目)。好名字:RecencyBank。坏名字:"飞天银马计划"。 元数据 作者(名字 + 邮箱)、创建日期、权威 URL。尤其当你们组织用短链接重定向如 http://go/recency-bank。 目标 一句话解释项目的 purpose,应该在文档第一页用任何干系人都能理解的平实语言出现。"通过在 Trogdor web 服务器和 Postgres 数据库之间增加缓存层来提高应用性能。" 背景 回答:团队为什么接这个项目?解决什么问题?之前有尝试解决吗?如果有相关文档,链接它们——项目测试计划、相关系统的设计文档、项目先前迭代的设计文档。 关键检查:你的设计文档在没有外部上下文的情况下能读懂吗? 目标 描述项目的高层目标,从背景部分逻辑连接过来,解释实现完成后世界是什么样子。避免用实现细节来设定目标——目标应该表达项目对用户、团队或公司的好处。 ❌ "将 Kubernetes 添加到我们的基础设施。" ✅ "最大限度地减少与部署新应用版本相关的中断。" 非目标 如果有些目标读者可能误以为在范围内的,明确写在非目标里。"创建一个通用、可复用的缓存系统——范围外。""位置感知缓存——范围外。" 场景 如果你的目标是"给图表加一个分享为 URL 的按钮",读者可能不理解实际是什么样子。场景部分允许你描绘一幅画面:Bob 创建自定义报告 → 点击菜单栏的分享 → 邮件链接给 Charlie → Charlie 看到只读模式下的完全相同的报告。 图表 图表极有价值,尽管可能看起来不那么明显。作为设计作者,你直观理解各部分如何拼在一起。你的审查者没有这个心理图景。最快让他们看到它的方法就是画出来。 考虑:数据如何流经你的系统?不同组件如何拼在一起?系统如何与依赖和下游客户端交互?定义了哪些通信协议? 选一个方便编辑的图表工具——Excalidraw、 Drawings。作者见过开发者画漂亮的白板图然后拍照放进文档,但第一稿很惊艳之后永远困在那张图上因为他们不能编辑照片。 术语表 定义读者可能不认识的术语。仔细想一下文档的潜在读者——特别是新成员和团队之外的人。最好的方案是使用可识别的术语,或在行内定义,这样读者不必在文档里跳来跳去。 约束 如果有重大约束——预算、客户端、基础设施或依赖——解释这些约束,让读者理解设计选择的背景。"我们的服务器全是 RISC-V,所有代码和依赖必须在 RISC-V 架构上运行。" 服务水平目标(SLO) SLO 是服务向客户端或用户提供的可衡量目标。在公司内部通常不会因为错误而惩罚同事(虽然那会有点好玩),所以设计文档定义 SLO 而非 SLA。 典型考虑:正常运行时间 / 可用性、延迟、规模。好的 SLO 防止模糊——"50% 用户面 HTTP 请求延迟 <=200ms",不是"在移动设备上性能好"。 监控 / 告警 如果你的服务挂了,你怎么知道?如果性能慢了 100 倍,你怎么知道?什么事件应该触发告警?"Trogdor 的 95% 用户面 HTTP 请求延迟 >= 3s——通知值班工程师。" 时间线 将项目分解为里程碑,指定干系人什么时候收到交付物。选择创造有用制品的里程碑。比如先做一个显示假数据的 UI 给客户看——假数据让你在错误理解需求时能尽早发现,而不是已经实现了所有后端管线再用生产数据填充 UI 后才发现。 接口 你的项目存在是为了服务人或其他软件系统,这些交互长什么样?图形系统的 UI(只需简单草图)、软件接口的 API 或 CLI 语义、文件接口的文件格式。用具体的代码示例说明接口的变化:type Server struct { db PostgresDB } → type Server struct { db } 依赖 / 基础设施 用什么编程语言?代码跑在什么硬件或服务上?持久数据存在哪里?深入思考哪些依赖在实现后难以改变——换语言或存储后端很难,但换第三方发邮件服务一个下午的事。 安全 考虑了哪些威胁?攻击面是什么?信任边界在哪里?即使认为安全威胁不太可能或无关,文档化你的推理仍然有助于提示审查者找出你忽略的威胁。 隐私 系统处理什么敏感数据?保留多久?谁可以访问?如何保护它? 法律考虑 如果在金融或医疗等高度监管领域——如何遵守相关法律。即使不在监管领域:如果事情出错系统是否可能违法?如何避免?如果开源,定义选什么许可和为什么。 日志 关键事件是什么?有不同日志级别吗?日志存在哪?保留多久?谁可以访问?有没有敏感数据必须排除出日志? 开放问题 文档化你的待解决问题:问题需要更多工作的是什么?看到什么选项能解决?下一步是什么? "选择缓存 RAM 大小:加 RAM 提高性能但贵且有收益递减。理论上可以设置测试环境跑模拟来发现最优值,但那些模拟要花 3 天开发时间。建议方案:选 128GB 不测试,可能接近最优,开发时间显著比 RAM 贵。下一步:问技术主管。" 已解决问题 解决开放问题后,总结决策,从开放问题移到已解决问题,保留完整讨论以备后查。 已考虑的替代方案 如果预料读者会问"为什么没选 X",主动回答。简要几行描述强力替代方案及为什么不行。不用在文档里耗费数小时写每个被拒方案的详尽理由。 驱动你的设计文档通过审查 完成设计文档后,下一阶段是和团队分享并收集反馈。(作者有一篇后续文章讲如何获得有意义的反馈。) 原文:Michael Lynch, "How to Write an Effective Software Design Document", Refactoring English, 2026-06-24 #软件工程# #设计文档# #工程实践#
显示更多