构建软件项目最难的部分不是编码而是需求 [译]
Jared Toporek
AI 想要替代程序员谈何容易。
随着越来越多的 AI 最新成果的新闻报道,很多人觉得 AI 很快就能取代我们这些程序员,他们觉得未来管理层和产品经理可以直接绕过程序员,让 AI 直接开发出他们想要的产品。作为一名有 15 年工作经验,日常就是根据这些人的要求构建软件的程序员,我对这种担忧其实并不太认同。
编码固然充满挑战,但我从未花费过两周以上的时间来解决代码问题。一旦你熟悉了编程语法、逻辑和技术,编码大体上是个直接明了的过程。真正的难题通常在于软件应该完成什么任务。软件构建真正的难点不在于编写代码,而在于定义需求,而这些需求仍然需要人类来确定。
本文将讨论软件需求与软件构建之间的关系,以及 AI 实现优秀成果所需的关键因素。
这不是漏洞,而是特性……不对,等等,其实是个漏洞
在我软件事业初期,我被调入一个项目中,目的是提升团队的工作效率。该软件的主要功能是在电商网站上配置定制产品。
我的任务是编写能够根据购买的产品类型和客户所在的美国州(出于法律要求)变化的条款和条件。
有一次,我以为我发现了一个潜在的问题。用户可以选择一个产品类型并生成相应的条款和条件,但随着工作流程的推进,系统还允许用户选择另一种产品类型和预设的条款和条件。这违反了商业需求中明确约定的一个特性,而且客户还签字确认了。
我天真地向客户提出了一个问题:“我是否需要移除允许用户改变正确条款和条件的输入选项?”我至今还记得我得到的回答。他那充满自信的确切回答是:
“那绝不会发生”
他是一位在公司工作多年、熟悉公司业务流程、被指定监管软件项目的高级执行官。正是这位执行官明确要求保留修改默认条款和条件的功能。我一个初出茅庐的小职员,怎敢质疑这位高管,尤其是他所在的公司还是我们的客户?我不以为意,很快就把这件事抛之脑后。
数月后,就在软件即将上线前的几周,客户端的测试员发现了一个漏洞,而处理这个问题的任务落到了我头上。当我看到这个漏洞的细节时,我忍不住笑了出来。
我曾担心的修改默认条款和条件的问题,就是我被告知永远不会发生的事情,现在竟然真的发生了。而且,猜猜是谁被归咎,又是谁被要求解决这个问题?
尽管修复这个漏洞相对简单,且带来的影响不大,但这次经历成为了我职业生涯中反复遇到的一个主题。我与许多软件工程师同行交流后发现,这样的问题并非我独有。问题变得越来越复杂,更难解决,代价也越来越高,但问题的根源通常是相同的:需求不明确、矛盾或错误。
当前的 AI:对比国际象棋与自动驾驶汽车
人工智能这个概念已经出现很久了,近年来的重大进展引起了媒体和国会的关注。在某些领域,人工智能已经取得了显著成就,比如国际象棋。
早在 1980 年代,人工智能就开始应用于国际象棋。现在普遍认为,人工智能在国际象棋上的表现已经超过了人类。这并不奇怪,因为国际象棋的游戏规则是固定的(尽管这个游戏还没有被彻底“解决”)。
国际象棋的游戏始终是 32 个棋子在 64 个方格上进行,有着官方认可的明确规则,最关键的是有一个明确的胜利目标。在每一轮中,棋手可以选择的走法是有限的。下国际象棋就是按照规则进行决策。人工智能系统能够计算每一步棋的后果,从而选择最有可能夺取对方棋子或获得有利位置的走法,最终赢得比赛。
自动驾驶汽车则是另一个人工智能活跃应用的领域。制造商们长期以来一直在承诺推出自动驾驶汽车。虽然一些车型具备自动驾驶的功能,但还存在一些限制。在许多情况下,汽车需要司机的积极监控;驾驶员可能需要双手握紧方向盘,自动驾驶功能并非完全自主。
就像下国际象棋的人工智能程序一样,自动驾驶汽车主要依赖基于规则的系统来做出决策。但与国际象棋不同,自动驾驶中的每一种可能遇到的情况并没有一个明确的规则指导。司机在行驶过程中需要做出成千上万个小判断,比如避开行人、绕过双排停放的车辆以及在繁忙的路口转弯。做出正确的判断意味着是安全到达商场还是医院的关键所在。
在技术领域,常见的标准是五九甚至六九的可用性——即一个网站或服务在 99.999%(或 99.9999%)的时间内保持可用。实现最初的 99% 可用性的成本并不高,这意味着你的网站或服务每年可以停机超过三天,即 87.6 小时。然而,每增加一个 9,达成这一目标的成本就会呈指数级增长。当达到 99.9999% 时,每年的停机时间只能允许 31.5 秒。这就需要更多的规划和努力,当然成本也更高。获得最初的 99% 可能并不容易,但与最后的那一小部分相比,它在比例上更容易实现,也更经济。
一年有 525,600 分钟(365 天 × 24 小时 × 60 分钟)
99% 可用性 -> 每年停机 5256 分钟,即 87.6 小时 99.9% 可用性 -> 每年停机 526 分钟,即 8.76 小时 99.99% 可用性 -> 每年停机 52 分钟,不到 1 小时 99.999% 可用性 -> 每年停机 5.2 分钟 99.9999% 可用性 -> 每年停机大约 31.5 秒
无论人工智能(AI)离足够好还有多远,事故和致命风险总是存在的。这些风险和后果在人类驾驶背后每天都在发生。我不确定政府会接受什么比例的事故和死亡率,但至少它应该和人类驾驶一样好。
之所以难以达到可以接受的安全水平,是因为驾驶汽车涉及的变量比棋盘游戏要多得多,而且这些变量是无限的。前 95% 或 99% 的情况可能相对容易预测和处理。然而,在达到 99% 之后,会出现许多边缘情况(edge cases),尽管每个情况可能有一些共同特点,但每个都是独一无二的,例如其他人驾驶的车辆、道路封闭、施工、事故、天气事件等。想想看,你有多少次在道路重新铺设后,道路上的分割线还未画好时驾驶。对 AI 模型来说,要能识别这些异常和边缘情况,并且更重要的是,如何适当地作出反应以避免事故,无疑是一个巨大的挑战。每个边缘情况可能有一些共性,但很少完全相同,这使得 AI 更难以确定正确的应对方式。
AI 无法创造软件,只能编写代码
创造和维护软件的过程更像是驾驶而非下棋。它涉及的变数更多,其规则基于主观判断。在构建软件时,虽然有期望结果,但这结果往往不像棋局那样单一明确。软件是不断进化的;不断增加新功能,修复漏洞;它是一个持续的过程。与之相反,一盘棋的胜负一旦确定,游戏就宣告结束。
在软件开发中,我们有一个工具可以让软件设计更接近棋类的严格规则:技术规格 (technical specifications)。在最佳状态下,这些规格会详细描述用户的预期行为和程序的运作流程。例如,用户如何在线购买三明治:点击这个按钮,建立这个数据结构,启动这个服务。但实际情况往往不这么理想。我们经常接到的是功能清单、草图设计和模糊的需求文档,然后被告知要自己做出最佳判断。
更糟糕的是,需求常常会变更或被忽略。最近,我被要求帮助一个团队开发一个能够提供 COVID-19 健康信息的应用程序。这个应用将服务于一个无法稳定接入 WIFI 的地区。团队希望我帮忙开发一个通过短信进行调查的应用程序。起初,我对此感到很兴奋。
但当我开始了解团队的具体需求时,我意识到这将是一个挑战。对于零售公司来说,通过简单的量表(如 1-10 分)询问顾客再次光临的可能性是容易的。但要通过多个步骤和选择题来调查 COVID 感染的症状就复杂得多。我虽然没有直接拒绝,但我确实指出了这个过程中所有可能的问题,并希望团队能清晰定义我们如何处理各种问题的答案。例如,是否以逗号分隔的数字来对应每个答案?如果提交的答案不符合任何给定选项,又该如何处理?
经过一系列的讨论后,团队也达成了相同的结论。我们决定最好不要继续这个项目。虽然听起来令人难以置信,但我认为这其实是一个成功的结果。如果在没有明确解决所有潜在错误的方案下贸然开始,面对无效用户数据时,将会造成更大的浪费。
人工智能 (AI) 用于软件开发的核心思想,真的只是让利益相关者直接通过计算机创建基于短信的调查问卷吗?AI 能否深入提问,处理通过短信收集调查数据时可能遇到的各种问题?能否预见并解决人类在此过程中可能犯下的错误?
要从 AI 中得到一个实用的软件产品,你需要清楚地知道自己的需求,并能精确地定义它。我在为自己编写软件时,有时直到开始编程才意识到其中的难题和挑战。
过去十年里,软件行业从瀑布模型转向了敏捷开发。瀑布模型要求在编码前就明确定义需求,而敏捷则提供了足够的灵活性,让开发过程中可以进行调整。
许多采用瀑布模型的软件项目失败了,原因在于利益相关者以为自己清楚地知道需求,并能准确描述和记录,但最终却对交付的产品大失所望。敏捷软件开发旨在解决这一问题。
AI 可能最适合的是重写现有软件,使其适应新硬件或更现代的编程语言。许多机构仍在使用 COBOL 编写的软件,但学习这门语言的程序员日益减少。如果你对需求非常明确,或许可以用 AI 来更快、更经济地开发软件。我认为,AI 在重建已有软件方面可以比人类程序员更高效,因为有人已经明确了那些软件的功能。
AI 在采用瀑布模型开发软件方面可能做得不错,这个模型有时也被称为“死亡长征”。而我们人类在瀑布模型中的表现并不理想。这并非因为编码阶段的问题,而是在此之前的所有准备工作。AI 能做出许多惊人之举,但它无法读心,也不能告诉你应该追求什么目标。