共计 5752 个字符,预计需要花费 15 分钟才能阅读完成。
目录介绍
01. 整体概述阐明
- 1.1 重构的背景
- 1.2 重构的要求
- 1.3 遇到问题
- 1.4 重构的目标
- 1.5 设计指标
- 1.6 产生收益剖析
02. 重构的具体实际
- 2.1 重构什么
- 2.2 何时重构
- 2.3 思考如何重构
- 2.4 针对简单场景
03. 重构技术手段
- 3.0 举一个重构例子
- 3.1 列举重构事项
- 3.2 把握要害节点
- 3.3 编写测试用例
- 3.4 mock 业务数据
- 3.5 发现代码 bug
- 3.6 优化编码方式
04. 防止重构失败
- 4.1 是否给短缺理由
- 4.2 乱套设计模式
- 4.3 先有问题后革新
05. 架构设计思考
- 5.1 针对简单场景
- 5.2 如何做架构设计
01. 整体概述阐明
1.1 重构的背景
我的项目的代码往往牵一发而动全身,业务逻辑耦合重大。
- 对于大的架构重构,其实始终很审慎的。准则是将重构交融在每次迭代中,逐渐优化代码的构造。而后将这个工作继续进行上来!
当初设计的架构让我的项目的依赖关系越来越简单,保护老本也越来越高。
- 决定梳理并优化一下整个我的项目构造。在施行过程中,仍然保持将整个重构的过程交融在每个迭代中,逐渐实现一次大的架构降级。
1.2 重构的要求
重构代码对一个工程师能力的要求,要比单纯写代码高得多
- 重构须要你能洞察出代码存在的坏滋味或者设计上的有余,并且能正当、熟练地利用设计思维、准则、模式、编程标准等理论知识解决这些问题。
进步代码的品质
- 具体点说就是,进步代码的可读性、可扩展性、可维护性等。
多问本人为什么这样设计
- 在做代码设计的时候,肯定要先问下本人,为什么要这样设计,这样做是否能真正地进步代码品质,能进步代码品质的哪些方面。
- 如果本人很难讲清楚,或者给出的理由都比拟牵强,没有压倒性的劣势,那基本上就能够判定这是一种适度设计,是为了设计而设计。
1.3 遇到问题
我的项目痛点在哪里
- 先要去剖析代码存在的痛点,比方可读性不好、可扩展性不好等等,而后再针对性地利用设计模式去改善。
对重构了解不深刻
- 对为什么要重构、到底重构什么、什么时候重构、又该如何重构等相干问题了解不深,对重构没有系统性、全局性的意识。
对重构没有技巧
- 面对一堆烂代码,没有重构技巧的领导,只能想到哪改到哪,并不能全面地改善代码品质。
1.4 重构的目标
软件设计巨匠 Martin Fowler 是这样定义重构
- 重构是一种对软件内部结构的改善,目标是在不扭转软件的可见行为的状况下,使其更易了解,批改老本更低。
重构的定义很重要
- 有一个值得强调的点:“重构不扭转内部的可见行为”。把重构了解为,在放弃性能不变的前提下,利用设计思维、准则、模式、编程标准等实践来优化代码,批改设计上的有余,进步代码品质。
遇到问题再重构
- 保护代码的过程中,真正遇到问题的时候,再对代码进行重构,能无效防止后期投入太多工夫做适度的设计,做到对症下药。
1.5 设计指标
重构围绕一个陈词滥调的概念「解耦」「拓展」「保护」等维度开展,设定几个指标:
- 清晰划分各模块的角色
- 明确架构层级及各个模块所在的层级
- 进步整个架构横向扩大的能力
- 各模块独立开发,面向接口和协定编程
- 进步代码可维护性和可读性
02. 重构的具体实际
2.1 重构什么
依据重构的规模
- 能够抽象地分为大规模高层次重构(以下简称为“大型重构”)和小规模低层次的重构(以下简称为“小型重构”)。
大型重构指的是对顶层代码设计的重构
- 包含:零碎、模块、代码构造、类与类之间的关系等的重构,重构的伎俩有:分层、模块化、解耦、形象可复用组件等等。
- 这类重构的工具就是应用学习过的那些设计思维、准则和模式。这类重构波及的代码改变会比拟多,影响面会比拟大,所以难度也较大,耗时会比拟长,引入 bug 的危险也会绝对比拟大。
小型重构指的是对代码细节的重构
- 次要是针对类、函数、变量等代码级别的重构,比方标准命名、标准正文、打消超大类或函数、提取反复代码等等。
- 小型重构更多的是利用咱们能前面要讲到的编码标准。这类重构要批改的中央比拟集中,比较简单,可操作性较强,耗时会比拟短,引入 bug 的危险相对来说也会比拟小。你只须要熟练掌握各种编码标准,就能够做到得心应手。
2.2 何时重构
须要阐明的问题
- 集体比拟拥护,平时不重视代码品质,堆砌烂代码,切实保护不了了就大刀阔斧地重构、甚至重写的行为。
- 有时候我的项目代码太多了,重构很难做得彻底,这就更麻烦了!所以,寄希望于在代码烂到肯定水平之后,集中重构解决所有问题是不事实的,咱们必须摸索一条可继续、可演进的形式。
找到代码中的问题
- 能够看看我的项目中有哪些写得不够好的、能够优化的代码,被动去重构一下。或者,在批改、增加某个性能代码的时候,你也能够棘手把不合乎编码标准、不好的设计重构一下。
2.3 思考如何重构
进行大型重构的时候
- 要提前做好欠缺的重构打算,井井有条地分阶段来进行。每个阶段实现一小部分代码的重构,而后提交、测试、运行,发现没有问题之后,再持续进行下一阶段的重构,保障代码仓库中的代码始终处于可运行、逻辑正确的状态。
- 每个阶段,咱们都要管制好重构影响到的代码范畴,思考好如何兼容老的代码逻辑,必要的时候还须要写一些兼容过渡代码。
小规模低层次的重构
- 因为影响范畴小,改变耗时短,所以,随时都能够去做。依照分,拆的思维一直优化代码。
借助工具剖析代码问题重构
- 除了人工去发现低层次的品质问题,还能够借助很多成熟的动态代码剖析工具(比方 FindBugs、PMD),来主动发现代码中的问题,而后针对性地进行重构优化。
03. 重构技术手段
如何保障重构不出错呢?
- 你须要熟练掌握各种设计准则、思维、模式,还须要对所重构的业务和代码有足够的理解。除了这些集体能力因素之外,最可落地执行、最无效的保障重构不出错的伎俩应该就是单元测试(Unit Testing)了。
- 当重构实现之后,如果新的代码依然能通过单元测试,那就阐明代码原有逻辑的正确性未被毁坏,原有的内部可见行为未变。
3.0 举一个重构例子
举一个简略的例子看重构事项
- 现状:App 业务线各种依赖宏大,而后交织在一起,关系变的简单。依赖库之间的强依赖导致版本抵触多。模块计划发生变化,下层批改老本大。功能模块兼容性导致保护老本大。
- 重构计划:整个架构的核心思想是面向接口编程和依赖注入使各个模块之间实现解耦,而后通过横向角色划分与纵向层级划分的形式约定各个模块之间的关系,再通过接口分层的形式,明确具体模块在不同层级上须要实现的性能
3.1 列举重构事项
针对重构的业务具体列举
- 针对一个比拟大的重构业务,先进行梳理,而后依据问题或痛点思考,列举解决方案,而后开始实际并保障代码稳定性,最初测试并交付。
列举重构事项
- 第一步:面向接口编程,依据业务抽取形象接口,因为接口是对某个性能需要形象,所以不会对具体的实现造成依赖。
- 第二步:层级划分与角色划分,总体分为三个档次:底层、组件层和应用层。
- 第三步:除了通过接口实现模块间的通信形式,咱们还设计了一套外部通信协定,用于在利用内部消息通信。对于一些易变的、灵便的、简略的通信,能够间接通过发送音讯的形式进行通信。
- 第四步:抽离功能模块,抽离公共视图模块,抽离公共业务模块,抽离产线业务模块。
3.2 把握要害节点
比方针对该例子关键点
- 第一个关键点:依赖盘根错节,那么就须要划分档次图,将 App 的架构设计分层。比方根底层,组件层,服务层,业务层,壳工程。而后定义好从上到下的关系,这样依赖就清晰明了!
- 第二个关键点:下层批改老本高,那这个时候可能依据业务形象一套交互的接口。
- 第三个关键点:代码的构造档次情绪,视图层,数据处理层,业务层等档次清晰。低耦合!
3.3 编写测试用例
编写具体的测试用例
- 能够模拟谷歌官网 demo 来编写测试用例,这个测试用例的测试粒度越小越好。首先保障主流程畅通,而后在写边界测试用例。
要把继续重构作为开发的一部分来执行
- 那写单元测试实际上就是落地执行继续重构的一个有效途径。设计和实现代码的时候,咱们很难把所有的问题都想分明。
- 而编写单元测试就相当于对代码的一次自我 Code Review,在这个过程中,能够发现一些设计上的问题(比方代码设计的不可测试)以及代码编写方面的问题(比方一些边界条件处理不当)等,而后针对性的进行重构。
3.4 mock 业务数据
mock 业务数据很重要
- 尤其是有接口申请的业务逻辑,这个时候能够 mock 本地 json 数据,而后模仿各种业务场景。非常有利于调试各种 case
3.5 发现代码 bug
踊跃发现代码 bug 很重要
- 在代码演进中,bug 防止反复呈现很重要。作为实际写代码,这个过程自测 case 列举一下,而后自测,自测一项勾选一项。
3.6 优化编码方式
理解敌人——俊俏的代码
- 臃肿的类:开发者不去思考这些性能是不是应该放在这同一个类中,导致这些类会变得很臃肿,造成一个类几千行,让下一个接盘侠欲哭无泪。
- 臃肿的办法:好几十上百行的一个函数堆在一块,用面向过程的思维来写代码,倡议一个办法代码行数不超过 80。
- 函数参数过多:函数参数过多会导致调用者对办法难以了解,参数弄混。倡议能够将参数组成一个对象传入。
- 层层嵌套的判断:如果逻辑不简单尽量减少 if-else 的分支包裹,太难浏览。比方不满足条件了间接 return,不走其余代码,这样能够缩小一层嵌套。
- 满篇跑常量值:一个类外面呈现各种未命名的常量值。0,1,2 等等铺天盖地。这种状态码意义改了,改代码会把你改哭的。难道就不能先申明一个对立的常量变量来应用吗。
- 不置可否的命名:不能依据名字一眼看懂它的性能的命名不是一个好命名。当然生僻的单词除外。含糊的,没有性能意义的命名会给浏览造成很大艰难。
优化编码的具体操作
- 分拆大函数:当函数比拟大了,就能够依据性能节点分拆成多个小函数,兴许其中的小函数还能够专用。比方结算购物车,包含计算各类商品的总价,再计算折扣,再计算满减优惠。别离拆分成三个,一眼就能看出这段逻辑先后做了什么。
- 封装到父类:如果多各类要执行类似的性能和代码,能够把该办法放到它们的父类中,或者提取进去成业务工具类。
- 针对类臃肿:办法迁徙,恪守“繁多职责”准则,当类中的办法不适宜放在以后类中时,就应该为该办法寻找适合下家。移到与办法耦合大的类中。
- 搬移字段:当在一个类中的某一个字段,被另一个类的对象频繁应用时,咱们就应该思考将这个字段的地位进行更改了
- 提炼类:一个类如果过于简单,做了好多的事件,违反了“繁多职责”的准则,所以须要将其能够独立的模块进行拆分,当然有可能由一个类拆分出多个类。对类细化。
- 晋升办法、字段:将办法向继承链下层迁徙的过程。用于一个办法被多个实现者应用时。在继承的体系中,当多个类应用了雷同或相似的办法,就能够思考将该办法抽取到基类,没有基类就创立一个。字段晋升同办法。
- 升高办法:即父类形象办法让多个子类实现。多个子类有雷同的性能然而有各个具体的实现办法,那么这种封装就能够用多态性了,父类创立一个形象办法,将办法实现升高到子类。
- 反复代码的提炼:有时候为了赶我的项目进度,尽快实现性能,会偷懒将实现性能的一片代码复制一遍,间接套用。这种把多余的删掉,保留一个,兴许只需传一两个参数就能够封成一个办法供多处调用。
- 重命名变量(类、办法、变量):这个很重要,能够不夸大地说,命名的程度就体现了编程能力的高下。在重构的过程中,当发现类名,办法名在以后版本不合乎它的性能含意,就该思考对其重新命名。
- 补加正文:对于全局变量,专用函数,逻辑简单的中央增加正文,补救之前的脱漏。
04. 防止重构失败
4.1 是否给短缺理由
为何要这样重构
- 如果本人很难讲清楚,或者给出的理由都比拟牵强,没有压倒性的劣势,那基本上就能够判定这是一种适度设计,是为了设计而设计。
4.2 乱套设计模式
不假思索地套用学过的设计模式
- 看到某个场景之后,感觉跟之前在某本书中看到的某个设计模式的利用场景很类似,就套用下来,也不思考到底合不适合。
- 最初如果有人问起了,就再找几个不痛不痒、很不具体的伪需要来搪塞,比方进步了代码的扩展性、满足了开闭准则等等。
4.3 先有问题后革新
先遇到问题而后再革新
- 从问题讲起,一步一步给你展现为什么要用某个设计模式,而不是一开始就通知你最终的设计。
看到某段代码之后能剖析
- 就可能本人剖析得有条有理,说出它好的中央、不好的中央,为什么好、为什么不好,不好的如何改善,能够利用哪种设计模式,利用了之后有哪些副作用要管制等等。
05. 架构设计思考
5.1 针对简单场景
设计模式要干的事件就是解耦
- 也就是利用更好的代码构造将一大坨代码拆分成职责更繁多的小类,让其满足高内聚低耦合等个性。
- 创立型模式是将创立和应用代码解耦,结构型模式是将不同的性能代码解耦,行为型模式是将不同的行为代码解耦。而解耦的次要目标是应答代码的复杂性。设计模式就是为了解决简单代码问题而产生的。
依据是否简单投入工夫
- 对于简单代码,比方我的项目代码量多、开发周期长、参加开发的人员多,咱们后期要多花点工夫在设计上,越是简单代码,花在设计上的工夫就要越多。
- 如果你参加的只是一个简略的我的项目,代码量不多,开发人员也不多,那简略的问题用简略的解决方案就好,不要引入过于简单的设计模式,将简略问题复杂化。
5.2 如何做架构设计
架构设计要以实用为目标
- 不要光想着造一个世上最牛逼的架构,这样往往是不靠谱的,咱们不是救世主。一切都是以后理论状况为主!
总结下,架构设计有三个根本准则:
- 1、适合优于世界领先。适宜本人以后业务的就好,不要总想搞当先的架构,比方一个用户量 100 万的 App,光想着对标微信的架构,适宜微信的架构未必适宜本人。
- 2、简略优于简单。如同写代码一样,代码量越少越简略越好,架构设计也是一样,越简略的架构越容易看懂和保护。
- 3、演进优于一步到位。可扩展性咱们当然要思考,然而人不是神,无论你怎么去预测将来的零碎演进,总是很大可能会失策。所以架构设计优先解决当下的问题,至于起初的问题,到时候再对架构计划进行改良。
这三个准则也是有优先级的
- 具体是:适合优于先进 > 演变优于一步到位 > 简略优于简单
- 适合也就是适应以后须要是首位的,连以后需要都满足不了谈不到其余。架构整体倒退是要一直演进的,在这个大前提下,尽量谋求简略,但也有该简单的时候,就要简单,比方生物从单细胞始终演变到现在,简单是防止不了的。
开源我的项目:https://github.com/yangchong2…
开源博客:https://github.com/yangchong2…
正文完