软件开发方法






4.81/5 (35投票s)
年轻人的开发方法指南。
引言
软件方法论关注的是创建软件的过程,而不是技术方面,而是组织方面。在这两篇文章的第一篇中,我将介绍不同类型的方法论。我将从历史角度描述它们,因为了解我们身在何处以及我们将走向何方的一种方法是知道我们从哪里来。
还将有一篇姊妹篇文章,探讨最新的技术进展以及我认为的未来发展方向。这第二篇文章的标题颇具争议,名为“为何说软件开发并非工程”,我将在其中详加解释。在第二篇文章中,我将讨论几种流行的敏捷方法论,特别是它们最重要的方面(例如单元测试),这些方面通常被忽略或一带而过。
在开始之前,我应该提醒读者我喜欢用类比。实际上,整篇文章就是一个巨大的类比,几乎被拉伸到极限。我喜欢类比,因为软件开发中的许多概念都很抽象,难以理解,但使用一个熟悉的现实世界情境,比如打车去酒吧,可以阐明这些思想。当然,类比总是有不完美之处。要仔细理解其中的相似之处和不同之处。
临时
从历史上看,第一种方法论基本上就是没有方法论。这通常被称为“临时”方法论。
我们从一个简单的场景开始。你要去车站酒店与你的朋友吉姆见面。你不知道那里在哪里,但你跳上一辆出租车,告诉司机你要去哪里。几分钟后,你安全抵达目的地,而且没有浪费任何喝酒的时间!
在这个类比中,你就是“客户”,出租车司机就是“开发者”。上面的情况是理想情况,即客户知道自己要去哪里,而开发者知道如何到达那里。不幸的是,现实世界从未如此简单。考虑以下几种变体。
问题
1. 你告诉司机去哪里,但你却到了火车站而不是车站酒店。显然,他听错了,毕竟他的很多乘客都去那里。
你澄清了情况,但出租车司机不爱交流,结果你到了错误的酒店。最终,你发现司机英语说得不好。
过了一会儿,你放弃了。如果你真的坚持,你可能会到达目的地,但那时吉姆已经离开了。
2. 你请出租车司机载你去车站酒店,他立即回答:“哪个?”显然,十英里半径内有三家,你不知道吉姆去了哪一家。你都试了一遍,但没找到吉姆。
司机建议可能是“消防站酒店”,实际上离你出发的地方不远。
3. 出租车司机好心告诉你,目的地很远,你钱不够。他建议你坐公交车。
当然,公交车很慢,而且不会直接开到酒吧门口。你最终还是到达了。
4. 出租车直接载你去了酒店,但酒店关门了。
5. 你半路上意识到你需要寄封信。然后吉姆打来电话说他去了另一家酒店。然后你堵车了,而且还需要上厕所。整个行程比预期的要长得多,也贵得多。
6. 出租车司机似乎知道路,但经验不足,过了一会儿他才意识到自己走错了方向。他不得不几次掉头,但最终还是找到了目的地,只是旅程比预期的要长得多。
我相信你能想到更多可能出错的事情。
摘要
只要问题简单,临时方法论就可以奏效。如果客户确切地知道自己想要什么,开发者知道如何满足他们,并且拥有正确的工具(如必要时的可靠车辆和街道地图),那么成功的机会就很大。然而,大多数时候你会迟到或根本无法到达。
上述场景代表了软件开发中几种常见的问题,即沟通不畅(1),客户不知道自己想要什么(2)或以为自己知道直到尝试后才知道(4),需求变更(5)和开发人员经验不足(6)。我将留给读者自己去解读场景3的含义。
瀑布
好吧,你想避免以上所有问题,但你该怎么做?常识是向专家寻求帮助,有许多乐于助人的人愿意提供服务,当然是要收费的。你会发现你需要一个“分析师”来弄清楚你真正想去哪里,以及一个“设计师”来提供详细、无歧义的路线说明。
分析师通过演绎和/或专家猜测来精确确定你想去哪家“车站酒店”。也许他们甚至设法联系到吉姆来确认位置。他们还会找到确切的地址和营业时间。
现在你确切地知道你想去哪里,但如何到达那里?设计师提供“规范”或路线说明,例如:行驶2英里到环岛,走第三个出口,等等。为了确保司机理解这些说明,重要的部分甚至会被翻译成他的母语。优秀的设计师还可能尝试预见问题并制定应急计划——例如,如果高速公路交通拥堵,就采取另一条替代路线。
规范的关键在于在出发前将行程完整彻底地规划好。所有相关人员都会阅读规范并同意这样就能让客户按时到达酒吧。你看到这种方法有什么问题吗?
当分析师/设计师忙于工作时,你(客户)会感到越来越紧张。已经过去一段时间了,你还没有出发。你也希望得到反馈,一旦行程开始,一切都会按计划进行,因为你的出租车旅行经验告诉你,它们可能非常不可预测,而且司机从不告知他是否迷路或走在正确的路线上。
你需要一个“计划”,这样你就可以检查每个人是否在做好自己的工作,并且如果有什么不对的地方就会立即显现出来。该计划还将要求司机定期报告他的位置,以便你知道他是否会迟到或根本无法到达。对于一个大型项目,你需要一个“项目经理”来制定计划。
问题
这一切听起来非常周全且令人放心,但这种方法存在许多问题。
1. 首先,出租车司机必须在出发前阅读并理解整个规范——例如,他可能需要弄清楚必要时他在哪里可以买到燃油。规范复杂且详细,司机可能需要一段时间才能理解并开始。
2. 出租车司机试图严格遵循规范,但存在一些小歧义,他做出了错误的假设。当他意识到错误时,他已经走了好几英里错误的方向,不得不掉头。
3. 规范中存在一些没有人检查过的关键假设。例如,周五晚上8点以后永远打不到出租车。设计师没有考虑到这一点,但他辩解说这超出了他的职责范围——客户应该知道这一点,因为是他乘坐出租车,而且他签署了规范。
4. 发生了意想不到的事情。例如,意外的交通堵塞导致进展缓慢。
5. 设计师不知道的一些问题。例如,道路施工需要绕行很长一段路。出租车司机知道这件事,但没人问他。
6. 有些问题是所有人都没有意识到的。例如,计划路线是单行道,即使地图上没有标明。
7. 有些事情你(客户)忘了说——例如,你需要在途中去银行取点现金。对你来说这似乎是件小事,但设计师抱怨说这完全使大多数规范无效(当然,他有点夸大)。
8. 发生了没有人能够预料到的意外事件,例如导致交通混乱的重大事故。
9. 出租车司机对这个过程感到恼火和沮丧。“直接告诉我你想去哪里!”
10. 项目计划估计旅程将花费一个小时。乘客立即开始看书或在后座睡着了。出租车司机认为这只需要一半的时间,尤其是因为他知道一条捷径。他磨蹭了一会儿,绕道去处理一些私人事务,然后就失去了时间的概念。乘客醒来,想知道他在哪里——司机向他保证一切都在计划之中。
然而,这时只剩下15分钟了,他几乎没有取得任何进展。他发现他的捷径被封锁了,然后因为超速被罚款。最后,他付出了巨大的努力,才迟到了20分钟。讽刺的是,他因如此敬业而受到所有人的赞扬。
11. 设计师从过去的经验知道出租车司机的能力参差不齐。规范是按照最低标准编写的,即使这会贬低普通出租车司机。
12. 设计师知道出租车司机有偏离规范的倾向。这可能是应乘客的要求(参见上面的第7点),或者他可能会选择风景优美的路线以使旅途更愉快(并增加费用),或者选择一条可能节省时间但风险很大的捷径,或者仅仅是出于个人兴趣而绕道。
为了应对这种情况,设计师会尽量限制提供给司机的_信息,只提供他们需要知道的内容。极端地说,设计师可能会遮住出租车的所有窗户,让司机只能依靠里程表和指南针来导航。显然,这是一种非常危险的方法,因为司机没有任何反馈来纠正哪怕是最小的偏离路线。
13. 你开始了旅程,但有很多问题和延误。你设法联系到吉姆,并安排在他附近的一家酒店见面,这家酒店对你们俩来说实际上更方便。(不幸的是,这完全使规范无效,并被丢弃了。)
摘要
瀑布模型可以奏效,前提是一切都按计划进行,但在复杂项目中,事情很少能一帆风顺。问题的关键在于在尝试实现之前就必须让规范完美无缺。不幸的是,即使你一开始就接近正确,事情也会发生变化。对于大多数现实世界的项目来说,这意味着这种方法注定失败,或者至少导致项目延期且预算超支,以及一段非常令人沮丧的经历。
上述场景代表了瀑布方法论的几种常见问题,即理解(1)和遵循规范(2)的难度以及一开始就制定好规范(3、5、6、7)的难度。该过程无法应对变化(4、8、13),也未能充分利用开发人员(9、11、12)。
一个主要问题是,如果没有明确可交付的里程碑,大多数开发人员会拖延到开始(10)。然而,公平地说,这种行为得到了加强,因为大多数项目在开发开始后很久都会发生重大变更(甚至被取消)。对开发者来说,一开始就努力工作是没有意义的,因为很可能这些努力都会被浪费。
原型
原型方法论解决了瀑布方法论“规范”的主要问题,即直到到达目的地你才确定它是否能奏效。很难或不可能证明规范的正确性,因此我们转而创建一个简单的产品工作示例,就像建筑师会创建一个新建筑的模型一样。
为了继续我们的出租车类比,设计师或其代表骑着摩托车去检查你是否能到达车站酒店,甚至探索一些替代路线。当摩托车司机找到一条好路后,实际的出租车行程就可以开始了。
问题
1. 摩托车不是汽车。它可以避开交通拥堵,或者通过汽车无法通过的狭窄小巷。为了证明行程的可行性,设计师可能草率地忽略了出租车行程需要更长时间的事实。
2. 对你(客户)来说,创建原型似乎是在浪费时间,因为你的行程要等到摩托车到达才能开始。(摩托车在出租车出发前可以出发,但总有找到更好路线的风险,出租车不得不掉头。)
3. 你觉得如果摩托车能这么轻松到达,为什么不直接骑摩托车,而是避免乘坐更昂贵的水上出租车。问题是摩托车旅行可能不那么愉快。此外,摩托车不是为载客设计的,你和你的行李可能导致它不稳定,从而引发事故。
摘要
原型方法论适用于项目在最佳方法或可行性方面有很多未知数的情况。可以快速探索不同的路线并决定最佳路线。然而,如果最佳路线很明显且经常使用,那么创建原型就没有必要了。最终,拥有原型可能并不会让完成项目变得容易多少。
上述场景代表了原型开发中经常遇到的问题:创建最终产品可能比创建原型更困难(1),而且使用原型可能根本没有多大好处(2)。一个主要问题是,一旦客户尝试了软件的可运行原型,就可能倾向于直接使用原型而不是开发完整产品,即使原型在许多非明显方面可能完全不适合(3)。
4GL
这与其说是一种方法论,不如说是一种利用新技术的方法。这种思想在20世纪80年代被大力推广,即开发非常高级的语言,允许用户创建自己的应用程序。这些所谓的“第四代语言”据称足够简单,任何人都可以使用。
在我们的类比中,这就像完全抛弃出租车司机。当然,大多数人(在类比中)不能开出租车,所以我们需要一个简单的系统,让用户只需使用简化的控件。不幸的是,唯一可行的方法是创建一个巨大的引导轨道网络来保持出租车在轨道上。
问题
1. 你坐进出租车,输入目的地,然后收到一条模糊的错误消息。你哪里也去不了。
2. 轨道网络的成本巨大,所以目前它还没有到达很多目的地。
3. 即使你的目的地并不远,你也需要绕远路。
摘要
这个想法很好,但总的来说并不可行。也许有一天,随着人工智能的发展,这种方法可以奏效。
上述问题意味着:技术不够先进(1)且开发成本高昂(2)。实际上,与 Sother 方法相比,产品运行缓慢且笨拙(3),结果总体上不令人满意(2)。
迭代语句
今天敏捷方法论(见下文)的前身可以大致归类为“迭代”方法论。它们也经常被称为“级联”方法,因为它们实际上是一系列小的瀑布。
我将不详细讨论这些,因为它们使用不广泛(名义上除外)或不太成功。它们更多的是试图修复瀑布方法论的问题,而不是完全绕过它们。因此,它们存在许多相同的问题,甚至加剧了一些问题。
敏捷
瀑布方法论的主要问题是前期投入大量的规划、分析和设计工作。当涉及到实际实现时,有太多的变量和未知数,几乎不可能按计划进行。
原型方法论让我们通过展示有合理的成功机会来消除一些不确定性。然而,在实际开发开始之前,仍然有大量的初始工作来设计和构建原型。
如果我们能将项目分解为一系列步骤,以便在每个阶段都能证明我们离最终产品更近一步?在每个步骤之后,我们都会产生一个可用的(但不是最终的)产品,以便客户可以看到项目正在朝着正确的方向前进。
为了继续我们的出租车类比,我们可以立即开始我们的旅程,因为我们知道要到达任何可能的目的地,我们都必须走进城的主路。当遇到不确定的时候,我们就停下来评估情况并选择最佳路径。此外,通过不断重新评估,我们可以适应任何 unforeseen 和新的发展。
表面上看,这与“临时”方法论非常相似,你只需跳上出租车就出发。确实,它赋予了出租车司机再次找到最佳路线的权力,但反馈机制让更多人可以看到正在发生的事情并保持事物按计划进行。
它也不会排除使用额外的团队成员来确保行程顺畅无阻。导航员可以监控交通状况,寻找麻烦点,并尝试找到最佳路线。机械师可以确保出租车始终处于良好状态,不会抛锚。
但是仍然有一些潜在的陷阱需要注意。
问题
1. 你(乘客)确信你知道自己要去哪里,旅途顺利,但当你到达目的地时,却发现其他人认为这不是正确的地方。吉姆不在那里,而在另一家酒店。
2. 旅途正在顺利进行,但当你走到一半时,情况发生了彻底改变——吉姆打电话说他去了相反的方向。旅程已经投入了很多,所以不愿轻易放弃并重新开始——毕竟,那是“瀑布”做事的方式。
3. 直达路线是沿着山坡直接走,然后过旧桥。采用了更慢的路线来减轻风险,因此客户始终能看到目的地。最快的方式是直达路线,但并未被认为是“正确”的方式。
4. 前往目的地有两条同样好的路线,一条从山北面,一条从南面。然而,司机想走一条路,导航员想走另一条路。作为妥协,他们选择了最糟糕的路线——直接翻过山顶。
摘要
敏捷方法论的优势在于开发团队很满意,因为他们不仅被授权驾驶出租车,还可以导航并确保一切顺利。客户也很满意,因为他知道司机没有迷路,即使迟到了,在每个阶段他都知道自己在哪里,并且仍然对何时能到达有一个好想法。
然而,仍有可能出现问题需要注意。一个问题是客户代表并不真正了解“真实”客户的最佳需求(1)。敏捷方法是渐进式的,但有时你无法将现有软件演变成真正需要的东西(2)。对于一个简单、理解透彻的项目,“临时”方法可能仍然更好(3)。最后,集体决策可能并非总是最佳决策(4)。
极权主义
最后,我介绍一种我经历过但从未见过描述的方法论。在很多方面,它类似于敏捷方法论的极端化。客户高度参与开发,发布周期不是几周一次,而是每天甚至更频繁。
这通常发生在客户是一位前出租车司机,并且想要对产品和流程拥有完全的控制权时;因此,我将这种方法论称为“极权主义”。另一种名称可能是“后座司机”。
问题
1. 在每个转弯处,你(乘客)都会检查地图并提出建议,甚至告诉司机他走错了路。出租车司机必须停下来检查,但主要是为了安抚乘客。
2. 由于不断的指示,司机变得困惑,甚至忘记了自己要去哪里。即时方向不断变化。
3. 司机停止思考要去哪里,而是只听从你的指示。你最终走到了一条单行道的死胡同。
摘要
这种方法没有任何优于敏捷方法的优势,而且有很多缺点。首先,与瀑布方法一样,它剥夺了开发者的权力(2、3),对其工作质量和生产力产生了相应的影响。没有明确的目标,也没有像敏捷方法那样在每个冲刺结束时的成就感。
也很难对软件进行任何重大的更改并保持其一致性(1、2)。因此,不应该比每周尝试一次发布新“版本”。开发人员需要时间进行自己的测试,并整合来自不同团队成员的输入。使用这种方法,你可能会浪费时间原地打转,追踪那些最终会“不劳而获”的非问题。
此外,客户需要做大量的测试才能提供每日反馈。反复测试同一件事会变得枯燥乏味,最终客户会变得不那么勤奋,而错误会溜过去。
结论
不幸的是,在开发软件时,变量和未知数比简单的出租车旅行要多得多。在这个奇异的世界里,车站酒店可能不是一个固定的酒店——它可能会移动甚至消失,或者可能存在无数个看起来相同的酒店。道路可能是未绘制的,并且总是在变化。
我还要提到,有些事情可能会出错,这是任何开发方法论都无法涵盖的——车站酒店可能会爆炸,谁知道呢?有交通事故和车辆故障。
我希望这篇文章能让你深入了解不同的软件开发方法论。在我的下一篇文章中,我将探讨最新的技术进展,特别是几种敏捷方法论。我还会强调我认为重要的领域以及未来可能的发展方向。