项目模块重构分享与思考

code小生,一个专注 Android 领域的技术平台

作者:黄俊彬
链接:https://www.jianshu.com/p/25688ed4777f
声明:本文已获黄俊彬授权发表,转发等请联系原作者授权

背景

云盘产品,文件模块的业务功能相对复杂,包含文件的显示、排序、筛选、加密隐藏、批量移动复制等功能。项目代码可以追溯到14年以前,中间也有N多人的接手,目前还是存在非常多问题,维护及扩展也是相对比较吃力。

最近由于产品功能正在策划,大约有一周时间可以对项目进行优化。故决定对文件模块进行梳理重构。在开始之前,这里先抛出几个问题,相信大部分的同学也可能有类型的疑问,在文末的终结也会谈一下自己的看法。

  1. 业务需求频繁,开发功能都来不及,哪里有时间进行代码重构

  2. 公司并不看重代码质量,首先要满足功能开发。重构这个事情,做了也不一定被认同。等一下重构后,产生新的问题,后果更严重

  3. 这代码改起来真是蛋疼,好几个类功能都一样,新增或者修改都需要改几个地方。但是没办法,为了赶时间,暂时先这么干吧

  4. 想重构,但是却不知道如何下手。有时候有点空闲的时间,又感觉不够。所以一直没有动

文件模块情况

简单类关系图

这里简单介绍一些文件模块目前的一些问题。先看一些类的关系图。

640
image
类说明
说明
MyFileFragment显示文件及文件操作的Fragment
FileMainActivity文件主页面,依赖MyFileFragment
BaseList2Activity文件列表基类,显示文件
MyFileActivity作用和MyFileFragment相同,全局很多跳转到文件页面都是使
DiskMusicActivity音乐模块,从网盘导入音乐文件,是一个提供音乐文件选择页面,继承了MyFileActivity
AddAttachmentActivity聊天模块,从网盘选择图片,是一个提供图片文件选择页面,继承了MyFileActivity
DiskSearchActivity文件搜索页面,继承了MyFileActivity
FileListBaseFragment文件展示页面,与BaseList2Activity类似
FileChooseActivity网盘文件选择页面,是一个提供选择文件页面,依赖FileListBaseFragment
主要存在问题

在项目的开发维护工程中,主要存在的地方如下:

1、存在多个功能相似的页面,例如MyFileFragment及MyFileActivity,功能高度相同。全局跳转到文件页面使用了MyFileActivity,文件主入口使用了FileMainActivity。由于历史原因,一直维护着2个类,新增功能和修改功能都要维护2个地方

2、文件列表显示存在多个类,BaseList2Activity、FileListBaseFragment、MyFileFragment

3、文件选择也有多个页面,音乐选择一个DiskMusicActivity、图片选择一个AddAttachmentActivity、还有附件选择一个FileChooseActivity

经常出现产品加一个功能,要几个类修改,并且有时候修Bug容易遗漏地方。

重构

思路

在准备开始动手重构之前,先梳理了一下思路。

1、先搞清楚目前存在问题,哪里不爽。分析解决问题的方案

2、尽量不要动到原有的业务逻辑,着重于结构的升级

3、分解重构执行步骤,尽量细化成小任务,每个任务不相互影响。由于时间有限,争取每完成一个小步骤的重构,都能达到上线的状态

执行

根据目前存在的问题及重构思路。本次重构主要解决3个大问题。

1、在项目中要干掉MyFileActivity,统一使用MyFileFragment。不要再同时维护2个相同的功能的类

2、统一文件列表的显示,避免出现多个显示文件的类

3、全局应该统一一个文件选择的页面。避免出现选择音乐一个界面、选择图片一个界面、选择附件又一个界面

阶段一
阶段一主要有优化处理1、2点。这里先上一下简单类结构关系图

640
image

1、将MyFileActivity移除,新增BridgeFileActivity(继承了FileMainActivity),替代MyFileActivity。将全局文件跳转统一替换到BridgeFileActivity,BridgeFileActivity最终依赖了MyFileFragment。这样将文件主要操作的代码统一在了MyFileFragment,避免维护多个相同功能的类。

2、将文件的基础显示都FileListBaseFragment中,MyFileFragment继承于它。MyFileFragment扩展文件的操作功能。如删除、复制、移动、加密等功能

3、由于MyFileActivity的移除,原继承于它的DiskMusicActivity、DiskSearchActivity等都需要进行改造。重新定义DiskMusicFragment、DiskSearchFragment继承于MyFileFragment。将原来的Activity依赖于新定义的Fragment。

至此完成第一阶段,对原业务都未进行修改。只是将跳转入口进行替换。成功移除了MyFileActivity。解决上述问题1、2。

阶段二
阶段二主要优化第三点,并且重新命名类名。同样先上下简单类结构关系图

640
image

1、对FileChooseActivity进行扩展,使用Builder模式进行配置,支持文件类型的筛选显示。废除DiskMusicActivity、AddAttachmentActivity。

音乐筛选页面代码跳转:

FileChooseActivity.IntentBuilder builder = new FileChooseActivity.IntentBuilder(this);
        builder.setChoiceMode(ChoiceMode.MULTI)
                .setEventBusFlag(Signature.signature(this))
                .setShowLocalFileList(false)
                .setYywSelectType(FileChoiceParams.MUSIC)
                .setSupportCheckAll(true)
                .launch();

图片筛选页面代码跳转:

FileChooseActivity.IntentBuilder builder = new FileChooseActivity.IntentBuilder(this);
        builder.setChoiceMode(ChoiceMode.MULTI)
                .setEventBusFlag(Signature.signature(this))
                .setShowLocalFileList(false)
                .setMaxLimit(15)
                .setYywSelectType(FileChoiceParams.PIC)
                .setSupportCheckAll(false)
                .launch();

总结

回到一开始抛出的问题,这里做一下自己的总结思考。

1、业务需求多,时间赶这是常态,时间要靠自己规划及提高效率挤出来。在开发的时候也要充分考虑,不能盲目追求功能实现。 一般项目上线后,新功能策划都有一段空白期,善于利用

2、不管公司重不重视代码重构。首先多思考、优化重构,对自己也是一种提升。相信在重构的过程,自己也可以有所收获

3、项目存在种种的历史遗留问题,有时候重构与不重构就是一个长痛和短痛的取舍。自己负责的模块代码不优化,加需求,改Bug,最终坑的还是自己

4、项目重构是不断演化的过程,没有一蹴而就。

有关重构技术

祖传代码的重构体验

640

分享技术我是认真的

项⽬重构⽅案设计 最近接⼿到⼀个已经成型的项⽬,然后我们的任务就是对它进⾏重构,这个项⽬是⼀个功能很齐全的WPF视频播放器(附带很多其他功 能),在仔细研究了项⽬的背景和架构以后,初步做出了⼀下的重构⽅案: ⽬前现状: 虽然整个系统做得很漂亮,代码也写得不错,但仍有以下不⾜: 1. 架构有待改善。虽然看似MVC架构,却没有遵循MVC的模式,⾥⾯逻辑和UI耦合很⾼,没有清晰的规律。 2. 没有充分⽤到WPF的特性。WPF除了给我们很多炫丽的效果外,还给我们提供了诸如Binding,command等特性,这些特性可以帮我们隔开耦合, 同时减少代码量。 3. 代码和⽂件没有组织。代码、dll、样式⽂件和资源⽂件等没有统⼀的组织,到处都有,这样看起来就会很混乱。 4. 没有建⽴公⽤代码库。没有把公⽤的代码库独⽴出来,很多地⽅都是另外在写,这样既增加了代码量,同时维护和重构也带来了⿇烦。 5. 逻辑处理不应暴露在Client端。项⽬是⼀个C/S架构的系统,没有必要把所有的逻辑都暴露在Client端,应该⽤分布式把Logic放在服务器端,这样 可以更安全同时使客户端变⼩。 6. 没有单元测试。这样⼀个庞⼤的程序,没有单元测试是⾮常危险的,我们不可能做到100%的覆盖率,但是我们可以对主要的逻辑和Function做单 元测试,这样既减少了测试⼈员的⼯作量同时整个系统的安全、稳定和可维护性得到了⼤⼤的提⾼。 7. 性能不够优化。启动项⽬,通过WPF性能⼯具Perforator和Visual Profiler分析得出,程序启动和界⾯操作都导致CPU很⾼,内存也消耗⽐较多。 解决⽅案 1. 1. 针对缺陷1的"架构问题"。做法是采⽤MVP或者MVVM模式,⽬前正在对⽐和考虑。 2. 针对缺陷2的"WPF特性"。做法是充分利⽤Binding,command等特性。 3. 针对缺陷3的"代码和⽂件没有组织"。做法是建⽴⼀些单独的⼯程或者⽂件来分类和组织这些代码,并且充分隔离 耦合。 4. 针对缺陷4的"没有建⽴公⽤代码库"。做法是把⼀些公⽤的代码和常⽤的代码做成单独的Dll,并且有完整的单元测 试,这样才能提⾼效率。 5. 针对缺陷5的"逻辑处理不应暴露在Client端"。做法是⽤WCF做为中间层,把业务逻辑全部进⾏封装,通过WCF提 供统⼀的接⼝供项⽬调⽤。 6. 针对缺陷6的"没有单元测试"。做法是不管⽤MVP还是MVVM,我们起码保证对逻辑组件的代码有充分的单元测试 覆盖,同时对⼀些公⽤的组件也要有单独的单元测试代码。 7. 针对缺陷7的"性能不够优化"。这个我会单独做⼀个性能优化列表出来,针对耗资源的操作和其他有损害性能的操 作,我们应该避免。 8. 那么我们就可以结合实际情况搭建如下的结构 9. 10. 因为使⽤了MVVM模式,所以UI结构图就做如下调整 11. 12. 由于整个项⽬客户部希望我们引⽤第三⽅的组件或者⼯具,所以很多功能都只能通过企业库实现,⽐如AOP和 IOC,log和exception对项⽬特征做了定制化,数据访问通过企业库重写实现局部ORM,对性能要求⽐较⾼的应⽤仍 然实现存储过程。对所有事务操作都转移到数据库,邮件使⽤JOB进⾏发送。⼤型数据和客户要求较⾼的实时操 作,⽤MSMQ和SSB相结合的⽅式。层次依赖关系 UI: 功能模块使⽤时候,都会⾸先通过UI层次Security模块的安全验证(验证是通过Components模块⾥⾯的⾃定义的⽤于页⾯功能以及功能 点验证的控件触发), Security模块会通过服务层获取⽤户⾝份数据,⽤于页⾯验证. 功能模块的实际功能实现,如果需要数据库⽀持,那么依然会通过服务层进⾏数据操作.整个架构基于MVVM模式。 Service:通过WCF做中间服务,使应⽤隔离开来,这样有利于扩展和维护,同事提⾼了整个应⽤程序的伸缩性。 Business Logic: 服务层内部之间的组合关系,主要体现再依赖和调⽤,由上往下调⽤,逐级依赖,最后Service底层边界Data Access模块将调 ⽤Framework中的Data模块,Data模块将调⽤MS.EntLib3中的Data,向数据服务器发送数据操作命令和数据. Framework: 该层次提供许多基础的功能模块(七⼤块),分别提供给UI,Service层⾥⾯的模块直接或者间接的调⽤,同时也可以看到 Framework层次内部各模块之间再运⾏时也有互相依赖调⽤的关系存在.该层次的部分模块会依赖和调⽤Ms.EntLib3中的模块,⼀般是按 照两个层次⾥⾯的模块名称,产⽣关系的. MS.EntLib3: 该层次的各个模块是整个系统框架中最底层的,只会在运⾏时被更⾼层次的模块依赖和调⽤,同时该层次内部各个模块之间也 存在依赖和运⾏时调⽤关系.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值