[翻译]无痛功能规格说明书——Part1:何必麻烦?
当 Joel测试 刚面市的时候,读者反馈的最大痛点之一就是写规格说明。写规格说明看起来就像是用牙线:大家都知道自己应该写文档,但是大家都不写。
为什么人们不写规格说明?他们声称不写规格说明可以节约时间,他们表现得就好像编写规格说明这件事是专门为了 NASA 航天飞机工程师或者是大型保险公司人员保留的奢侈品,扯淡。首先,不编写规格说明就是你引入项目的 最大不必要风险,这就像只穿着T恤就出发去穿越莫哈韦沙漠,然后寄希望于“车到山前必有路”一样愚蠢。不写规格说明就直接开始进行项目的程序员以为自己是很酷的枪手,随手掏枪就能击中目标,但实际上他们不是。他们只是编写糟糕的代码,生产劣质的软件,通过承担完全没有必要的风险来威胁他们的项目。
我相信,在任何重要的项目上(指的是超过一周的编码时间或者超过一个程序员的投入),如果您没有编写规格说明,那么您 一定 会最终花费更多的时间,而且收获低质量的代码。原因如下。
规格说明最重要的功能是去 设计 程序,即便是程序中所有的代码都由您独立完成,您编写的规格说明只有您自己一位读者,编写规格说明的过程——在微小的细节层面描述程序的原理——也会强制您真正的设计去设计程序。
让我们来采访我想象中的两位来自不同公司的程序员。Speedy,来自 Hasty Bananas Software,她从来不写规格说明,“规格说明?我们用不着那种东西!”。与此同时,Rogers 先生,是一位来自 The Well-Tempered Software Company 的程序员,他在规格说明定稿前坚决不会写代码。这两位只是我想象中众多朋友中的其中之二。
Speedy 和 Rogers 先生有一个共同点:他们都在负责各自产品 2.0 版本的向后兼容性。
Speedy 认为保证向后兼容的最佳方案就是写一个可以把 1.0 版本文件转换成 2.0 版本文件的转换器。她迅速开工,热火朝天,大约两周后,她确实完成了一个可用的转换器,但她的客户不太满意,Speedy 的代码迫使他们必须将公司里每一个人的软件都升级到新版本。Speedy 的最大客户 Nanner Splits Unlimited 甚至拒绝购买这个新版软件。Nanner Splits 要求软件的 2.0 版本应该直接兼容 1.0 版本的文件,而非必须进行转换。Speedy 决定再写一个向后兼容的转换器,并且把他集成到“保存”功能里。这里开始有点混乱,因为当客户使用 2.0 版本的特性数据后,使用 2.0 版本格式保存是没有问题的,但使用 1.0 格式保存时可能会提示客户编写的数据不兼容 1.0 版本的保存格式(此时客户已经在软件上奋战了半个小时,最后却可能无法保存)。总之后面这个版本的转换又使用了两个星期的时间,而且也不是很好用,整个项目的耗时是四周。
现在,就职于 Well-Tempered Software Company(简称 “WellTemperSoft”)的 Rogers 先生,他是著名的不懂变通之人,他 拒绝 在明确规格说明之前编写任何代码。他大概花了 20 分钟设计了一个和 Speedy 相同的向后兼容方案,并编写了一份规格说明,内容非常简单:
- 当使用新版本软件打开旧版本文件时,文件立刻被转换为新版本的格式。
这份规格说明书被发给了客户,客户立刻反馈:“稍等!我们并没有打算让每个人都立刻升级新版软件!”,Rogers 先生进行了一些思考,之后修改了他的规格说明:
- 当使用新版本软件打开旧版本文件时,文件在内存中被改为新格式。当保存文件时,用户可以选择是否将其保存为旧格式。
至此再次花费了 20 分钟。
Rogers 先生的老板是一位面向对象程序员,他看了这个说明书后感觉有些地方不太对,然后提出了一种他建议的架构。
- 将代码拆分成两种接口:V1 和 V2。V1 包括了所有 1.0 版本软件的功能,V2 继承了 V1,添加了新的功能。这样 V1::Save 可以用来保证向上兼容,V2::Save 可以用来存储新的数据。当客户打开 V1 版本的文件而视图使用 V2 版本的新功能时,程序会立刻提醒客户,客户必须选择将文件转换为 V2 版本或者放弃使用 V2 版本的新功能。
这里又花费了 20 分钟。
Rogers 先生感到有点暴躁,因为这种重构需要消耗他 3 周的工时,他自己的方案原本只需要 2 周!但是这个方案确实使用一种优雅的方式解决了所有客户的问题,所以 Rogers 还是这样做了。
最终,Rogers 先生耗时 3 周零 1 小时,Speedy 耗时 4周,而且 Speedy 的代码更糟糕。
这个故事的寓意是,通过编造的例子,你可以证明任何事。emmm,No,我不是这个意思。这个故事的意思是当您使用人类语言描述您的产品时,只需要几分钟的时间您就可以思考多种可能性,修改或改进您的设计。没有人会因为删除文档中的一段话而感到失落,但当您通过编程语言设计您的产品时,这意味着每次您需要花费数周的时间来迭代设计。更糟糕的是,往往一个只花了两周时间编写代码的程序员会非常执着于他的代码,无论代码有多么糟糕。不管 Speedy 的老板或者客户说什么都没办法说服她丢掉她的转换器代码,即使那些代码被设计的很糟糕。最终导致的结果就是,交付的产品往往是最初的错误设计和后续的理想设计中间的折中方案,最后就是“这是我们能做到的最好方案,因为我们不能丢掉我们的老代码”,这显然不如“这就是我们最好的方案,句号”。
以上,就是需要写规格说明的第一个原因。第二个原因是规格说明有助于节约沟通时间,当您编写了一份规格说明,您只需要写一次文档,表述程序如何正确的工作。随后团队中的每个人都可以阅读这份规格说明,QA 同事阅读后了解了程序预期中应该如何工作以及如何测试程序;市场同事阅读后可以编写一些模糊的产品白皮书并发布到网站上;商务开发同事误读了它,对这个产品如何治疗秃头、疣之类的东西产生了奇怪的幻想,但他吸引了投资者,所以没关系;程序员同事阅读后了解了代码应该怎么写;客户阅读了以后知道了我们正在创造一个他们会愿意付款的产品;文档哥(反正就是团队里负责写技术文档的人)阅读后会去写一篇漂亮的手册(最后会丢掉或者扔掉,但那就是 另一个故事 了);经理们阅读后可以在管理会议上假装自己对一切了如指掌;诸如此类。
而当您没有编写规格说明时,这些沟通仍然会发生,但他们是多次偶发的。QA 同事随意的探索程序,当程序看起来有点怪时,他们就会跑过来 一次又一次 的打断程序员并且 一遍又一遍 的询问一些关于程序预期运行状态的愚蠢问题。这除了会 破坏程序员的生产力 外,程序员还倾向于给出符合他们代码预期的答案,而非“正确答案”。因此 QA 实际上是在依据程序来测试程序,而非依据设计来测试程序,这显然不太靠谱。
当您没有编写规格说明时,可怜的文档哥的遭遇是最好笑的(以一种悲伤的方式)。文档哥一般不被允许打断程序员的工作,在很多公司里,如果文档哥养成了打断程序员的工作去问问题的习惯,程序员就会跑去找他们的经理哭诉说都是因为[脏话删除]的文档哥打断工作,搞得他根本没法完成任务,经理出于对项目进度的考虑,只能命令文档哥 再也不要 去打扰那些程序员的 宝贵 时间。您可以轻松的识别出这种公司,因为他们的帮助文件和用户手册中提供的信息并不会比您在软件屏幕上自己看到的多。比如当您在屏幕上看到这样一条消息:
- 是否开启 LRF-1914 支持?
… 然后您就点击 “帮助”,随后弹出一个可悲又可笑的帮助内容,比如:
- 允许您选择开启 LRF-1914 支持(默认)或是关闭 LRF-1914 支持。如果您希望开启 LRF-1914 支持,请点击 YES 或是输入 Y,如果您不希望开始 LRF-1914 支持,请点击 No 或是输入 N。
emmm,感谢帮助,但是此处文档哥想要掩盖他其实并不了解 LRF-1914 的意图太明显了。他们也没办法跑去问程序员,因为:(a)他们很内向,或者(b)程序员在海得拉巴然后文档哥在伦敦,或者(c)他们被禁止打扰程序员的工作,当然或者是由于各种各样的公司病,不胜枚举,但是最最根本的问题是 没有规格说明书。
需要编写规格说明的第三个原因是,如果没有详细的规格说明,那么就不可能制作项目进度表。如果您是在读博士或者是想花 14 年时间来成就某些事情的话,那么不做项目进度表也无所谓(或者说您正在开发《毁灭公爵》续作,“we’ll ship when we’re good and ready”)。但是对于几乎所有现实中的生意来说,您就是需要知道事情需要多少时间,因为开发项目需要花钱。您不可能在不问价格的情况下去买牛仔裤,那么又怎么可能在不知道产品需要多少开发时间,或者说不知道需要投入多少钱的情况下,去做一个可靠的商业决策?关于项目进度表的更多信息,可以阅读 Painless Software Schedules。
一个常见的错误是在设计阶段对一件事情进行讨论,但 永远得不到结论。Windows 2000 的开发领导人 Brian Valentine 有一句出名的 座右铭,“Decisions in 10 minutes or less, or the next one is free”(必须在 10 分钟内做出决定)。
在太多太多的编程组织中,每当出现了关于设计的争执,通常是处于政治的原因,没有人能够做出定论,因此程序员只能先去做没有争议的工作。随着时间的推移,所有的艰难选择都被留在了最后,这种项目是 最可能失败 的项目。如果您在围绕着某种新技术创建了一家新公司,而且您发现您的公司很难以做出决策,您最好尽早关门,把钱还给投资者,因为您最终无法交付任何产品。
编写规格说明是给这些争议(无论大小)下定论的最好方法,如果您不编写规格说明,有些争议甚至无法被发现。即使是细枝末节的决定也可以通过文档来规范。例如,如果您在创建一个会员制的 web 系统,您一定会赞成在用户忘记密码时可以通过邮件找回。很好,但是这些不足以支撑代码,为了编写代码,您甚至必须精确到邮件中的文本内容。在大多数公司里,程序员并不会被赋予撰写用户可见文本信息的任务 (这通常也是合理的)。因此,产品文案通常需要由市场营销人员、公关人员或其他擅长英语表达的人员来完成。“亲爱的用户,这里是您丢失的密码,以后请别这么粗心了。”当您开始强迫自己编写一个明确且全面的规格说明(关于这个,随后我会聊很多)时,您会注意到所有的这些细节,要么您会解决他们,要么至少打一个大大的红标。
好的,我们现在达成共识了。规格说明就像美国苹果饼一样,人人爱吃。我相信大多数人都理解这一点,我的一番抱怨虽然有趣,但并没有教给你任何新知识。那么为什么人们不写规格说明呢?这并不是为了节省时间,因为这并不能节省时间,而且我认为大多数程序员其实心里有数。(在大多数组织中,唯一存在的“规格说明”都是程序员在编写代码并向三百个人解释该功能之后,用记事本敲出的一段简短的文本。)
我认为本质原因就是大多数人讨厌写作,在一片空白的屏幕上从头开始码字会让人感到沮丧。就我个人来说,我是通过在大学里参加了每周需要提交 3-5 页论文的课程克服了我对写作的恐惧。写作就像是肌肉训练,您写的越多,您的写作能力就会越强。如果您需要去写规格说明但是您没有这方面的能力,开始写日记,开始写 weblog,报一个创意写作班,或者给您已经四年没联系过的大学室友写一封信。任何需要将文字写到纸上的事情都能提升您写规格说明的水平。如果您是软件开发部门经理,然后您手下的小弟对于写文档一窍不通,您可以把他们送去参加两个星期的封闭式写作训练营。
如果您在一家从来不写功能规格说明书的公司工作,也许您确实没见过功能规格说明书长什么样。在本系列的下一章中,我会给您展示一个简短的功能规格说明书,并且和您一起探讨一个好的功能规格说明书的写作要点。继续阅读!