写点什么

必须移除无用代码

  • 2017-02-14
  • 本文字数:2846 字

    阅读完需:约 9 分钟

Kevlin Henney 指出,需要发现和移除无用代码。对于编程人员理解程序并采取行动而言,无用代码的存在是一种障碍,因为无用代码存在被唤醒的风险,并会导致严重的问题。移除无用代码并非是一个技术问题,而是一种理念上的和文化上的问题。

Kevlin Henney 是一位独立顾问和培训师。他在 2017 年欧洲测试大会上以“我们做事方式中的错误”为题目做了开幕式主题演讲,并在演讲中展示了无用代码的唤醒是如何给企业带来上百万的损失。InfoQ 以问答、总结和文章的形式对大会作全程覆盖报道。

软件故障会对个人造成不便也是十分烦人的,还会产生显著的经济和社会影响。Henny 展示了数个由于细微的软件故障导致上百万损失的例子。

Henney 指出,故障可能源自无用代码。无用代码是存在于系统中的、但并不被认为会再被使用的代码。意外执行这些代码会导致系统严重故障。因此,他建议必须移除无用代码,以避免此类问题的发生。

InfoQ 就如何解决无用代码所导致的问题采访了 Kevlin Henney,并请教他如何处理出错状态和异常。

InfoQ:您谈及被激活的无用代码将会对企业造成巨大损失,能就此解释一下吗?

Kevlin Henney: 2012 年 8 月 1 日纽约股票交易所开盘后,Knight Capital Group 最新的高速算法给出的交易路线错误下单,所产生的交易充斥了整个市场。系统在错误运行大约 45 分钟并完成了 4 亿股交易后才被下线。一切尘埃落定后,所造成的净损失达每分钟一千万美元以上。

这个破产界定事件源自于一场完美风暴(即独立发生时没有危险性但一并发生时会带来灾难性后果的事件组合)。为使新的 NYSE 交易系统按预期在 8 月 1 日上线,公司在服务器上部署了更新。工程师手工更新了服务器,但他们并不知道其中的一次部署失败使旧版本保留运行。在新的 NYSE 交易系统中,他们重用了一个旧标识,但是该停用标识已更改了用途,用于表示另一个意义。虽然该标识在过去的八年中都没有被使用,旧版本代码依然依赖于这个旧标识。

这段已有八年时间处于无用状态的代码由于标识值的更新而被唤醒了。僵尸灾难发生了,只剩下破产一条路。

InfoQ:采取哪些措施本可以避免问题的发生?

Henney:可以说完美风暴中的任何一个贡献因素都是有问题的,但是这些因素的组合被证明会引发更为严重的问题。更改其中任何一个贡献因素都有可能阻止或至少降低损害:

  • 服务器是手工更新的:这是一个迫切需要自动化的任务。
  • 失败的更新并未得到关注:没有人去审查更新。飞机舱门虽然是手工上锁的,但飞行安全是通过机组成员间的交叉验证得以提升。
  • 无用代码并非真的无用,除非确实被移除。他们早在几年前就应该移除那些多余代码。
  • 有时确实是出于十分现实的考虑而将标识、记录等改做他用,而非添加新的。但是如果完全可以添加新的而非回收利用,就应该去添加新的。
  • 企业在处理违规交易系统中缺失了上报流程。通常很难预期能得到准确的交易失败情况,但是如果采用高速交易系统意在实现比交易员更快交易的话,很明显这也会导致金钱更快的损失,因为高速交易系统放大了交易能力。企业应该具有清晰的上报流程,最好是具有一种中止机制(Stop-the-line Culture)。
  • 在发生故障的 45 分钟里,他们在不了解错误原因的情况下将正确的更新进行了回滚。这使得问题更为复杂化,而非解决了问题。一个实时系统不知因何出错,却手忙脚乱地处理,只会让事情变得更糟。不要这样做。
  • 这反映了他们缺少自动化安装,也缺少让系统离线的简单方法。他们应该将“更新”和“紧急停止”都自动化。

InfoQ:对于如何处理无用代码,你有哪些建议?

Henney: 我的建议就是:“找到他们,删除他们。”

“找到他们”是其中最难的部分。有时无用代码真是难以触及,正如静态分析所给出的。静态分析的有效性虽然取决于所使用的工具、语言和架构,但它是一个很好的解决问题的好出发点。

内幕交易在股票交易中被认为是非法操作,但是在代码里使用内幕知识却是完全可被接受的。开发人员可能对超出需求的代码实现已经有了很好的认识。利用产品特性知识也是完全合法的,当在需求层撤回或替换特性时,关联到这些特性的代码可能也终将退役。

另一条可用线索是代码稳定性。你的版本控制系统是一个关于变更的知识库。代码块的哪一部分从未变更过?很多原因导致代码从未变更,例如:代码已经正确的、代码是无用的或者只是不敢于去更改的。除非开展调查,否则你也不知道原因。当然由于自动重构,无用代码可能仍保持被更改的状态,这些更改也有与其他重构更改相关的签名,但并非是修复软件故障或添加特性。

系统的运行时监控并不能明确指出哪一部分代码是无用的,但可以明确指出哪一部分代码是活的。这有助于缩小搜索范围。

简而言之,就是做假设并进行调查。

删除无用代码并非技术问题,而是思维模式和文化上的问题。人们常会感觉代码如果不做一些事情就没有效果,因此将代码遗留下来也是可以的。需要牢记正是出于同一理由,我们应该移除这样的代码。即如果代码不做任何事情,那么移除它。这个原则可以由版本控制系统替你实现。

移除代码出于很多原因,并非仅是因为存在僵尸灾难的可能性。无用代码使得运行时的资源占用大于所需资源。如果你关心的是性能,那么就要考虑移除无用代码。此外,对于编程人员理解问题并采取行动而言,无用代码也是一个障碍。充斥了无用代码的系统浪费了开发人员的时间,妨害了软件文化,导致代码总处于修改和改进状态。

如果你是因为不确定是否为无用代码而不想移除这些代码,这种不确定性其实是说明了你的架构存在的问题以及它与开发人员之间的关系。

InfoQ:你在演讲中也谈到了关于处理错误的代码的问题。处理错误的代码并非无用代码,但是其中的问题常被忽视并遗留下来。对非致命错误的不正确处理是如何导致灾难性失败的?

Henney: 某一部分代码被使用得越多,越可能是发生过缺陷的地方。处理错误的代码通常是系统中最不常被使用的代码,很多错误场景是非常罕见的。因此虽然存在处理各种错误场景的代码,但是代码的正确性并未得到验证。一旦罕见错误场景发生,虽然处理错误的代码在设计上是用于解决错误而非产生新的错误,但是控制流程在导向有问题的执行路径后整个系统就崩溃了。有时毫不夸张的说,就像 1996 年首次阿丽亚娜火箭失败那样。

InfoQ:对于处理出错状态和异常,您能给出哪些建议?

Henney: 我的建议是做审核、静态分析和自动化测试。全面的走查和透彻的讨论有助于找出被疏忽的地方并发现新的问题。你可以从工具中得到一些有用反馈,了解在运行时发生的情况。反馈的内容根据编程语言不同而有所差异。

测试是一种确认在安全环境中执行代码片段的方法,谨记人们在编写处理错误的代码时总会有些盲点和乐观倾向,仅仅去测试正常用例(Happy-Day Scenario)。为解决该问题,时常问一下自己:当发生错误时,相应的处理代码在哪里?对错误条件的测试在哪里?对处理代码的测试在哪里?

查看英文原文: Dead Code Must Be Removed


感谢薛命灯对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-02-14 18:004266
用户头像

发布了 227 篇内容, 共 79.2 次阅读, 收获喜欢 28 次。

关注

评论

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

【uniCloud】云对象的应用与提升

小鑫同学

前端 Node 10月月更

Spring Boot「04」Annotations 01

Samson

Java spring 学习笔记 spring-boot 10月月更

走进“yarn create vite”的源码学习

小鑫同学

前端 Node 10月月更

算法 _【实验5.2】1-深度优先搜索暴力求解旅行商问题

清风莫追

算法 深度优先搜索 10月月更

【实战】自定义 Github Action 库

小鑫同学

前端 Node 10月月更

Spring之注解开发

楠羽

笔记 Spring 框架漏洞 10月月更

Java Lambda 表达式

Yeats_Liao

后端 Java core 10月月更

io的实质

wzh

Linux 面试 后端 io java 编程

read、select、poll、epoll区别

wzh

网络 Linux Kenel epoll IO多路复用 poll

cstdio的源码学习分析10-格式化输入输出函数fprintf整体分析

桑榆

源码刨析 10月月更 C++

利用fs-extra实现"yarn create tlist"创建项目

小鑫同学

前端 Node 10月月更

Babel 插件开发&访问节点

小鑫同学

前端 Node 10月月更

2022-10-12:以下go语言代码输出什么?A:1;B:2;C:panic;D:不能编译。 package main import “fmt“ func main() { m := m

福大大架构师每日一题

golang 福大大 选择题

贤鱼的刷题日常--P1548 [NOIP1997 普及组] 棋盘问题

贤鱼很忙

c++ CSP 10月月更

贤鱼的刷题日常--P2671 [NOIP2015 普及组] 求和

贤鱼很忙

c++ 10月月更 题解

跟着卷卷龙一起学Camera--夜景拍照02

卷卷龙

ISP camera 10月月更

跟着卷卷龙一起学Camera--夜景拍照03

卷卷龙

ISP camera 10月月更

这是我见过的,最好的工作流设计

跟YY哥学Jira

设计 Jira workflow

开发 Babel 插件可以试试这个 CLI 工具

小鑫同学

前端 Node 10月月更

【Serverless】前端上 Ali 云必备指南

小鑫同学

前端 Node 10月月更

微服务与 API有什么区别?

雨果

微服务 数据api

支撑阿里“双十一”的消息中间件,带你云淡风轻面对高并发

图灵教育

RocketMQ 中间件 架构师 消息中间件

跟着卷卷龙一起学Camera--夜景拍照04

卷卷龙

ISP camera 10月月更

数据质量监控,你一直都做错了

雨果

数据质量

内网渗透-IPC$横向控制OA系统【网络安全】

网络安全学海

网络安全 信息安全 渗透测试 内网渗透 漏洞挖掘

干货|什么是特性团队/功能团队(FeatureTeam)

laofo

Scrum 研发效能 PMO 敏捷精益 敏捷研发

【入门】你连Babel都不会配?那插件不成乱装了

小鑫同学

前端 Node 10月月更

【入门教程】Rollup模块打包器整合

小鑫同学

前端 Node 10月月更

【愚公系列】2022年10月 Go教学课程 026-结构体

愚公搬代码

10月月更

Java 序列化与反序列化

Yeats_Liao

后端 Java core 10月月更

支撑阿里“双十一”的消息中间件,带你云淡风轻面对高并发

图灵社区

RocketMQ 中间件 架构师 消息中间件

必须移除无用代码_软件工程_Ben Linders_InfoQ精选文章