cramforce 译者
张健欣 策划
万佳
谷歌软件工程文化的主要元素之一就是通过设计文档定义软件设计。在开始项目编码工作之前,软件系统或应用程序的作者会创建这些相对非正式的文档。设计文档记录了高级实现策略和关键设计决策,并且重点记录了这些决策之间的权衡考虑。
作为软件工程师,我们的工作本质上不是生产代码,而是解决问题。非结构化文本,类似设计文档的形式,也许是在项目早期解决问题比较好的工具,因为它易于理解、更简洁,且以比代码更高的层次来沟通问题和方案。
除软件设计的原始文档外,设计文档还实现了软件开发周期中的如下功能:
在早期发现设计问题,而那时变更的成本还比较小
在组织内围绕设计达成共识
确保考虑到交叉领域的问题
将高级工程师的知识扩展到组织中
围绕设计决策形成组织记忆的基础
在软件设计师的技术组合中充当总结工具
设计文档的结构设计文档是非正式文档,因此它们的内容不会遵循严格的准则。一个首要原则是,针对具体项目可以用任何最合理的形式编写。
话虽如此,形成的特定结构必定有其价值所在。
上下文和范围这一部分会粗略地向读者介绍新系统是如何构建的以及实际情况如何。这不是需求文档。请保持简洁!我们的目标是直接让读者了解最新情况,但先前的一些情况可以被推测或者能链接到详细信息。这个部分应该完全聚焦于客观背景事实。
目标和non-goals这一部分会列举出系统目标是什么,但有时候更重要的是,列出系统的non-goals。注意,non-goals并不是像“系统不应该崩溃”这样的负面目标,而是那些本可以合理地成为目标但却明确地选择不作为目标的东西。一个很好的例子是“ACID准则”;当设计数据库时,你肯定想知道这是一个目标还是一个非目标。而如果这是一个non-goals,如果它不会阻碍目标的实现,那你仍然可以选择一个提供它的解决方案。
实际设计这一部分应该从概述开始,然后扩展至详情。
设计文档适合写你在设计软件时所做的权衡。把重点放在这些权衡上,来产出具有长期价值的文档。换句话说,给定上下文(事实)、目标和non-goals(需求),设计文档可以提供建议方案并展示为什么某个特定方案最能满足那些目标。
在比较正式的媒介上,编写文档的目的是提供灵活性,以适当的方式展示手头的问题。因此,对于如何真正地描述设计并没有明确的指南。
尽管如此,对于大部分设计文档来说,一些最佳实践和重复话题都很有意义:
系统语境图在许多文档中,系统语境图都非常有用。这样一张图将系统作为更大技术环境的一部分展示,允许读者结合他们已经熟悉的环境进行理解。
系统语境图示例
APIs如果正在设计的系统暴露一个API,那么勾勒出这个API通常是个好主意。然而,在大多数情况下,人们应该按捺住将正式接口或数据定义复制粘贴到文档中的诱惑,因为这些定义通常都很冗长,包含一些不必要的细节,而且很快就会过时。相反,人们应该聚焦于与设计及其权衡相关的部分。
数据存储存储数据的系统应该讨论如何及用何种大致的形式存储数据。和关于API的建议类似,并且理由相同,应该避免复制粘贴完整的模式定义。相反,要聚焦于与设计及其权衡相关的部分。
代码与伪代码除了一些描述新奇算法的场景,设计文档应该很少包含代码或伪代码。在适当的情况下,可以链接到设计实现的原型。
约束度影响软件设计和设计文档形状的主要因素之一就是方案空间的约束度。
极端的一个例子就是“绿地软件项目”,我们都知道目标,而且解决方案可以是任何最有意义的方案。这样一个文档可能涉及面很广,但它还需要快速定义一组规则,来允许对一组可控的解决方案进行细致研究。
另一方面,系统中可能的方案都定义得很好,但是完全不清楚如何将它们组合起来实现目标。这可能是一个很难更改的遗留系统,而且它不是按照你希望的样子设计的,或者是一个程序库设计,需要在宿主编程语言的约束下运行。
在这种情况下,你也许能列举出相对容易做的事情,但你需要费些心思将这些事情组合起来,从而实现目标。可能有很多方案,但没有一个是非常好的,因此,这样一个文档应该聚焦于根据所有确定的权衡点来选择最佳方案。
可供考虑的备选方案本节列出了能合理实现类似结果的备选设计。重点应该放在每个设计所做的权衡,以及这些权衡如何导致选择这个设计的决定,而这正是这个文档的首要主题。
虽然简略介绍最终没有被选中的方案也没有什么,但是本节会非常明确地展示为什么被选中的方案是针对项目目标的最佳方案,以及读者可能想知道的,为什么其它方案提供的权衡针对目标方案是不太理想的。
交叉