10 月,开发者不可错过的开源大数据大会-2021 WeDataSphere 社区大会深圳站 了解详情
写点什么

关于测试和恢复性的争论:面向对象 vs. 函数式编程

2008 年 3 月 07 日

Michael Feathers 最近的博文在博客社区引发了一场异常激烈的论战。Feathers 发表言论说一些面向对象编程语言的内嵌特性有助于测试的进行,并且使用面向对象编程语言编写的代码更容易恢复

他举了这样一个例子,class X 有一个叫作 badMethod 的方法,这个方法处理一些“痛苦”的工作,比如调用并更新产品数据库、或者处理一些甚至关系到底层硬件的事务:

<pre goog_docs_charindex="352">public class X {<br></br> public void method() {<br></br> ...<br></br> badMethod();<br></br> ...<br></br> }<br></br> ...<br></br>}<br></br>

理想的设计是,系统可以允许独立测试一般的类和类组。但如果这个例子没有实现这样的设计,“badMethod 是个非 final,可覆写的方法”的事实就有利于为获得“测试足够的机动性”提供所需的灵活性,因为它允许“覆写功能并为我们创建一个楔子来让测试变得更简单”: > public class TestableX extends X { void badMethod() { // do nothing } }

Feathers 称之为一个 seam(接缝),“一个你无须修改便能使用一个功能替代另一个功能的地方”。他相信 OO 语言提供的缓绑定技术使得其本身比函数式语言的恢复更为友好。

一些评论者,包括 Feathers 本人在内,都强调了大多数语言都能提供 seam 的事实:预处理器、继承/多态性和委派、宏和函数指针、高阶函数、动态函数、一等函数、模块边界或 monads。。。。。。其中一些人认为,真正关系到可测试性的是底层设计而非编程语言的选择。比如 John,他断言,无论使用何种语言,“代码的结构需要首先考虑到简化单元测试。”另一位博客 Andrew,强调说如果“代码的结构没有向所需的测试看齐的话”,那么实现将不得不向顺应测试的方向,做相应的修改。因此,他也评论说“关于‘seam’的想法确确实实是瞄准了为实现可测试性而进行恰当设计的底层问题”,也就是说,适当地布置 seam。

针对这些争论,Feathers 强调说,尽管大部分语言都拥有 seam,但关键在于哪种语言用起来更为顺手,尤其是在代码未能以方便测试的方式而设计的情况下:

我同意“针对测试来设计”是真正的重点所在,但我也知道无论我们做什么,总会有一些系统没有以这样的方式来设计。也正是因为这个原因,我非常在乎可恢复性。

[…]

我知道设计 seams 是可能的,但那不是问题所在。真正的问题在于在它们没有被加入进设计的情况下,而适当布置它们到底有多简单。

[…]

当然,seams 也不总是与你所想要实现的测试粒度相一致,毋庸置疑的是,在对 seam 具有良好支持的语言中,要实现与测试粒度相一致会简单得多,因为 seam 已经存在那里,也因为它创建新的 seam 更为简单。

根据 Feathers 所述,尽管在函数式语言中可以采用其他模型来达到同样的目的,但“这是沉重的”,但 Haskell 例外。在 Haskell 中,“大部分你想在测试中避免的代码,都可以采用 monad 来实现”。

尽管 Feathers 着重指出,他知道人们会辩论说“纯函数式可以满足任何单元测试的需求”,但仍然有许多评论者强力辩论说他没有考虑到函数式语言的细节,以及函数式语言所能提供的机会。Erikd 表达了这样一种感觉,他觉得 Feathers 是在将 Java 构造器和惯用方法运用到函数式代码中去。

首先,他看上去是在使用 Ocaml 文法编写 Java 代码,然后又抱怨说 Ocaml 不够像 Java。他的结论一点都不惊人。Ocaml 不是为了编写类似 Java 这样面向对象的代码而设计的,就是这么简单。

其次,他声称使用函数式语言比 Java 困难。虽然使用 Ocaml 文法编写 Java 代码可能确实很难,但是编写一般的 Ocaml 代码或函数式代码就不会那么困难了。

很多函数式语言的拥护者强调说,在函数式编程中,是没有副作用的,并且据 Greg M. 所说,这点可以预防写出需要重构的代码,而且可以将测试变得更为简单:

函数式语言可以让你将代码结构在顶层就将所有讨厌的事务分离开来,并且保持代码的纯逻辑。

[…]

当你的单元拥有完全独立的保障时,单元测试可以变得如此简单!或者说,最差也能保证清楚和明显的依赖性。

Robert Goldman 也发表辩论说“常规的面向对象编程语言中过度采用的状态对测试来说很不利”,因为人们需要“创建巨大的互相关联的对象实体,才能为测试提供平台。而且,检验预期的副作用的过程可能会导致额外的复杂性”。相反,“在类似于 Haskell 这样的纯函数式框架中,所有这些问题都被封装在 Monad 中”。正如 Greg Monads 提出的那样,它可以允许编写“一段(凭空)创建 IO 命令流的代码,以及另一段代码来利用这个 IO 流,并且决定如何执行这些命令”。

与 Greg 来自同一个阵营的 Ericd 坚持认为,在函数式编程中没有内部状态,所以也就没有状态变化的处理。如果要测试“一个没有状态转变的模型或系统”,人们根本不需要 Feathers 谈到的那种测试:

剩下所需的唯一测试是收集一组输入来测试所有边界条件,将这些输入传递给待测函数,然后验证其输出就可。

[…]

如果组件可以被分离测试(也就是纯函数)并且测试结果表明函数是正确的话,那么这些纯函数的组合理所当然也是正确的。

Feathers 对此回答说,他“非常理解纯函数式,并且也知道拥有好的设计的代码自然不该有这些问题”。他强调,并不是所有的代码都有好的设计,而且,“Haskell 的确是迫使你将副作用隔离开来的函数式编程语言的一种,然而其他一些语言,比如 OCaml 或 Scala,“它们看起来无法避免人们将代码搞得乱七八糟”。

无论如何,很多不同意 Feathers 看法的争论者认为,将函数式代码搞得乱七八糟的唯一方式就是在使用函数式语言时采用非函数式用法。Goldman 断言,拥有副作用的程序“被公认为是像 ML、Ocaml 和 Common Lisp 这样的混合性语言的非函数式部分”,显然是要避免使用的。Greg 同样支持这个观点,他表示,除非人们非要和函数式语言作对,以非函数式用法的方式来编写代码,那自然也就没办法“得到你本可以从权威的 OO 代码中‘得到’的 IoC 和分离关注点。”这也是为什么 Erikd 坚持认为,有 OO 技术背景的人想要使用函数式语言编写高质量代码的话,就必须抛弃“旧习和思考方式”,尽可能长时间地忘却“面向对象和专断的编程特性”。

查看原文: Debate about Testing and Recoverability: Object Oriented vs. Functional Programming Languages

2008 年 3 月 07 日 09:53888
用户头像

发布了 71 篇内容, 共 17.2 次阅读, 收获喜欢 3 次。

关注

评论

发布
暂无评论
发现更多内容

别困惑,不是你的错!90%的开发者把Clubhouse看成了Clickhouse

京东科技开发者

Clickhouse 社交 clubhouse

红信圈系统开发,红信圈APP开发

luluhulian

我认为的互联网医疗场景用户及场景

卢嘉敏

需求 医疗 用户

LeetCode题解:153. 寻找旋转排序数组中的最小值,二分查找,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

交易所搭建

v16629866266

交易所开发

2021年人工智能数据采集标注行业四大趋势预测;清华提出深度对齐聚类用于新意图发现

京东科技开发者

人工智能 数字货币

第四次作业

Geek_79e983

京东科技集团21篇论文高票入选国际顶会AAAI 2021

京东科技开发者

机器学习 AI

流媒体传输协议之 RTP (上篇)

阿里云视频云

音视频 流媒体 rtp

自动驾驶“绝地求生”结束了,但深兰的造车故事才刚刚开始

脑极体

架构的变迁,从分层架构先聊起

华为云开发者社区

架构 软件 分层架构 架构师 系统

产品0期 - 第四周作业

曾烧麦

产品训练营

极客时间APP购买课程模块用例文档

夏天的风

用例图

产品0期 - 第四周作业 - 附件1

曾烧麦

产品训练营

作业 - 第四周

eva

Web页面制作基础

魔王哪吒

学习 程序员 面试 前端 二月春节不断更

有了这个算法,图像上文字擦除再也用不上PS了

华为云开发者社区

深度学习 算法 GAN 文字擦除 图像

【新春特辑】发压岁钱、看贺岁片、AI写春联……华为云社区给大家拜年了

华为云开发者社区

华为云

WEEK4作业

Geek_6a8931

话题讨论 | 你选择去一线城市还是老家的省会城市?

石云升

话题讨论 职业发展 2月春节不断更

JVM调优艺术:JVM内存管理机制深度剖析

程序员小毕

Java 程序员 面试 性能优化 JVM

惊呆,一条sql竟然让oracle奔溃了

程序员jinjunzhu

oracle mybatis 批量操作

当自动驾驶遇到5G,会擦出怎样的火花?这篇文章说明白了

华为云开发者社区

人工智能 自动驾驶 5G 通用AI

Vue开发中可以使用的ES6新特征

devpoint

Vue ES6

4. 列表一学完,Python 会一半,滚雪球学 Python

梦想橡皮擦

python 爬虫 Python Monad 2月春节不断更

我的2020年学习总结

兆熊

学习 总结

说说Golang goroutine并发那些事儿

华为云开发者社区

Go 线程 进程 并发 goroutines

互联网医疗里,用户需要的是什么

卢嘉敏

需求 医疗 用户

【STM32】GPIO输入—按键检测

AXYZdong

硬件 stm32 2月春节不断更

Elasticsearch Mapping

escray

elastic 七日更 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

一个只会写Bug的Coder年终总结

z小赵

程序员 互联网 职场成长

关于测试和恢复性的争论:面向对象vs.函数式编程-InfoQ