车金融|GPS审核系统的前世今生

GPS审核系统历经前后几次自主创新重构以及在需求迭代中小规模重构优化,系统最终能持续半年需求不再迭代,这背后多少有重构带来的变化和影响。GPS审核系统并非最初就有,它仅仅只是原先一个庞大既臃肿系统中的一个业务功能模块,团队负责期间不断成长蜕变,最终实现“丑小鸭变白天鹅”的故事再现。作为见证艰辛历程的我,此刻想跟大家那段“春秋战国”往事,相信通过这篇文章能带来你职业生涯或架构设计的启迪。

【温馨提示】:最近推出《金融产品中心的前世今生》后,借着兴致,再推出新作。整篇文章共计5800余字,全是地铁旅程中手机码字,实属不易。此外,又多次润色。文笔不佳,敬请原谅。感谢读者能够认真阅读完毕,相信你从中不少收获和启迪。感谢读者的关注,我将后续继续推出此系列文章。

秋夜无霜
车金融|金融产品中心的前世今生

车金融|GPS审核系统的前世今生

车金融|基础数据平台的前世今生

车金融|合同中心系统的前世今生

车金融|金融产品规则引擎的前世今生(上篇)

车金融|金融产品规则引擎的前世今生(中篇)

车金融|金融产品规则引擎的前世今生(下篇)

车金融|我在M公司的那两年

一、导读

GPS审核系统作为车金融业务线一个小众边缘的审核系统,其核心价值在于通过安装GPS以确保放款后,贷款给客户的车资产,提供一种反欺诈途径,也是一个放款前必须审核通过必要条件。因此,它的意义在于确保财产的安全性提供了一种有效的保障手段。也有效对于客户车辆被盗时为侦查提供一种有效手段,所以业务审核意义非凡,必不可少。

从整个获客,到贷款意向,到授信签约,最终到放款进件前,GPS审核业务动作必不可少。GPS审核在于确保设备按照不同车型遵守安装规范,放款前确保设备正常工作有信号。

我们技术团队对业务系统的重构,则是从系统架构和扩展性伸缩性出发,致力于提供更稳定的服务,适应公司业务发展规模,提高系统的维护性和易用性,提升审核人员的运营效能,从而提高整体团队运营效能和研发效率。

二、重构前夕

重构前夕

清晰地记得入职之初,我接触的第一个需求就是GPS审核模块的一个页面交互业务调整,也就是从那一次邂逅,为今后我和GPS审核系统结下不解之缘。

入职时的第一周,我是在陪同加班一周度过的(其实内心不忍心离开座位,毕竟大家都不离座位,我于心何忍),至今历历在目,仿佛昨日。那一刻,让我觉得到我所处的研发团队是一个很拼搏的团队。

我觉得很庆幸,能够加入这样一个团队可以促进成长,可以向大家取经学习新知识,新技能。看着他们每次下班后,依然面对着电脑,或沉思,或凝视,或叹声。我觉得这是一群有趣有灵魂的小伙伴。午饭后,他们陪同老板一起相聚玩荣耀不亦乐乎,但作为不爱好游戏的我,自然觉得无法入围,只得寻其他小伙伴公司楼下走一走。聊聊人生,聊聊未来,聊聊我们的公司和团队。

我们车金融研发团队有一个技术栈相对较老的系统(别看老,据说价值千金),它基于SpringMVC,ORM基于Hibernate,前端则使用JSP架构。这些技术栈,此刻的你倘若是工作好几年的服务端工程师或许听闻过,但对于工作两三年的你或许前所未闻。团队中一些新系统应用则基于springboot,RPC服务基于zookeeper+dubbo,唯独这个老系统格格不入。

我负责的第一个需求宣讲场景是这样的,一个产品经理(당김해)来到我的工位,讲道“这里的弹出窗口,在表格的这个栏位,需要支持可以选择多个审核退回原因……”,我是以这种方式接触在新公司的第一个需求,跟离职前公司神州专车可谓大径不同。

第一次在本地构建部署这个老系统应用,由于我刚刚新买的Mac Pro,按键操作和触摸板有些不熟练,看着Tomcat的启动许久输出日志,看到一个亮眼的红色错误日志。 “无法找到文件路径” ,我查看属性配置文件,看到一个写死代码的Window磁盘路径,顿时赞叹不已。我于是修改兼容Mac操作系统文件目录,重新构建部署,又过了许久,看到服务部署启动成功,服务启动耗时将近两分钟。

后来的几天,我抽空认真研读了几个模块的代码业务逻辑以及代码编写风格,但作为追求代码设计以及代码规范的我,相信当时的我是何种一种心情。此刻的我,应该持一种包容,毕竟这个项目肯定经过一个特殊时期,项目时间研发紧张能够顺利上线,实属不易,我们的确不应该以今人的眼光看待那些令人不爽的瞬间。

项目工程源代码Java源文件三级目录包打开后,自上而下占据着我的13.3寸屏幕,再打开子包目录,文件数目更是令人吃惊。web目录下大量的js文件以及jsp文件,静态资源文件更是数目众多,我很难一睹风采,就默默在心中赞叹不已,这个老系统承载着多少往事。

这个需求第一次上线情景,研发人员构建部署有一个平台(Jaguar),当时发布时间并没有多少限制,一级人员审核通过,即可随时构建发布。但那一晚,上线似乎并不顺利,小小的一个需求,没想到在线上回归测试就发现了问题,尽管最终历经千辛万苦找到bug,并修复重新上线。我们看到GPS审核相关的业务逻辑,混淆在一些不相关的service模块中,类之间的关系也是非常不清晰,从那一刻,让我清晰的认识到这些代码设计真的很糟糕。

此刻回忆起这些岁月往事,印象深刻,但它自那一刻起在我心中便立下一个flag,期望有朝一日我可以带领团队重新重构它。我带着一个小小的愿望,埋在心间,期待着,憧憬着,一天天就这样过去了,终于有一天……。

三、重构历程

3.1 初探重构

这次重构“初探”,是因为我于心不忍那些糟糕的代码一次次伴随需求迭代再次映入眼帘。坦白讲,每一次业务逻辑调整,涉及不仅仅只是你修改一个JSP和Java文件,而且很多相关的代码为了复用反而写的更加复杂。

有四个查询列表页面,通过ajax从服务端获取数据,涉及不仅仅是一个service类,竟然是多个。其中一个service模块通过页面请求参数标识,服务端代码通过大量的if判断逻辑,实现不同页面查询条件的路由逻辑,而且竟然SQL和HQL混淆其中,总之代码很糟糕。我思考了许久,我并不是犹豫去改造它,毕竟初来乍到,再修改出bug让领导觉得你能力不行啊!其实,我不怕,我也相信我可以重构它,即便风险大,但确实有值得,重构之后下次再变动,快捷键快速定位到Java类源代码行,我无需再一个个去找。

我尝试使用设计模式重新设计这个数据查询列表模块,通过模板方法和策略模式重构这段代码,四个查询页面即抽象类的四个子类,同时抽象类抽象出两个抽象方法(SQL和HQL查询方法),如此设计既可完成现有业务逻辑对接。这是我第一次设计尝试运用设计模式解决大量的if条件判断场景的应用实践,心中颇为满意,凝视着自己第一次重构的代码,那一刻觉得颇有成就感。这段代码重构就这样在需求迭代中不知不觉上线了,但的确没有出现故障,可见背后我也为此做了很多充足的功能测试工作。

【设计模式活用】之代码重构之DAO扮演多个职责的重构案例

上述这篇文章可以具体查看代码设计,这里不做过多讲述

3.2 服务解耦

应用服务拆分前后变化

曾经一直配合功能测试的一位同事(Xiao-wei),曾说过,每次修改GPS审核,上线或多或少都问任何坑。不仅他怕,我也怕,坦白讲代码太凌乱了。

gps-provider的诞生

之所以把GPS服务单独拆分出来,是为了GPS服务可以方便部署,作为跟进几次需求迭代的我,不希望再次碰那个我认为很糟糕的服务应用(lyqc-crm和lyqc-loanapply),lyqc-loanapply依赖若干个dubbo服务,然后通过lyqc-crm代理包装提供http接口服务,我希望GPS审核也可以独立出来一个应用服务,后续我只需要维护这个单独的应用即可逃离苦海。

这次服务拆分是在一个大需求中并行开展的,我抽出额外时间重新设计这块业务逻辑。但它的意义在于,GPS审核服务成为我在这个团队第一次重构的案例,意义非凡。我把它命名之“gps-provider”,正体现我之初衷和用意。

gps-web的诞生

它与之gps-provider的角色和定位不同在于,它是为审核人员运营平台功能提供后端接口服务的。最初对接老系统,提供接口服务,便于后期前端分离奠定基础。为什么还要再拆分一个单独的服务,在于简单来讲一个提供前端审核使用,一个面向APP和其他业务系统对接。

之所以如此架构设计,始于我曾经在神州专车的项目架构演进经历。最初的司机系统不仅仅提供给APP端接口服务,还有运营端平台功能接口服务。但后来的需求迭代,以及上线部署涉及的影响,使得我们如此拆分可以降低线上故障产生的频率,此外更有利于提高系统的稳定性和可用性。

3.3 重塑交互

前端重构变化

尽管对接web的服务端重构工作已结束,然使命未结。前端页面依然需要依赖老系统开发维护,伴随着车金融重构的声音越发高涨,曾高呼“前后端必须分离”的 Mr Suk-sok 양 석 섬早已开始审核系统的重构工作。我们团队不甘落伍,GPS审核系统重构正值良机。恰巧前端资源丰富,于是从前端协调过来一个开发工程师(Jie-chao 뎡 겨초同学),开始我们前端技术架构的重构之路。

前端团队技术栈当时主要以VueJs和ReactJs为主,前端工程师之所以选择ReactJs的缘由,是因为他告诉我项目研发不能少了这种语言的存在,前端领导也想推行这个语言的应用实践。然而,此刻对比者两种前端框架语言,毕竟国内VueJs的用户人群相比之下更多。其次,从代码开发角度来讲,我看到业务线内部很多项目VueJs是基于模板与业务逻辑实现代码分离,我比较赞成这种设计思想。不像ReactJs混淆一起,不方便开发维护。即便从零学习前端的我,反而认为VueJs学习成本更低。

这次前端页面重构期间有一个小故事,审核系统已上线有个订单详情页面模块,而对于GPS审核人员也需要显示订单详情页面,以辅助审核人员查看客户信息和车辆信息。最初我们的技术方案,无需前端再开发,让审核系统的前端提供一个页面url,数据从审核系统获取加载。当时认为这种方案比较好,是因为毕竟已有一个完善已存在的模块可以复用。此外,为了缩短研发周期,最初审核系统的前端开发Jing-xian也同意这种技术方案。

然而,审核系统需求迭代快,我们重构尚未上线,Jing-xian突然不同意这种技术方案。他给出的理由是,审核系统需要兼容两个业务系统(GPS审核系统和审核系统)的业务逻辑和数据展现。无奈之举,我们团队不得从零开始重新开发,并直接让前端参考他们的页面设计,数据则由服务端(gps-web应用)提供接口服务。

我们在测试环境,并未申请宝贵的测试资源介入功能测试。我们团队相信研发自主可以完成功能测试,GPS审核同事也可以帮忙,并最终实现顺利上线。上线期间,并未下线老系统功能,而是与新系统并行了一段时间,我们同GPS审核的负责人(Xie Jie 헤 겸)沟通了我们的上线事宜和灰度方案及计划,期望他们可以介入提供协助支持。

GPS审核同事(譬如Yi-min 강 임민 同学)特别给力,并鼎力配合我们的线上灰度,也相信我们重构将带给他们功能交互上更好的体验,进而提升他们的审核效率。坦白讲,我非常喜欢这种沟通协作方式,可以面对面了解前线人员的痛点,进而收集一线资料,从而为系统优化提供案例基础和宝贵资料。

由一个用户试用新系统功能,尝试体验和功能良好的前提下,让更多的用户切换到新平台,有问题及时跟进排查尽快修复安排上线,倘若遇到流程阻碍性问题则切换到老系统,正是这种灰度方案和协同机制最终完成全量用户切换。

对于GPS审核人员,我们能够确认人数并找到相应对接人,然而通过系统角色查询的用户必然人数更多,我无法通知所有人去切换到新平台。因此我选择通过公司钉钉拉进一个沟通群,并确定哪些人员正在使用,哪些人员曾经某一段时间使用。我找到了两个运营负责人(A Yang 양 과왜 和 Jennie 조 수현),沟通了目前重构和灰度情况,并声明我们要下线老系统。

就这样,为了更友好的表达我们研发的诚意,我代表团队发送了一封邮件抄送给相关人等,同时抄送给老板以及产品团队人员,通知老系统将要下线,新系统确定的人员角色我会重新授权,不确定的人员新系统不会支持使用。倘若如有人员使用系统功能,则邮件回复重新申请授权即可。

胜利的曙光就在前方,繁杂的事我来操办,作为一个技术团队负责人,我认为有义务,也应该更漂亮地完成这次重构工作。这次重构工作不仅提升了我们团队相关人员的技能,学习一下整个GPS审核业务知识,侧面也增深了我们研发团队同审核、运营、产品以及其他团队的信任和情谊。

3.4 支援前线

自重构伊始,期间GPS审核需求也没有相关产品对接负责。恰巧这段时间跟GPS审核同事沟通甚密,日常通过微信沟通完善系统一些功能优化。GPS审核只是整个车金融业务线上一个子系统流程,所以影响甚少。我们优化不少功能,包括相关查询列表页面的数据展示,以及增加相关领单派单等附加功能,辅助审核日常运营,提升他们的审核效率。

3.5 MySQL拆库

MySQL拆库项目计划

尽管GPS审核服务拆分上线运行将近一年载,然而此系统的若干个数据库表依然公用原老系统的数据库(这个库大概有300多个表,由于需求不断迭代以及相关业务的废弃或迁移,很多表早已废弃不再使用),这也造成了潜在风险隐患。虽然不同团队小组已拆分不同的系统服务,由于各服务共同一个数据库,倘若出现数据库服务器突然故障或出现SQL慢查询,其实不仅影响自身业务系统,而是影响一系列依赖数据库的应用服务。

这种隐患问题一旦碰到,则是非常致命的。曾经线上出现一次故障,由于GPS应用服务涉及调用三方系统的一个GPS设备自动校验接口。这一天,大量请求三方接口长时间不返回响应结果,由于GPS审核系统内部业务逻辑恰好属于同一个数据库事务处理,导致数据库连接申请后。由于外部服务阻塞,无法释放数据库连接,进而耗尽所有空闲连接和最大连接数。

最终导致应用服务提供的下游服务,从而影响app端,而销售又不断尝试提交。由于链条上其他应用服务也公用这个数据库,而数据库服务器最大连接数也是有限的,因此数据库服务器CPU增高,影响了整条链条的业务。

虽尽管DBA人员强制杀掉一些客户端进程,但是由于GPS应用服务本身对外依赖的服务没有设置网络连接超时时间,所以问题依然不断产生。最后不得快速修改代码设置超时时间,重新部署上线,最终才慢慢恢复常态。

因此,这一次出现线上故障后,我们便快马加鞭规划拆库目标。拆库遵循表结构不变为前提,上线时,则通过运维人员停止GPS应用服务,然后DBA人员开始迁移表数据。迁移完毕后,构建发布应用服务(该Tag版本基于新数据源),最终完成拆库上线目标。

拆库后,GPS审核系统维持一段稳定运行时期,也便于开展后续的进一步重构优化工作。尽管伴随着车金融订单系统的诞生,GPS系统从业务流程都维持清晰的业务模块划分,保持基本的基调不动摇。

MySQL拆库上线流程方案

3.6 大刀阔斧

GPS审核流程重构预研前后对比

2019年上半年,我们团队不断壮大,除了需求研发之外,我们团队依然保持自主创新,保持我们的团队特色。我们团队计划部署一项重构任务,鉴于前期GPS审核系统虽然服务拆分,但是伴随着需求迭代,考虑业务场景的复杂性,我们有必要需要把整个GPS审核系统以业务场景动作以及审核流程状态机两个维度展开重新设计。由于已拆分两个系统(gps-provider和gps-web),但是相关业务代码从代码设计上并不良好,也不易于扩展维护,譬如分布式锁的获取和释放,GPS领单和派单,派单的策略模型。

我从团队抽出两位能将( Ling-yu 상 령욱)和 (Kang-kang 반 강강),由Ling-yu负责整体重构方案的预研和梳理,团队一块统一过目整体设计方案。技术方案通过确认后,则由Ling-yu主导,与Kang-kang一块负责代码整体设计与实现。

重构时团队做的技术方案,其凝结着Ling-yu背后付出的汗水

>上述是Ling-yu同学做的充足的技术方案预研,把GPS审核的每个业务场景重构优化对比都有清晰的描述,以及给出重构优化的缘由。这里,感谢我们曾经的小伙伴。

按照技术方案,团队经过一周多代码重写后,然后自测所有业务场景功能点。我们寻找合适上线时间点,配合灰度方案,最终完成顺利上线。

梳理的人工派单业务流程图
梳理的人工审核业务流程图

设计模式的巧妙运用

策略模式+模板方法模式+工厂模式+委托在代码设计的运用

这次重构,考虑生产业务场景的多样性和复杂性,把多个业务操作进一步抽象封装,基于策略模式等,模板方法等设计模式的运用。有效提高代码的扩展性和维护性,使得各个业务场景操作通过子类实现的业务逻辑分离,同时也提高了代码的复用性和阅读性。

一个查询列表基于设计模式重构案例

上图是为了解决多个查询列表大量冗余代码问题,基于设计模式(策略+模板+适配器等)重构实现案例。

参考相关博客:【设计模式活用】之接口改造案例的设计思路(代理、适配器、工厂、模板方法)

四、正定乾坤

GPS审核从最初的一个边缘模块,到应用服务的拆分,又到GPS数据库的拆分,期间又经过几次大小的重构,前后历时一年多时间。经过一次次重构,使得我们的系统服务更适应业务的发展趋势。从技术架构而言,则是为和伸缩性扩展性奠定基础。

伴随着重构步伐的谢幕,系统经过几次需求迭代,都不会让研发人员陷入曾经的痛苦之中。有了重构优化带来的变化,我们研发团队也能在闲暇之余喝喝茶,聊聊天,何乐而不为。

此外,重构优化的结果使得系统可维护性有效提高,复杂的业务场景通过更良好的代码设计,使得我们即便一名新的研发人员也能快速应对。这就是重构不断优化的结果,也是重构优化的质变潜在力量所在。

五、尾语

这篇文章自2020年11月5日开始起稿,期间则是在地铁途中通过手机码字完成这篇鸿作。前后5次校稿,耗费5个多小时。今日2020年11月10日方才完成定稿,恰逢薪水发放日,值得纪念。

秋夜无霜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值