文档章节

偿还技术债 - 通过重构拯救老代码(翻译)

fx911
 fx911
发布于 2016/07/21 18:52
字数 4317
阅读 1033
收藏 24

###偿还技术债 - 通过重构拯救老代码

**尝试去接管一个陈旧的代码库使他成为达成一个可控的状态?**这几年的大型的旧web应用程序开发给了我们如下这些建议。

####通过重构去拯救旧代码 松鼠会因为忘记自己把松果放在那里,使得每年多了几千棵松树。类似的,这些事情在项目中都没有什么关系。你的项目是可以被拯救的

**无论代码多么的杂乱,让人疯狂。**但是你的老板让你上了,你要相信不管前路多么曲折坎坷,你总能搞定的!

####心无畏惧

公平的说。比起冲进一个四处鲜血还有巨龙守在门口的沼泽地待几年,你更愿意在一片清新的草原上散步。

不幸的是,你的老板和这片沼泽地的公爵达成了一个协议,派你上了。

不管怎么样,你上了,所要做的就是把这块泥泞的沼泽变成一块美丽的牧场

####技术债 - 它怎么会这样 当你在项目中遇到一个又一个坑的时候,你可能在想:这是哪个“无能”的人做的?有人肯定能预见这个问题,但是为什么不是这样呢。

可能吧,不过更多的时候并不是这样。包括我们自己,很自信的写出的东西可能之后自己也不知道是什么了。

“无能”这个词并不适合解释这种情况。从工作本身的角度解释,它应该叫做“技术债”。

####代码癌

“代码癌”这个东西充斥在各个项目的开发周期内,指的是为了快速解决当下问题采取的临时方案(原文中为“Ugly hacks”)。随着这种只完成了功能但是很难维护的东西的出现,然后技术债就开始越积越多。

然后,一点一点的,项目就开始失控。不经手真正代码的的人根本不会在意这一点,但是,最终,他可能最后落在你的手上。

对于任何项目来说,快速完成需求,推出新的功能都是非常重要的。如果做不到,珍贵的用户就会离开。举个例子,就像是他们宁愿去隔壁泥泞沼泽上的酒吧喝着长岛冰茶,也不会在你花了一整年修剪工整的草坪上傻站着。

所以,就算是一个健康的项目,技术债也一定会产生,但是为了避免代码最终变得无法维护,这种积累的技术债在某些时候一定要解决的。

为了避免让一群疯狂的受害者冲进你的沼泽地找你讨债。作为沼泽地的主人,你可能需要一些**“重构”**:交换一些代码的位置,让他能够更好地维护和拓展。

####说服客户

对于这片泥沼的公爵,你需要告诉他他的土地上正在不断的进入小怪物。因为总有客户想要这样那样的功能。当你面对一个deadline定为一周但是你完成它至少要两周的需求,你需要学会向他解释,让他明白你需要花一点时间来做点小小的重构

如果做不到这一点,可以预见,技术债将不断增加,最后无法收场。

其实你的目的和你的客户是一致的,愉快而顺利的工作,然后大家都能赚钱~ 这个的前提就是需要有一个稳定的项目可以让你从容的写出你的代码。

####争取你的自由

你需要学会如何将情况解释清楚。我觉得最好的办法就是向这片泥沼的主人解释清楚有哪些潜在的风险隐藏在角落里,要让他知道你的好意。你可以试试下面几条建议:

1.解释什么叫做“技术债”,告诉这种债务过高会让开发越来越慢。我们可能需要花费很多时间才能找到问题,而且要花费很多时间去解决它。

2.给出清晰的短期目标和计划,告诉客户你可以选择花一周去实现一个功能,也可以给我吗一周时间重构,然后花一天去完成这个功能。但是第二种方案对于以后的开发有很多好处。

3.告诉客户,其实你们最终的目标是一样的。而且,你们担忧的事情也是类似的。

一旦你和泥沼的主人达成一致,事实上最困难的事情就已经结束了。下面,让我们的项目走上正确的方向吧

####不要再弄出一个新的沼泽地

你可以尝试修复它,不要重写它。

你可能说服了沼泽地的主人,你可以为他创造一个崭新的牧场。你会用更新的工具,更好的方式。但是,听我的,千万不要

重新的风险有很多:

1.这样做就像按下了一个危险的开关,新代码从来没在生产环境下跑过,谁都不知道会发生什么。

2.数据迁移,从旧的系统向新系统迁入和迁出数据很容易出现问题。

3.复刻旧的错误,你开始重写了,就有可能重复旧项目中的问题,旧项目的一些巧妙的特性也会被弄丢。很多问题都发生在系统的一些你本身刚开始就有疑问的地方。你会浪费很多时间,不管是你还是你的客户。

4.你需要紧跟着业务,你在做新工程的时候,旧的工程也需要同时跟进业务需求。这样相同的东西需要在两边同时开展。

所以,听我的,不要从头开始,优化现有的

####让问题变得可见

这种事情很容易让人不爽,把问题都暴露出来。就像是让沼泽里的怪物们统统跑到了你的眼前向你的脸上吐痰,巨龙喷着火要烧掉你的头发,住在蘑菇旁的小侏儒踢着你的小腿。

不管你有没有注意到,这些害虫一直在侵蚀你的项目,你得想办法摆脱他们。所以必须得在任何时候都能看到到底问题出在哪

预见错误。每周花一点时间处理最常出现的一些问题。将问题图表化,可能能更有效的做到这一点,

监控环境变化。这可能是找到瓶颈和预见危机的关键(见下文)。

这样,你就能知道是什么问题对你的项目伤害最大,你就能提早发现问题展开救治,而不是最后面对一个垂死的病人束手无策。

####处理最重要的问题

做到这一点。你就需要有一个对系统完整的目标。就像你清楚的知道你最终要构建的完美的牧场是什么样,在你的每一步工作都是朝着这个目标。

这样你就不会忘记你每一小步做了什么。在这一小步一小步中间,你就会发现自己到达了自己最终的目标。

结合上文所说的监控方式以及你的最终目标,确定什么是你最先要处理的。你最大的问题应该不是马上实现某个目标,而且开始管理重构路上你找出的问题

还有个建议,有些小问题就像是一写坡脚的小精灵,你可能看她们不爽,但是实际上她们是无害的。你最好把时间花到如何踢出真正对人有伤害的那些食人魔。

####这行代码是我写的

解决问题是最重要的,但是不意味着其中的实现细节不重要。事实上,他们同样重要。

这里有个沼泽生存原则,保持你的宿营地比你发现他的时候更干净。随着你持续的整理,注意不留下什么垃圾。你的环境就会越来越好直到你发现这篇泥沼变成了绿洲。

态度决定一切:

1.细心。代码是你写的,你要能向所有接触它的解释清楚它,不要草率马虎。

2.团队要一样细心。你辛苦的填上一个有一个坑,但是后来人还在不断挖坑的话,依然还是那个样子。

3.纪律。团队任何一个人开始让事情变糟,都不要让他逃掉责任。

4.保持小步骤。在正确的方向上,进度比完美实现重要。

5.小小的胜利都能让人信心十足。你会发现一些地方优秀的修改会促使你想去修复它边上的问题。

####建立标准模块

一个对文明评价的重要指标是 在每平方米的土地上有多少图书馆。同样的,这对你的项目来说也是一个类似的指标(当然在项目里我们不叫他(Library)图书馆)。

举个例子,即使在最烂的沼泽地里,也会有几个不是特别糟糕的景点。无论何时,当你发现了一些好代码,他们完成了一些很不错的事情,就把他们挪到你的标准模块里,是的他们可以复用。

毫无疑问,你要修复的代码做的都是不好的。它们完全忽略和和避开了能让程序员觉得更轻松的可以陈祚最佳实践标准的原则。没有人会帮你搞定他们,你只有一条路可走:在你的新代码中实践下面的标准

让你的代码标准化和模块化。有些情况下你不得不使用旧的方式和不标准的方式处理旧的问题,但是这不意味着,你不能不在新的代码中实践这些正确的东西。

####用你的新模块重构 每当你的新模块写好,你就可以用它来重构旧的。你做这件事的时候没必要向马拉松的冲刺阶段一样紧迫。每当你偶然发现你有一个好的新方式替代那部分老代码的时候。保持小步骤,最后你会发现一点一点你就找不到那些困惑你的老代码了。

通常,上述步骤是可行的。不过有时候你发现有些代码包含无数的依赖关系四处分布(比如会话访问,各种模块和服务纠缠在一起)。这时候,有个好方法是把它们的依赖方法和函数从他们内部暴露出来,外部就可以通过这些函数和方法访问他们。这种方式使得这些代码相对独立,以后更利于分离和移动它们。

同时,一旦代码独立了,它们就变得可测试了。

####通过测试建立信任

自由穿行的食人魔们可以比带着枷锁的食人魔更可怕。把系统中最为关键的部件(同时它们可能造成最严重的问题)加上锁链对于掌控一个系统是非常重要的。在每次构建的时候进行测试(最好是自动化的)尤为关键

如果有更多的对你的系统行为的自动化测试,你就能在改动项目的时候有更充足的信心。一点有东西出错,这些测试就能让你在发版前及时修改它们

####高级别测试

有一个有效的测试方式叫做:关键场景验收测试。对于一个电子商务系统,肯定包括一个结账的流程。没有订单你肯定不赚钱,测试这个订单流程,你就能在客户没有发觉之前解决这个问题。有了这样的测试,你就可以避免自己不知不觉的引进重大问题

####低级别测试

这种低级别测试我们推荐单元测试。使用上文说的小步骤逐一分解依赖的方式,你会使得你的代码有一套清晰的输入和输出结构。这种情况下就很适合用单元测试覆盖这些代码的功能。你可以定义一组输入,并且定义它预期的输出。这些测试可以确保这些代码的行为和你预期的一致

####不要测试所有的东西

没必要测试系统的每一行代码。原则上让系统的每一个方面可以使我们对所有事情充满信心,但是让所有东西可测试并为他们编写和维护测试用例会让成本变过高。根据我的经验,你最好把时间花在为重要的业务逻辑和有可能造成重大问题的代码上(即使他们看起来很简单)。

这样你就相当于把沼泽里最危险的怪物们锁起来了,整个沼泽变得更安全咯。

####隔离和更换

结合我们上文提到的战略模式和技术,我们总结唯一个原则:“隔离和替换”。

每当你遇到某些代码,他们的内部逻辑很难理解,而且打算用那种小步骤重构的方式整理出来。下面有些步骤建议:

1.隔离混乱的部分,把他们放到一些单独的方法里。

2.把依赖的部分拆出来作为他的参数

3.把逻辑里的副作用分离出来(比如向数据库保存数据),这里也是小步骤进行

4.隔离单独的逻辑到不同的方法里

5.添加单元测试覆盖逻辑模块

6.重写的逻辑模块。就算他能通过测试,也要保证至少他的行为要类似老系统中的行为。

7.保持新老版本同时能在线上运行。保证旧版本也能运行

8.log记录下新老版本的输出。

9.对比日志,看看他们输出的不同,如果有不同就为该模块添加一个新的单元测试,然后开始修复它。

10.重复上述步骤直到他们一致为止。

11.最后新版本能完全替换旧版本的相关逻辑

这种做法就像是不需要停车就能为他换了发动机,甚至是没有人能主要到他的内部发生了变化。

####说服自己

在这里,上述的态度和方法,至少对于我来说,是一个拯救一个濒临崩溃的系统之路

最初我还在犹豫,为什么要把我的时间花在这样一个长期的旧工程上。但是这期间我也获得了很多能帮助我变得更好的技能

1.识别糟糕的代码。你认识到什么是糟糕的代码因为你花了大量的是在在它上面。你在新项目中就不会使用它这种方式因为你知道它会在未来搞出多少问题。

2.回归本质。我认识到系统的每一个方面都值得质疑和重新评估。项目里没什么是无懈可击的,你会发现许多更现代的框架可以帮你处理很多问题。

3.你和项目同时成长。随着你对项目的关注越多,你就会看到更多的挑战。你知道了哪些是这个系统的瓶颈,越来越多的人在依赖的工作成果,而你是整件事情的中心。

4.人们总是不断的生产新的东西。如果赶在在他们对项目造成伤害之前,理解他们的运作方式也是个不错的技能。

5.有趣的经历。回头看你这一路的历程,看看这个系统的样子和你几年前第一次遇到他的时候。是不是也蛮有成就感的呢。

####去完成这个巨大(至少是长期)的任务吧 你可以选择做一个胆小的农民,期待中谁能把你从这片沼泽地带到迪士尼乐园。或者你可以摆正你的姿态,扮演好救世主的角色。在任何一个有坚固地面的沼泽地里,你都可以找到你的位置。

####最后 几年之后,你漫步在这片牧场上。你看到公爵在地平线上竖起了啤酒广告代替了原来“这里有怪物”的标志牌。

######感觉翻译的不太像人话。。。。

原文链接:http://blog.intracto.com/paying-technical-debt-how-to-rescue-legacy-code-through-refactoring

© 著作权归作者所有

共有 人打赏支持
fx911
粉丝 13
博文 2
码字总数 8576
作品 0
海淀
程序员
私信 提问
加载中

评论(3)

fx911
fx911

引用来自“小海bug”的评论

good 但 .给出清晰的短期目标和计划,告诉客户你可以选择花一周去实现一个功能,也可以给我吗一周时间重构,然后花一天去完成这个功能。但是第二种方案对于以后的开发有很多好处。 这一条 过于理想化,现实一般是这样的 一周可以实现 重构的话 需要3周,然后才能用4天解决,以后的效率会提升,重构带来的是长久的好处 并不会立马见效,你那个比喻 只差一天 很容易说服领导 但差距很大 的时候 就没那么容易说服了
文章是我翻译的。我觉得这件事情的标准前提还是在不太影响进度的情况下进行,你说的需要三周重构,我觉得也有可能是你选择的步骤跨度太大,或者说是单步定的目标太大。这种情况下就得看具体进度安排了,如果三周内没有太紧急的发布计划,可以尝试要求多一点时间;如果不行可以尝试把这三周计划的事情再做更细化的切分。 嗯,以上就是我不成熟的小建议~
小海bug
小海bug
good 但 .给出清晰的短期目标和计划,告诉客户你可以选择花一周去实现一个功能,也可以给我吗一周时间重构,然后花一天去完成这个功能。但是第二种方案对于以后的开发有很多好处。 这一条 过于理想化,现实一般是这样的 一周可以实现 重构的话 需要3周,然后才能用4天解决,以后的效率会提升,重构带来的是长久的好处 并不会立马见效,你那个比喻 只差一天 很容易说服领导 但差距很大 的时候 就没那么容易说服了
hylent
hylent
mark
全栈看到的技术债务

关于技术债务的讨论时而蔓延时而消退,技术债务仿佛是个筐,什么东西都可以往里装,然而当我们企图倒光筐里东西的时候,却发现每人看到的东西都不一样,甚至有时候都数不清里面都有些什么。 ...

wireless_com
2017/11/06
0
0
闲谈简单设计(KISS)疑惑

忙碌了一年了项目又到了交付了,虽然项目能成功上线(因为还有维护支持的团队)。但是个人从技术上看,这是一个不那么成功的项目,因为后期艰难的修复bug,添加feature。这与简单设计有什么关...

zting科技
2017/01/10
0
0
代码质量与规范,那些年你欠下的技术债

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文来自云+社区专栏,作者腾讯移动品质中心TMQ 提到“质量”二字时,我们的第一反应往往是“有多少BUG?”“性能好不好?“这样...

腾讯云加社区
07/03
0
0
源码的寿命

看看你现在日常工作中的代码。已经运行了多久了?代码有多老了?有六个月?一年?可能都有五年这么久了吧?十年?二十年呢?!这样的代码有多老了?不到10%?还是一半?亦或者已经有90%了?为了...

oschina
2016/03/01
6.7K
16
《Scrum精髓》之技术债

《Scrum 精髓:敏捷转型指南》全书45.7万字。本次读第8章技术债。 Scrum精髓 1. 技术债概述 技术债是Ward Cunningham率先提出的,定义如下: 技术债的定义 分类有: 低级技术债、 不可避免的...

通爸
01/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

mybatis学习(1)

JDBC连接方式: 1.底层没有使用连接池,操作数据库需要频繁的创建和关闭连接,消耗资源。 2.写原生的JDBC代码在JAVA中,一旦需要修改SQL的话(比如表增加字段),JAVA需要整体重新编译,不利...

杨健-YJ
30分钟前
2
0
怎么组织文档

可以从以下几个方面考虑组织文档: ☐ 各种分支的界面截图和对应的类及文件 ☐ 框架或类图 ☐ 流程图 ☐ 时序图 ☐ 注意事项

-___-
41分钟前
3
0
分布式之数据库和缓存双写一致性方案解析

引言 为什么写这篇文章? 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。 但是在更新缓存方面,对于更...

别打我会飞
43分钟前
9
0
我的oracle11G,12c OCM之路

ocm认证感悟 ---------------------- 距离拿到ocm证书已经过了1年的时间,当初拿到证书的心情到现在还记得。其实在每个DBA心里都有一个成为强者的梦想,需要被认可,我也一样。我干过开发,做...

hnairdb
44分钟前
2
1
手动部署kubernetes集群(1.13.1最新版)

一、机器规划 使用五台机子部署k8s集群,规划如下: master节点3台(同时也是etcd节点) node节点2台 ip分配如下: ip:192.168.10.101,主机名:k8s-etcd01 ip:192.168.10.102,主机名:k8s...

人在艹木中
49分钟前
31
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部