Register and share your invite link to earn from video plays and referrals.

yibie
@yibie
Joined November 2008
2.5K Following    4.5K Followers
推荐这篇文章,作者在 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 #软件工程# #设计文档# #工程实践#
Show more