作者 | 肖迪(墨诩)
来源 | 阿里开拓者公众年夜众号
序言
优酷CRP系统-内容采购版权管理系统,是个存在10年的老系统,技能框架上比较老旧;再加上”人来人往“,一定存在很多”不合理但是能跑“和”不敢改,以是ifelse“等等经典代码,一共81w行java代码,17w的jsp代码。我在今年全面接手CRP-财务部分,整体目标便是全面推进CRP财务的业财一体进程。而这些遗留的技能问题都是推进进程的寻衅,以是CRP财务本财年的技能主题便是“老系统重构”。
根据以往的事情履历,面对这样的系统,大开大合的重构改版,带来的每每是更加灾害性的”业务不可用“;以是我们的策略,还是要秉着业务优先的原则,跟随业务新需求来逐步重构。但无论产品还是研发心中都要有同一张大图,我们终极要做成什么样子。然后根据大图划清各个业务模块的边界,在担保不会影响其他模块的运行的条件下,进行重构。
81w行java代码中,实在大部分都是废代码,比如:功能和做事还在但是没有人利用;数据都已经迁移到其他系统,下贱也不在实际利用,但依赖还在;有很多job还在运行,但并没有实际的数据产出利用方。之前重构的时候跟组里同学开玩笑说“如果随机注释掉一个service中是所有方法实现,系统大概率还是work的”,虽然我们不会这样做,但可能是真的。对付这样的系统,重构的策略如果是重新梳理所有做事的利用情形,无疑是本钱特殊高的,roi很低。以是该当按需重构和迁移,并担保下贱依赖方的不须要做任何改动。
本篇文章会以个中一个模块“付款”来作为示例,缘故原由有二:
一、本财年付款的改版业务述求比较高,这个S的重构进程较其他模块更快一些;
二、想表达的主题更专注在代码重构方向。付款作为全体优酷运营中比较末端的商业行为,在系统上对付付款依赖的下贱系统和模块较少。如果是写“条约迁移和改造”,会更偏架构重构和老系统、数据的迁移方案。
付款模块一共涉及大概3w行旁边的代码,首先担保下贱依赖的接口都不变,还在原有工程做事,并且将老代码迁移到新的工程下。是否迁移工程取决于与迁移的ROI,我们的老工程的前端是用jsp实现的,现在要做前后端分离,以是老代码迁移到新的工程下。
付款
重构的第一原则因此业务为中央,不要为了重构而重构。先来理解一下付款的业务和业务的痛点。
付款要办理的业务问题
付款紧张办理俩个问题:1、0资损;2、流程效率
我通过MECE的从下而上的归纳整理后,谨严判断想法建议的“最小公倍数”的方法,对付款进行梳理,先理解一下付款在做一件什么事,以及如何完成目标?
给谁付:收款人是谁?是否有财务或者法务上的风险?以及须要验证对方供应的发票为谁付:决定了付款的本钱归属,归属到节目、部门或者财务口径的入账科目上付多少钱:是否存在应收款和搪塞款可以互抵的情形?付款依据是什么?税费如何打算?怎么付:通过什么办法支付,先票后款还是先款后票,是否支持预约付款?能不能付:根据不同业务场景以及金额,流转到不同的审批人进行审批。将这些要办理的业务问题向上抽象总结,付款要想做到
0资损:信息校验:很多根本信息的校验,最基本的不能付错人风险拦截:包括风险供应商拦截和风险金额的拦截金额精准:依据条约、账单、项目等打算出搪塞金额,然后进行对抵和税费打算(如有)金额依据状态同等:既然金额的精准决定了最多付多少钱,就要担保金额依据与付款单的状态同等性提高流程效率:自动凭据入账多种付款办法的支持快捷的流程审批到这里该当可以看出来,付款不是一个繁芜业务流程的模块,它的核心述求是“稳定”与“可扩展”。从这个季度的需求也可以验证这点
付款的技能痛点
代码臃肿,扩展性低
付款有个特点,没有很繁芜的业务流程,但是涉及到资金,在付款之前须要做很多的金额打算和风险校验。而且其余一个特点,付款作为一个工具性子的模块,会接入很多业务方。不同的业务,在金额打算、风险校验等流程上基本同等,但实际接入实现的时候,会有或多或少的差别(比如,付款金额的依据上,主客和OTT会有不同类型的账单)。可以看出付款这部分对付复用性、扩展性哀求是比较高的。现在要接入OTT的付款,我们先来看一下如果连续在老代码长进级,会有哪些问题。
@Override @Transactional(rollbackFor = Exception.class,transactionManager = "transactionManager2") public Payment submitPayment(PaymentDto paymentDto, User user) { 只保留能解释问题的关键代码或者注释,省去前全体方法600行旁边 payment工具初始化代码 ...省去60行代码... Integer r = paymentDao.insertPayment(paymentDto); payment付款依赖工具初始化代码 //保存关联节目 playComponent.dealPaymentPlay(paymentDto.getId(), ListUtils.emptyIfNull(paymentDto.getPaymentPlayDtoList()), user); //保存文件 appendixComponent.dealFile(paymentDto.getId(), ListUtils.emptyIfNull(paymentDto.getFileDtoList()), user); //保存账单 paymentAssociatedBillComponent.dealBill(paymentDto.getId(), ListUtils.emptyIfNull(paymentDto.getBillDtoList()).stream().map(AssociatedBillDto::getBillId).collect(Collectors.toList())); //保存任务人和其他操作人 comPermissionComponent.saveComPermission(paymentDto, "ALL"); 第一步做金额和风险校验,为大略只保留注释,省去实当代码 //1.校验重复提交 ...省去5行代码... //2.提交前校验 ...省去20行代码... //3.校验账单金额&&所属公司 ...省去5行代码... //4.校验娱乐宝账号 ...省去1行代码... //5.校验付款条件 checkPayCondition(payment); //6.校验节目金额 if (paymentComponent.needPaymentToPlay(payment.getType())) { checkPaymentSubject(payment); } 校验过程中混入payment工具初始化代码 CrpContract contract = crpContractDao.getContractById(payment.getContractId()); Integer operationFlow = contract.getOperationFlow(); payment.setContractOperationFlow(operationFlow); //7.校验本次申请金额是否超过预期 ....省去40行代码... //8.仅版权采购条约支持预约付款 if (){ throw new RuntimeException("仅版权采购条约支持预约付款!
"); } //8.校验预约付款不能选择先款后票 if (){ throw new RuntimeException("预约付款仅支持先收票后付款!
"); } //9.版权采购&&收款账户国家为CN&&签约币种为RMB 才可以利用预约付款 ...省去10行代码... payment工具初始化代码 payment.setApplyDate(new Date()); ...省去40行代码... 多了一次没有必要的数据库update paymentDao.updatePayment(payment); payment工具初始化代码 String actualApplyWorkNo = payment.getActualApplyWorkNo(); ...省去10行代码... paymentDao.updatePayment(payment); //异步提交审批流 BpmsDto bpmsDto = new BpmsDto(); ...省去10行代码... return payment; } private xxx(){}
比较范例的“流水账”代码,最直不雅观会导致的问题便是掩护困难,比如想查一个字段禁绝确的bug,最差情形要通读600+代码(还有部分private方法)。在升级的时候,最随意马虎想到的办法便是连续盖楼(比如代码中调用了俩次 paymentDao.updatePayment(payment),该当便是盖楼的时候,代码复制多了),从而使“泥丸”越滚越大。
剩余60%,完全内容请点击下方链接查看:
上线十年,81万行Java代码的老系统如何重构
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开拓者社区不拥有其著作权,亦不承担相应法律任务。详细规则请查看《阿里云开拓者社区用户做事协议》和《阿里云开拓者社区知识产权保护指引》。如果您创造本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将急速删除涉嫌侵权内容。