打破常规,重立新规;
01
开始想聊这个话题的时候,我是打算放弃的;因为这个话题波及范畴之广,内容之多,让我犯怵;
近几年,待过两家公司;一家经验过重构,另一家也打算重构 ……
其实要下定决心,颠覆重来,是一个很有勇气的决定;
归根结底,不到万不得已,谁想这么玩,谁违心破费大精力去做这些脏活、累活;
所以究其原因,也只能说是一种综合因素吧,就像古话说的,地利、天时、人和;
至于为什么这是个很有勇气的决定,因为做重构这事的团队危险极高;上至业务高层,下至底层码农,都有可能一个不小心就被刀;
我已经待过的一个团队,经验过一次重构,不过那是一次失败的经验;
开发预估了两个多月的工夫,业务大佬决定,期间间接对新需要停滞;然而,最终上到生产的零碎,老问题还在,而后又多了很多的新问题;
再起初啊,业务大佬和技术主管都被刀了;而后零碎回退成老版本,从新承接新需要,并且开发工夫被重大压缩,导致技术部门没日没夜的加班;
上面,我大抵做了归档和整顿,从这八个方面从新聊一聊零碎重构;
02
【重构起因】
其实下面也提到过,这是一个综合因素,可能是各种各样的因素叠加,造成一个不得不重构的后果;
上面,聊一聊我所碰到过的因素;要是没聊到的中央,也欢送大家补充;
第一个,能够归结为零碎的稳定性或可用性:不论吹得怎么天花乱坠,你的零碎总要可用吧,所以说可用和稳固是一个零碎的最根本要求。开发一个需要还要全服务停用吗?业务量增长,零碎还能抗下所有吗?那么问题来了,怎么保障可用和稳固?
首先,如果你是单服务零碎,那么为了保障可用和稳固,须要对服务进行扩大,退出更多的机器来分担零碎的性能压力,也就是常说的“服务集群”;
然而,往往咱们的零碎并不是单服务的,也就是咱们常说的散布式微服务;这种状况下,就不得不扯到分布式的三大法宝:限流、熔断、缓存。置信要实现这三个法宝,有很多成熟的框架和工具等,这里就不过多论述了;
第二个,开发标准问题:这也考验了团队 leader 对底下成员的约束力,以及是否存在代码 review 的环节;
假如一个团队,leader 的确没有对成员强制束缚开发标准,更别提代码的 review 了;最终导致的问题就是,各写各的,每个人都有本人的一套开发习惯和开发标准;最终就是一个大写的“乱”;
这样与日俱增,一代目埋坑,一代目撤,二代目上,二代目撤 …… 零碎不晓得经了多少开发人员的手,最终,新入职的冤种某天须要排查一个产线问题,好像误入了代码的迷宫,深陷其中,无法自拔;
第三个,颠覆原先外围业务,重立新规:这个要解释起来比拟麻烦,也碰到会比拟少,然而,我恰好就遇到了;
某天,业务大佬发表,目前做的这套业务规定要被废除了,他们从新拟定了一套全新的规定,意味着先前不晓得几手的代码曾经失去意义了,简直 90% 都须要从新写;
都到这一步了,那就大刀阔斧的改革吧;出事了,emmm,业务的锅;
03
【重构会议】
既然曾经确定要进行我的项目的重构,那么拉成员例会是必不可少的,不然就会一片迷茫,不晓得干点啥;
第一次会议,由技术老大牵头,叫上业务负责人,技术主管,开发全员,测试,产品,运维;
个别,第一次这种全体会议是没有后果,然而又十分必要的;因为上级领导须要通晓整个重构波及到的点,影响的方面,开发的工夫,以及整体的技术计划,参加的人员,还有须要的资源等等;
第一次会议消化完后,很快就是第二次会议;这个会议也是由技术老大牵头,参会的次要是技术主管和参加开发的人员和运维;次要是对系统重构进行总体的技术选型,探讨用到的框架,组件,实现的计划,部署计划等等;
这个会议继续的工夫会比拟久,大家搬好小板凳,筹备打持久战,可能从下班开始,到上班点了都还不能完结;当然,还是会有中场休息时间的;根本能够畅所欲言,提出本人的意见和认识;次要是围绕做什么?怎么做?做多久?这三个疑难点探讨;
接下来,就是由技术主管组织的技术部外部会议了;因为之前曾经确定好了对立的技术栈和实现计划,这一次探讨都是在此基础上开展的;
当然这一次会议可能须要更久的工夫,因为波及到是微服务的话,就防止不了一个问题:“服务拆分”;
大家都晓得,微服务是须要依据业务去进行拆分的;那么问题来了,业务的划分界线是什么?为什么 A 业务局部要蕴含 A1,A2,A3;其实这里就须要大家达成一个对立的认知,也是这次会议要达成的最终目标;
这次会议最初,服务曾经划分结束,然而短少去保护这些服务的人;那就须要对开发人员进行分组,每组有对应的负责人,看人员状况而定(_如果就两三个,甚至更少的开发,那就没必要分组什么的了,就是冤种,活都得你干_),每组对 N 个服务的开发和保护;
分组过后,组长会进行简短的组内会议,这次其实就是派活会议,认领各自的工作;也会明确一点,大家要干些什么?谁干哪些?每个人干完都须要多久的工夫?
最初,会整顿一份排期打算,下面每个人的名字赫然在列,当然还有工作列表,工时,等等;
所有筹备工作就绪,最初就是开干了,当然前面开发过程中还有一些不明确的点,也会长期组织一些会议,让大家达到对立的认知;
04
【并行需要】
在零碎重构的开发过程中,因为占用的周期会很长,投入的资源会比拟多,所以不免还会遇到这样一个问题;
一天产品经理急冲冲的跑过来说,当初有一些需要很着急,须要将重构停一停,先把这些需要排期上线;至于为什么会这么焦急,咱也不晓得,咱也不敢问呀;
这时候就会面临一个恶心的场面,这次开发的需要,必定须要在原先的服务中进行开发,那么重构的服务中,是不是还须要再写一遍?
王德发!说归说,骂归骂,方法总比艰难多!这时候有一种形式,那就是派出个会谈专家,以三寸不烂之舌,动之以情,晓之以理;多说说技术难点、痛点,占用的资源,实现的难度等等,去感动他,压服他,让这次需要排在重构前面;
如果你胜利了,那么祝贺你,这次重构工作,大家帮你分担一半;
什么?产品经理不批准;那就没有方法,只能在改变老服务的根底上,记录调整的点,最终在写新服务业务代码的时候,将改变的点一并加上去;
最初在提测的时候,告诉测试同学,这些需要相干的中央,在重构的新服务上线之前都须要从新走一遍流程;
当然,还有一种状况,就是像我之前说的,需要即随同着重构;这种需要也必定是大版本,开发周期较长;这种状况是最理想化的,只须要循序渐进的进行开发即可;
05
【技术选型】
这个话题,在下面的会议模块曾经提到过了,这里再来具体的聊一聊;
当然,这次也仅限于比拟风行的散布式微服务的技术选型;单服务的话,额,暂且不说吧;
其实也没什么好争议的,对于 Java 零碎而言,无非就是 spring 全家桶无脑往上堆,服务器资源拉满;就像买汽车一样,越奢华的车,堆的配置越多,价格越贵,然而舒适性和操控性也就越好;
然而还须要思考一些因素:老本、产品开源与否、技术社区活跃度、产品的成熟度、结合实际状况等等;
老本:工夫老本、学习老本、金钱老本;
事件是人做的,代码也是人敲的;须要思考团队成员善于哪些技术栈,如果一门技术只有少部分人会或者都不会,那就须要联合开发工夫,去斟酌需不需要用它,即使是热门的技术;
当然啦,如果老板违心出钱,间接买各种付费的技术就行,咱们只须要搭好根底的框架,而后往里面填充业务代码即可;如果不行,那就老老实实看看免费版,出了啥问题,只能本人排查去解决;
产品开源与否 :说到这个,开源是要害,最香的词“ 开源收费”;
就像下面说的,一旦遇到了什么问题,其实有必要去看这门技术的源码去解决的;比方典型的 SpringBoot 自定义 starter,须要定义“META-INF/spring.factories”文件,将文件中配置的类型信息加载到 Spring 容器;
一旦你闭源,那怎么玩?我怎么晓得你外部怎么去实现的?只能看官网文档,看你本人吹什么什么性能;
技术社区活跃度:这个因素其实和产品开源能够归为一类,都讲的是一旦这个框架或产品出了问题,咱们就能够去它的官网社区上找相似的解决方案;如果一个产品连社区都没,或者活跃度很低,那也就意味着你只能靠本人去解决了,那花的工夫老本可就 ……
产品的成熟度:咱们选用一款适合的产品,首先它得合乎咱们次要的需要,而后它才有其余额定的性能,这当然是最好的;因为一旦咱有一些非凡的业务场景,凑巧这些额定性能正好合乎你这个场景,岂不美哉;这样就不必要接入额定的产品或组件了;
比方 Redis,大家都不生疏;置信这个工具大家最多的是用它做缓存,它的确也是一款优良的缓存工具;
然而,我之前在做 OA 软件时,碰到这么一个需要;用户申请一个会议,并且指定了参会人员,当在会议开始前 15 分钟,前 5 分钟,别离对参会人员发送一个揭示;
典型的公布、订阅的模式,而后正好 Redis 就有现成的性能,过后就是用了 Redis 的这个性能;
但 Redis 适宜小型利用,如果是大型架构,置信还是会应用 rabbitMQ 或者 kafka 等更业余的 MQ 队列软件
结合实际状况:说到这个,有句老话说:“只有适宜本人的才是最好”;在思考须要用到哪项技术时,最现实的状况那就是间接付费购买,出啥问题,都是有技术支持滴,我出钱了,你得为我解决,然而,老本无限啊;
当然,有些人会说,技术选型这玩意,那是技术主管或者技术总监他们决定的,咱们小码农只管拧好螺丝就行;是的,往往很多时候就是这样;然而,你不去大胆说出你的想法和意见,你怎么晓得他们不会听取呢?格局关上,往上一层思考就对了;
06
【服务划分】
这块内容其实可聊的没多少,然而,也是最难的一块;
首先,划分;怎么分?按什么规范去分?分多少服务适合?分好之后怎么去治理?安顿那些人去治理?等等一堆问题;
我也只能浅谈下我之前做过的一次划分经验,因为每个公司遇到业务和场景是不同的,最终失去的后果也是不同的;而且,服务并不是一次划分就能完结,它是一个继续一直的过程;
过后咱们是全副参加这次重构的开发一起拉会议的,在此之前,曾经确定好了技术栈,就是热门的 springcloud 全家桶;技术主管先是浅谈一波他本人的想法,而后让大家在他划分服务的根底上,提出本人的认识,并且每个人都要说,因为不可能想法都是统一的;
我记得比较清楚的是,他划分中,有个序列号的服务,就是这个服务专门去生成序列号;前面几个人都点名这个服务也包含我;其实过后想的是,咱们的零碎业务里没那么大,能省一个服务,也是省一点资源;最终大家对立共识,将这种场景写一个工具类去解决;
最终探讨后,达到的共识,也只是一个初步的共识;随着业务需要的增长,一部分业务服务必将变得臃肿,那时候第二波拆分也就随之到来了;
07
【开发标准】
下面提到,造成零碎重构的因素有很多,其中一个因素就是代码凌乱,大家各有各的习惯和标准;
其实不难发现问题了,并不是每个人不晓得开发标准,而是大家没有对立的一套标准,大家只是没有达成共识;
那就来解决这个问题,制订一套对立的规范,让大家都没有异议的一套标准;
这时候就不得不提到阿里的标准,当初广为流传的《阿里巴巴 Java 开发手册》,甚至基于这套标准,在 IDEA 上还有专门的查看插件能够装置;
当然,这样做的确省事,省去了 leader 对代码的 review 工夫,包含我之前待过的一家公司,也的确就是这么做的;
其实认真用过几次这款插件就会发现,有些检测其实大可不必,然而你又不得不去恪守它的规定,这时候反而徒增工作量;
遇到这种状况就须要看下级了,能够把这个疑难点反馈给他,或者反馈给身边其余的小伙伴,起码让他们 GET 到你要表白的点,引起大家的共鸣;置信越来越多的人反馈这些问题,下级不会坐视不管的;那么祝贺你,又去掉一块大家都认为不适合的标准,让你开发不绕弯路;
总之,总结起来就是一句话:没有规范,大家对立认可的就是规范犯规;
08
【数据、接口迁徙】
谈到这个,除非开发的是 0 - 1 的我的项目,否则在平时开发中,或多或少都是会遇到的,而非重构会独自遇到的问题;
而咱们在入职一家新公司,或者长期在一家公司干活,遇到 0 - 1 的我的项目简直没有;如果有,那么你的运气很好;
就拿我下面的经验来说,业务颠覆了之前的规定,重新制定了新的业务规定,那就不得不引出一个问题,之前的老数据怎么办?
这个时候就须要跟业务确认,这批老数据是否能够依照某种默认的规定,做对立的解决;或者说,间接废除不论;一般来说,按前者解决的计划居多;
思考到重构,往往你的表也是从新设计过的,也有可能是老表和新表专用,一般来说后者的状况居多;
其实,说白了就是在老表外面去批改数据,在新表外面去新增数据,而咱们要思考的是这批数据怎么去调整比拟适合;
按咱们之前的解决形式,如果波及到的表,字段等较少,存储构造也颇为简略,是能够间接用 SQL 脚本去解决的;另外,还须要思考如果表数据较多,SQL 执行快慢的问题;
还有一种状况,要是波及到的场景很多,解决的表也居多,能够思考写程序去解决;比方,写个工作,去手动执行这个工作,解决掉这批数据;当然,也得思考数据量的问题,如果数据量大,用多线程跑批,或者多服务跑批等形式;
上面,来谈谈重构中的接口迁徙;
要保障一个准则,就是对接口的出入参放弃不动;不然,前端间接飞过来跟你聊人生;
然而,老服务的接口很多怎么办?还能怎么办,分工解决;
下面提到过,咱们是分组的形式,每个组负责一部分服务,分工比拟明确,所以相对来说,也比拟快;
大家整顿文档,老接口的 URL 是什么,新接口的 URL 是什么,出参,入参能不变就不变;如果真的须要调整的,须要给出正当的解释,大家统一通过后,而后自行跟前端去 battle;
有些老服务还会运行一段时间,所以并不是所有接口都会波及到迁徙,这种接口,那就相安无事;
在迁徙的过程中,必定也会遇到各种问题;比方举个简略的例子,之前老服务的分页插件应用的是 PageHelper
;而在新服务中,因为用上了Mybatis Plus
框架,那天然也就用它框架自带的分页插件了;这个时候就波及到批改,你只能本人外部消化了;
最初,当你感觉所有接口都迁徙结束的时候,别忘记对本人迁徙的接口,进行一次自测;不要怕麻烦,这个自测对于前面的联调和提测流程,都能够免去很多不必要的问题,也能够大大提高团队的效率;
09
【实现计划】
最初还有一点,业务场景的实现计划;这个听着有点形象,其实在下面说的会议中,也会波及;
不要认为这只是技术的决定,其实产品的参加也是很有必要的;你品,你细品;
我拿一个经典场景举例,A 账户往 B 账户打钱,而后零碎是微服务,很相熟吧;
没错,就是分布式事务的一个经典场景,要保证数据的一致性,A 被扣钱的同时,B 要加上相应的钱;
分布式事务我不多说,置信很多同学轻易一查,各种形形色色的计划;
然而这里我只讲一点,达到数据统一的工夫节点;你是要什么时候保障这个数据达到统一,也就是说,强一致性还是最终一致性;
要求强统一必然是就义掉一部分性能的,要求最终一致性就有可能在一段时间内产生数据不统一的问题;
这个时候,就须要拉上产品经理,跟他论述其中的原因,阐明技术计划上无奈躲避的点,让他做取舍;
有的时候,好的设计往往能躲避技术上的难点,也能够节俭开发的老本和工夫;
所以,在探讨这块内容的时候,必须要有产品经理在场,提出设计上不合理之处;咱们不能只局限于钻研技术问题,其实换个角度,或者你质疑的点,就不存在了;
记得实习的时候,公司的老板讲过一句话“人人都是产品经理”,当初回过头一想,还真是那么回事;
大胆的提出本人的意见,做一个有本人主意的小码农;
10
对于零碎重构,我就以一句话结尾吧,这也是援用了一位大佬的话,“对公司现有的资源和策略斗争,在技术栈和计划之间取舍”。
编程文档:https://gitee.com/cicadasmile/butte-java-note
利用仓库:https://gitee.com/cicadasmile/butte-flyer-parent