最近跟一个朋友聊到关于App架构的问题, 其中就聊到一个App, 开发了很长时间, 一开始没有去想框架的事儿, 迭代过程中, 由于时间紧, 任务重, 人员更替等原因, 也没能保证代码质量, 很多设计原则被抛之脑后, 代码质量逐步下降, 以致难于阅读, 难于维护. 进而导致迭代困难, 而形成恶性循环.
从而引申出如何重构App代码的话题, 谈点个人理解:
什么情况下需要重构
1, 结构错乱
- 代码无法分出层次, 无法分清业务线.
- 各个业务模块间/层次间的代码互相夹杂.
- 由于多人协作导致的多种架构(MVP/MVVM/MVC等)并存.
- 规范性问题, 导致各个模块内的代码形式互相不一致, 风格迥异.
2, 可读性差
- 超长函数, 超大类
- 代码的格式不规范或不一致.
- 冗余代码, 无用代码, 重复代码.
- 过于高明, 使用一些不常用的小技巧而且没有相关注释.
- 滥用继承, 接口实现等, 导致难以跟踪.
3, 不能很好的适应产品的发展
- 维护困难, 前一发动全身.
- 不具备扩展灵活性, 无法很快引入系统版本更新时新特性.
- 不具备可变更性, 产品添加新功能或修改需求时需要修改大量的代码.
重构的目标
重构的目的就是要提高代码质量, 而高质量的代码指标个人认为有如下几点, 当然其实也是老生常谈的几点.
排名分先后:
1, 可读性
- 规范一致性.
- 结构, 层次明了.
- 命名有含义, 注释要清晰.
- 逻辑简短, 没有长篇大幅的代码块.
- 方法提取, 类继承关系合理.
- 不滥用设计模式.
聪明是可读性的敌人.
2, 可维护性
- 杜绝魔鬼数字/字符串/尺寸值/颜色值等
- 代码复用, 以便维护.
- 不写死, 预测可能的变化(但不要提前设计).
3, 可扩展性
- 良好的分层结构, MVx模式运用.
- 通过一些设计模式的使用来提高可扩展性.
开闭原则: 修改关闭, 扩展开放.
如何重构
首先让我们重温下"重构"的含义:
<<重构 --- 改善既有代码的设计>> 这本大神作品强烈建议大家翻阅下~ 里面对重构的定义, 以及如何从一个个小的Bad Smell开始重构等都有详细的描述.
那么作为一个进行已久的Android工程, 我们应该如何重构呢?
其实这是一个对症下药的问题, 针对为什么要重构提出的几个代码问题, 重构也可以分成以下几步:
1, 架构选择, 结构调整
-
根据App的业务场景(展示型, 交互型, 后台工具型...)选择合适的架构.
- 并不是说一定要选用一个架构, 比如说后台工具型的App, 可能界面不多, 也服务器的交互也少, 基本是由Service组成, 可能直接用Android原生的结构就可以.
- 界面较多, 且与服务器交互较多的建议选用MVP架构. 可以通过P来做数据处理, 将数据源M与展示层V解耦, 便于替换数据源或是改变UI.
根据选用的架构以及业务模块分包
2, 技术/开源库选定
- ListView/RecyclerView的选择, Fragment/Activity的选择等.
- 根据业务特点和选择的架构, 选用相关技术/开源库支持或对当前使用的进行整理.
- 例如HTTP请求库, 缓存库, 图片加载库等等.
3, 确定规范
- 制定编码规范, 可以根据Google推荐的Java编码规范, 适当定制.例如我的项目中的基本规范.
- 制定代码提交规范, git flow管理流程规范等.
4, 自底而上, 由小至大
- 从底部开始, 也就是常说的Model层,数据层开始, 因为这部分相对独立, 可以通过提供接口与UI层隔离.
- 不要一下就大面积重构, 需要逐个小的case进行重构验证, 保证当前运行.
5, 持续重构, 伴随测试
- 持续进行小的重构, 每次重构需要伴随测试, 保证重构结果.
- 提取方法, 去除重复代码.
- 结构调整.
- 融入面向对象/接口编程思想, 注意SOLID原则.
- 多用组合, 少用继承
- ......
- 最好有单元测试支持.
6, 重构而非重写
- 不到万不得已不要想重写.
- 重写会产生各种意想不到的问题, 诸如设计过度, 对于当前代码把握不够(例如现在看起来很不友好的代码可能就是为了解决一个架构无法解决的问题等).
附--关于架构重构的规则
写完此文, 偶然机会在InfoQ上看到Uber的技术主管Raffi Krikorian在 O’Reilly Software Architecture conference上谈及的关于架构重构的12条规则, 共勉之: