什么是重构?
- 重构是在不改变软件可观察行为的前提下改善其内部结构。---Martin Fowler
- 通俗说法:看起来没做啥调整,让系统继续更好的满足客户需求。同时,希望重构完成后,这个系统能够多蹦跶几年。
重构的分类:
- 代码重构
如果想了解代码方面的重构主要有哪些方法,可以参考《重构:改善既有代码的设计》、《重构与模式》。
之前我们在有次讨论的时候,一个童鞋说:“我们现在的程序设计都被框架封装了,设计模式基本是用不到的。”这个说法我不太同意。因为我们现在也在进行代码重构,抛去设计不谈,但从代码风格上,最令人吐槽的是里面充斥着大量的if和else。刚毕业的童鞋可以觉得很正常。但是稍有经验的人就知道这些逻辑计算应该用策略来代替。设计模式是从细节代码到设计架构处处充斥着的一门设计美学,任何工程师都需要掌握和学以致用。
- 架构重构
如果想了解架构方面的重构主要有哪些方法,可以参考《软件设计重构》。下面列了一些架构重构方面的主要考虑点,并对其中一点做了说明。
1>可扩展和负载均衡策略
2>数据库的读写分离和主从切换
3>按需扩容
4>两地三中心,机房故障也能稳定的提供服务
5>持续的容量规划
每个阶段都有自己的业务目标。订单量会对系统容量有新的要求。针对业务目标做评估,对组件做评估,看当前支撑的量是多少,找到其中的瓶颈点做架构升级。应该有1.5倍到两倍的冗余。把握节奏,太早会影响需求的迭代速度,运维成本高。太晚会不足以支持单量。
技术方案长期规划,逐步实施。持续重构,重构在每个阶段都要有人力。
6>持续的性能优化
7>性能影响用户的留存率、成本
8>单机容量低、响应慢
重构的目标:
- 最终目标:更好的承载业务
- 具体目标有:改进设计、模型规范、重建生命周期、增大负载能力、提高响应速度、抽象、解耦、无法维护、扩容、业务复杂度、降级开发成本、容易理解、技术栈革新
重构面临的问题:
- 新的系统就不会再有问题了么?
- 再过几年,新系统也会变成老系统
- 一个正在运行的系统,如何新老系统平滑迁移?
- 日常需求不停顿,还要花费大量精力重新设计编码
- 之前踩过的坑如果没有很好地沉淀,可能会重新入坑
既然重构面临这么多问题,到底要不要重构?那就问自己愿不愿意为重构负起责任,坚持到底,并承担后果。
为什么要重构?
一般说需要重构了,都会是因为面临着一些问题。近期问题如:不能支持业务、故障、响应不满足需求、单点无法扩容。长期问题如:维护成本大、扩容成本大、有明显风险、不支持业务扩展。
我们的代码迫切的需要重构。我曾经为了申请重构资源,做了很多工作想让领导认识到我们重构的必要性。尝试着列举不重构的话,TOP3无法解决的问题:
1.我们是一个平台系统,当初的设计却是为了其中一个业务研发的,功能都是定制化的
2.在不合理的逻辑上叠加需求
3.数据模型不能覆盖目前的需求
不重构很痛,但总感觉没有说到痛点。后来我们领导说:“重构的目的是为了甩掉历史包袱。”听着更接近本质一点了,但是总感觉还是缺少什么。
后来我仔细想了一下。当初必须要重构。因为不重构一改就会出问题。当初资源申请困难是因为我一直都没解释清楚为什么一改就出问题。因为按照正常的理解:改出来问题是能力的问题,对业务没有很好的把控,对代码没有深入的研究。而实际上重构是因为”坏味道“使得架构和代码本身已经无法阐述它的行为。再通俗点说就是:现有架构和代码,与目前承担的事情不是一个东西。
为什么要持续重构?
- 从本质上,重构就是在代码写好之后改进它的设计。
- 如果你发现自己需要为程序添加一个特性,而代码结构使你无法很方便地达成目的,那就先重构那个程序,使特性的添加比较容易进行,然后再添加特性。
- 重构改进软件设计,因为代码结构的流失是累积性的。
- 重构使软件更容易理解
- 重构帮助找到bug
- 重构提高编程速度
对我们组来说,为什么要持续重构?
因为持续重构的代码是确保代码长期没有人动,一动就出问题的有效手动。
何时重构?
- 三次法则:事不过三,三则重构。
- 添加功能时重构
- 修补错误时重构
- 复审代码时重构
重构和性能优化
- 重构是对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。它提供了一种更高效且受控的代码整理技术。
- 和重构一样,性能优化通常不会改变组件的行为(除了执行速度),只会改变其内部结构。但是两者出发点不同:性能优化往往使代码较难理解,但为了得到所需的性能不得不那么做。
”两顶帽子“如何权衡
在开发过程中,通常会遇到两顶帽子。一顶是需求的帽子,一顶是重构的帽子。囚徒困境,如何抉择?
我刚接手交易的时候,对此也很迷惑,所以特地去了解了一下交易的前世今生。了解之前的交易负责人的关注点。有的疲于应付询问和问题;有的关注需求;重构是解决业务支撑开发量大的有力武器。但是需求来了,怎么办?
权衡的时候,重要紧急、重要不紧急、紧急不重要、不重要不紧急的四象限理论怎么发挥作用?都紧急的时候怎么按照重要度来进行排序。
回答这个问题就要先弄清楚交易最重要的是什么。交易的核心是稳定。如果重构是维持稳定的必要条件,而我们需要一个重做级别的重构,需要大量的时间。那么这时就需要保证重构和需求至少1:1的投入。
重构的原则
1.测试优先原则
TDD(Test-Driven Development):测试驱动开发
2.OCP原则
Open For Extension:开放封闭原则
3.小步快跑原则
大布局、小迭代
进化式设计和增量开发
避免过度设计,对于未来的变化,既不要考虑的太多,也不能一点都不考虑
代码满足当前需求,并留有可扩展余地
4.数据一致性原则
分库分表(横向、纵向)
字段合并、冗余
索引优化、数据缓存
重构设计方案选用
技术方案没有好坏,只有合适不合适。合适的方案用到合适的系统。判断合适主要考虑的方面:
1.业务契合度
2.覆盖面全不全
3.扩展性
4.人力投入成本
5.系统稳定性
6.安全
7.简单明了
重构的注意事项:
- 避免盲目重构
要重构,上面我的内容我自己认为都是需要想清楚的。另外还有一点,需要对重构系统进行一个生命周期预估,包括:
- 未来需求预判
- 模块划分拆解
- 总结历史问题
- 隐性及显性需求
我在知乎上看到说怎么判断隐性需求:隐性需求就是大家都觉得很不爽,但是又说不出个所以然。显性需求和隐性需求实际上没区别,视力不同的人看到不同的世界,洞察力不同的人看到不同的需求。
- 割接(新旧系统替换、迁移)实测演练
这块着重说一下,交易重构的割接采用的是留壳抠瓤的方式。就是对外接口和暴露方式不变,内部逐渐灰度用重构后的系统来替换新系统。
总结与思考:
以前上学的时候最不喜欢遇到主观题。因为一个试卷上有主观题,就基本上意味着得不了满分。 如今工作中,发现自己做的都是主观题。别人给自己打分,自己给别人打分。说好的标准可能到时候会发现难以实施。说好的加分项,自己也做了很大努力的,结果真正打分的时候,也只能呵呵了。但是通常面对结果,我会对自己说:“我会有一分钟的不开心,但是我服。”
因为打分的人总有自己的思考过程,得不了满分总意味自己有改进的地方。牺牲两周的午饭时间排练的街舞,得了第一名,也就得了一副蓝牙耳机。结果其实没那么重要,只是过程很开心而已。但是经验与教训的区别:经验给出了一条思路,教训却给了很多条。
我之前一个同事,自己创业失败去了我之前工作过的一家公司。后来在美团刚起步的时候加入了美团。做好了之后,如今又去了另外一家刚起步但是很有前景的公司。
我还认识一些人。他们很早买了房子。房价涨了,他们觉得赚了。又继续买了其他的房子。同样,价值都在增长。
这些都是成功的经验得以复制的例子。
教训的例子却不太好举。因为一旦成为教训,做出的思考很多,采取的改进往往也不是单方面的,得到的提高也往往是综合的。
如今,我不再怕主观题。对别人给我打得分,我会给自己一个实质性的收获。对我给别人打得分,我也会给别人一个满意的成长。在公司里能够得到的最大财富就是自身的成长改变,所以感激每一件能让自己反思自身的事情和经历。
就像我常说的:人生就是一场游戏,关键是经验值。