写点什么

测试驱动开发与遗留代码的问题

  • 2009-11-21
  • 本文字数:1633 字

    阅读完需:约 5 分钟

Allan Baljeu 试图在他庞大的、C++ 遗留代码库中使用 TDD,结果遇到了很大的麻烦,因为:

我们后来得到的类不能完全实现希望其具备的功能,当有人使用这些类时,会想要得到更加完整的实现,然而却会发现原有的设计不够完善,要进行新的设计,有些期望(测试)要做出改变,而之前对这些类的使用也得调整。

他在思考前期大规模设计(BDUF)也许有助于解决这个问题。 George Dinwiddie 敏捷教练,他认为Alan 的设计是在试图告诉他些什么。人们必须要注意“干净代码(clean code)”的基本原则,要注意基本的内聚和耦合性方面的问题(比如 SOLID 原则)。

Mike “Geepaw” Hill 也是 Agile Coach ,他提到:在他指导敏捷团队的这些年来,下列原因之一可能是类似问题的根本原因:

  • 团队在重构方面做得不够,因此你的类没有做到最小化。
  • 团队在“尽量简单”方面的技能还不够,同样如此。
  • 团队还没有采取具备侵略性和快速度的微测试(microtesting,也就是 **单元测试),所以改变常常会破坏测试 **
  • 团队不知道如何处理跨团队、或是公司对公众之间的依赖,比如公布 API 的情况
  • 团队既没有结对,也没有在开放空间中工作,这极大降低了团队层面的知识理解和传递
  • 团队似乎没有具备快速构建的能力
  • 团队可能还在使用老古董级别的工具

Keith Ray 极限编程教练,他提出:有了遗留代码(也就是欠下很高技术债的系统),实现一个故事的成本完全取决于偿还技术债的成本。接下来,他提出一种解决方式:

要让代码的结构更好(偿还技术债务),不管什么时候,当你需要集成一个新功能时,你应该同时注意新旧代码中的异味,并在发现异味时,马上重构,消除异味。 你可以手工采取小而安全的步骤进行重构(即使使用 C++)。要紧跟 Martin Fowler《重构》一书中的步骤,除非你能做到得心应手。带有 gcc 的 Eclipse 有些重构功能可以使用:“抽取方法”和“重命名”。“重命名”能够知道命名所在的范围,所以要比查找和替换更为安全。“抽取方法”和其他的重构功能可能有 bug,使用它们的时候要小心。像改变函数签名这样的东西,“依靠编译器”能够展示出哪里需要改变。

你还需要测试来保证没有破坏现有功能。Michael Feather 的《修改代码的艺术》提供了很多向遗留代码中加入测试的技巧。从更高层面来看,代码异味是破坏优秀设计原则的表现。举例而言:单一职责原则(SRP)认为:每个类、方法、模块只应该有一个意图。还有些原则是与耦合、内聚和管理依赖关系相关的。相比使用这些抽象原则,发现代码异味常常更为容易。“大类”和“大方法”可以通过“抽取类”和“抽取方法 / 移动方法”修改,不过知道 SRP 有助于判断抽取类或方法的哪一部分。

也许“告知,不要询问”是最重要的设计原则:不要分离功能和数据……恶劣的代码常常把功能实现放在一个地方,从其他地方得到需要的数据,这就造成了依赖性方面的问题,同时代码缺少局部性(locality)。其症状就是:“添加一个新功能,要修改多处代码。”代码异味“散弹枪式手术”、“依恋情结”、“参数列表过长”都是这样造成的。

尽快得到反馈能带来更多重构,这最终将会加快新功能的开发。尝试进行并行构建(分布式编译),尝试让源代码文件和头文件更小,降低头文件的复杂度——可使用前向声明、避免内联代码、尝试让每个类只有一个头文件 / 源代码文件。大量使用“指向实现的指针(pimpl idiom)”能降低 10% 的编译时间,但是也可能把“大类”和“依恋情结”这样的代码异味给隐蔽起来。

重构要比重写更好,其优势在于:你总是有可工作的代码。如果你的手工和自动化测试都很好,那你就可以交付代码了,即使目前的状态处于“优秀设计”和“恶劣设计”之间。

Keith 还写了“ Refactoring: Small Steps Guaranteed to Help You Clean Up Your Code ”,该文章发表于 Better Software Magazine,讲述如何重构 C++ 代码。

InfoQ 之前的相关内容:《如何处理遗留代码》《Bob 大叔谈测试驱动开发的适用性》《如何坚持TDD:使用者出现的问题以及解决方案》

查看英文原文: Test Driven Development and the Trouble with Legacy Code

2009-11-21 05:312192
用户头像

发布了 479 篇内容, 共 178.1 次阅读, 收获喜欢 53 次。

关注

评论

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

面试官问:JS的this指向

若川

JavaScript 前端 前端开发

毕业总结

小虾米

「架构实战营」

SpringCloud - Ribbon核心源码解析

码农参上

微服务 SpringCloud spring 源码

模块化开发

Jason199

js 模块化 6月月更

声网 VQA:将实时互动中未知的视频画质用户主观体验变可知

声网

人工智能 音视频

Prometheus 2.35.0 新特性

耳东@Erdong

release Prometheus 6月月更

Ubuntu下安装OpenJDK10

程序员欣宸

Java Openjdk 6月月更

设计电商秒杀系统

小虾米

「架构实战营」

SpringCloud - Feign核心源码解析

码农参上

微服务 SpringCloud spring 源码

一种跳板机的实现思路

vivo互联网技术

权限 跳板机 PAM机制

去哪儿网(Qunar) DevOps 实践分享

laofo

DevOps cicd 研发效能 持续交付 工程效率

从小到大为何一谈学习就愁眉苦脸

宇宙之一粟

学习 6月月更

直播带货平台包含了直播和娱乐模块,你知道是什么吗?

开源直播系统源码

软件开发 直播带货系统

面对 this 指向丢失,尤雨溪在 Vuex 源码中是怎么处理的

若川

JavaScript Vue 前端 前端开发 vuex

OpenHarmony应用开发之二维码生成器

坚果

鸿蒙 OpenHarmony OpenHarmony 3.1 Release 6月月更

使用 ABAP 操作 Excel 的几种方法

汪子熙

microsoft Excel Office SAP 6月月更

要搞清楚什么是同步,异步,串行,并行,并发,进程,线程,协程

乌龟哥哥

6月月更

Scala 基础 (三):运算符和流程控制

百思不得小赵

scala 大数据 6月月更

在IDEA配置Tomcat你GET到了吗

迷彩

调试 IDEA tomcat构建 开发工具 Web 6月月更

fastposter v2.8.4 发布 电商海报生成器

物有本末

海报生成器 电商海报 海报生成 图片合成

怎样能低成本构建一个电商平台

Geek_99967b

小程序 电商

面试官问:能否模拟实现JS的new操作符

若川

JavaScript 前端 前端开发

JavaScript 对象所有API解析

若川

JavaScript 前端 前端开发

如何系统学习LabVIEW?

不脱发的程序猿

​LabVIEW LabVIEW机器视觉 ​LabVIEW工业控制 ​LabVIEW单片机 ​LabVIEW开发技巧

一种低成本增长私域流量,且维护简单的方法

Geek_99967b

小程序 电商

Fabric.js 笔刷到底怎么用?

德育处主任

canvas 前端可视化 画布 FabricJS 6月月更

如何使用 DataAnt 监控 Apache APISIX

API7.ai 技术团队

后端 监控 APISIX 网关 DataAnt

面试官问:JS的继承

若川

JavaScript 前端 前端开发

COSCon'22 讲师征集令

开源社

开源

【使用Python实现算法】02 原生类型与内置函数

★忆先★

Python 算法题

行业分析| 快对讲,楼宇对讲

anyRTC开发者

音视频 快对讲 语音对讲 视频对讲 楼宇对讲

测试驱动开发与遗留代码的问题_研发效能_Mark Levison_InfoQ精选文章