软件质量的黄金准则

2020 年 8 月 31 日 InfoQ
作者 | Gabriel Gonzalez
译者 | 马可薇
策划 | 万佳

在关于软件质量的相关谈论中,我通常会引用一条经验法则。所以,我决定发帖总结一下。我将其称为“软件质量的黄金准则”,因为它简单明了,并且可以广泛使用。

黄金准则如下:

宁可在 upstream (上游,接近问题的根源层面) 推送补丁,也不要在 downstream (下游,远离问题根源的层面) 解决问题。

我将在本文引用 Haskell 社区和生态系统的例子,进一步解释这个准则对软件工程 tradeoffs 的影响。

免责声明:软件质量的黄金准则不代表你对待他人的黄金准则,反之亦然。

第三方依赖

很多开发者项目都借助于第三方依赖或工具,但他们却很少思考如何修改或改进这些第三方代码。相反,他们更多屈从于旁观者效应。这也就意味着如果一个项目的应用越广泛,那么开发者就会越发理所应当地认为会有人帮助他们解决一切问题。长久以往,这些开发者在面对热门工具中的问题就会熟视无睹。

举例来说,很长一段时间以来,Haskell 不支持访问资料字段的点语法。在 Java 中,如果想要修改嵌套结构资料中的数值,只需要将参照变数串起来,例如:

a.b.c.d.e = 10

但是,在 Haskell 中则是每多一层,每个等号就会重复之前等号的序列并多一个取值用的函数,例如:

a <- a{b=(b a){c=(c (b a)){d=(d (c (b a))){e=10}}}}

Haskell 社区在 downstream 通过各种方式 ,包括 lens 在内的软件包,试图模拟点语法。这种方式有好有坏,好处在于拥有一流的数据访问器,缺点则是不尽如人意的类型推理、错误信息,以及缺乏编辑器对字符完成的支持。直到最近,Neil Mitchell 以及 Shayne Fletcher 才通过 RecordDotSyntax 提案 将这个功能直接 upstream 到语言中,从根本上解决了这个问题。

从“软件质量的黄金准则”角度来看,开发者应当更倾向于直接改进依赖的工具和软件包,即‘upstream 推送补丁’,而非在本地迂回,逃避问题,即‘downstream 绕过问题’。这类 upstream 改进可以直接作用于以下几点:

  • 编辑器 /IDE

  • 命令行 shell

  • 所使用的编程语言

  • 所依赖的软件包

注意,upstream 解决问题的成功率并不是百分之百,尤其是当某些 upstream 不欢迎外界贡献者时,但至少也要尝试下,再说放弃。

类型化 API

函数类型同样可以遵循这个准则。假如有两种方法可以为 head 函数分配一个“安全”(总计)类型,用于获取列表中的第一个值。

第一种方法将错误推到了 downstream:

-- Return the first value wrapped in a `Just` if present, `Nothing` otherwise head :: [a] -> Maybe a

而第二种则将需求推到 upstream:

-- Return the first value of a list, which never fails if the list is `NonEmpty`head :: NonEmpty a -> a

根据黄金准则,后者应当更得人心。第二种方法的head类型签名需要一个非空输入,通过禁止用户提供空列表,从而将修复措施推到了 upstream。更一般地讲, 如果你能践行这条规则的话,最后就会做到让非法状态无法表示。

在上述例子中,前者的head类型签名则是通过返回一个Maybe来绕过可能存在的空列表。这种类型提倡在过程后期捕捉错误,错误不会在第一时间反馈,导致软件质量的降低。而如果想要提升质量,则应当直接在 upstream 中问题的根源那里快速失败,而不是根据 downstream 的问题症状位置间接调试。

社会分工

我是康威定律的坚持拥趸者,根据该定律:

设计系统的架构受制于产生这些设计的组织(广义定义)的沟通结构。—— 马尔文·E·康威

我有时将其解读为“社会分歧导致技术分歧”。

如果社会问题是技术问题的 upstream,那么依据黄金法则,我们应当优先解决根本原因(社会摩擦),而不是试图用技术解决方案掩盖社会分歧。

Haskell 社区内的经典例子,cabal 与堆栈的分歧,源于 FPComplete 与 Cabal 贡献者之间的分歧(根据 Haskell 的 reddit 子版块反馈修正)。由于未能解决 upstream 收费贡献者与开源贡献者之间的摩擦,导致 downstream 需要通过创建并行安装工具这样的技术解决方案来尝试绕开这个问题。如此一来,Haskell 社区分崩离析,导致初次使用的新手一头雾水并且用户体验极差。

这并不意味这 Haskell 社区中的分歧可以得到解决,也许收费贡献者和开源志愿者之间的矛盾是不可调和的,但这个例子仍然说明了未能在源头解决问题对质量的明显影响。

(译注:对国人来说,一个更广为人知的例子是 12306 电子售票系统:12306 问题的 upstream 是春运期间庞大人流量与铁路客运能力之间的供求矛盾,而 downstream 则是 12306 平台本身的数据处理能力和 UI 设计质量。显然,如果前者未能得到缓解甚至恶化,则后者的改进并不会从根本上解决广大旅客购票困难的问题,顶多是消灭频繁的卡顿和崩溃现象,而代之以"平滑"的购票排队体验——简单来说,该排队还是要排的。)

结 语

请注意,软件质量的黄金准则并不是要求你必须在 upstream 解决问题,该准则只是建议,如果其他选项条件相同,那么应当优先选择 upstream 修复。有时,出于其他因素的考量,例如金钱或时间的限制,不得不放弃 upstream 修复。但如果我们希望质量为上,那么还是应当尽量遵守这个准则的。

参考阅读:

http://www.haskellforall.com/2020/07/the-golden-rule-of-software-quality.html


InfoQ 写作平台欢迎所有热爱技术、热爱创作、热爱分享的内容创作者入驻!

还有更多超值活动等你来!

扫描下方二维码

填写申请,成为作者

开启你的创作之路吧~


点个在看少个 bug 👇

登录查看更多
0

相关内容

Haskell 是一种纯函数式编程语言,于 1990 年在编程语言 Miranda 的基础上标准化,并且以 λ 演算为基础发展而来。
专知会员服务
71+阅读 · 2020年9月20日
【2020新书】现代C++初学者指南,301页pdf
专知会员服务
159+阅读 · 2020年7月24日
【微众银行】联邦学习白皮书_v2.0,48页pdf,
专知会员服务
165+阅读 · 2020年4月26日
深度神经网络实时物联网图像处理,241页pdf
专知会员服务
76+阅读 · 2020年3月15日
IBM《人工智能白皮书》(2019版),12页PDF,IBM编
专知会员服务
20+阅读 · 2019年11月8日
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
互联网为什么需要全局唯一ID?
互联网架构师
3+阅读 · 2019年8月30日
MBSE在核工程设计中的应用
科技导报
5+阅读 · 2019年5月23日
从自动化到智能化的 GUI 测试体系 | 活动通知
DevOps时代
7+阅读 · 2019年4月25日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
为什么欧盟呼吁共建 AI 伦理准则?
AI科技评论
3+阅读 · 2018年3月14日
深度学习的GPU:深度学习中使用GPU的经验和建议
数据挖掘入门与实战
11+阅读 · 2018年1月3日
领域应用 | 中医临床术语系统
开放知识图谱
7+阅读 · 2017年9月7日
Arxiv
0+阅读 · 2020年10月15日
VIP会员
相关资讯
在K8S上运行Kafka合适吗?会遇到哪些陷阱?
DBAplus社群
9+阅读 · 2019年9月4日
互联网为什么需要全局唯一ID?
互联网架构师
3+阅读 · 2019年8月30日
MBSE在核工程设计中的应用
科技导报
5+阅读 · 2019年5月23日
从自动化到智能化的 GUI 测试体系 | 活动通知
DevOps时代
7+阅读 · 2019年4月25日
说说我的老同事,前端大神程劭非
余晟以为
17+阅读 · 2019年1月14日
WebAssembly在QQ邮箱中的一次实践
IMWeb前端社区
13+阅读 · 2018年12月19日
为什么欧盟呼吁共建 AI 伦理准则?
AI科技评论
3+阅读 · 2018年3月14日
深度学习的GPU:深度学习中使用GPU的经验和建议
数据挖掘入门与实战
11+阅读 · 2018年1月3日
领域应用 | 中医临床术语系统
开放知识图谱
7+阅读 · 2017年9月7日
Top
微信扫码咨询专知VIP会员