大风车Android客户端的架构演进
nbkangta
8年前
<h2>前言</h2> <ul> <li>以下内容不牵涉具体代码实现,也不包含插件化相关知识。</li> <li>没有银弹,只有根据当前的与可预见的业务情景不断调整的架构方案。</li> <li>阅读正文将花费您大约30分钟。</li> <li>本文会随时间持续改动。</li> </ul> <p>大风车从第一版发布开始到现在已经走过了两个多年头,陆续上线发布了二十多个版本,从一开始的提供web容器包装h5的简陋版本,发展到现在由九个专职原生开发同学及数位前端同学支持的12w行(统计数据来自 SonarQube )代码的规模。架构的可用性半衰期随着业务体量的增长而缩短,那么如何支撑现有业务的维护及后续的业务开发是对我们的一大挑战,而本人作为经历了从零开始的开发人员,下面带大家回顾一下这两年来的大风车Android客户端的架构变化。</p> <h3>组件化与模块化</h3> <p>首先来明确两个概念: 模块(module) 和 组件(component) 。</p> <p>什么是组件?</p> <p>组件是语言层面的划分,侧重于 功能重用 。在Android里表现为一个UI控件,一个工具集合,一个路由系统。</p> <p>什么是模块?</p> <p>模块则是业务层面的划分,侧重于 业务解耦 。在Android表现为一个业务module。同时模块中也可以包含任意个组件。</p> <p>两者可以说是在分治方向和粒度上的区别。</p> <p>大风车Android客户端在模块上有三个维度上进行项目拆分:一是 通用功能库 ,这个维度上包含了基础样式库、通用工具库(比如上传/下载、图片处理、压缩等等),即可重用的通用功能;二是 业务类型库 ,与具体业务相关,包含了可重用的业务功能;三是大风车客户端作为 主工程 ,他们都表现成一个单独的git项目,有自己的版本号与分支,前两个维度稳定后发布在Maven仓库上( <a href="/misc/goto?guid=4959545554281862421" rel="nofollow,noindex">Nexus</a> 或 <a href="/misc/goto?guid=4959736103116379513" rel="nofollow,noindex">Artifactory</a> 两种开源实现都可,具体取决于公司的技术栈),另外三者都有自己的项目地址和版本号,每个大风车发布上线的版本都会依赖这些库的对应版本。同时,三者最浅层的区别就是主工程的对外版本号不以开发人员的意志为转移,需要跟着产品的需求和改动走。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/a0267bafe528ccb2eb5725384a55f2e4.png"></p> <p>当然,上述的分层不是一蹴而就从一开始就设计好。因为初始的项目规模比较小,追求快速迭代和尽早上线,刚开始的大风车只有一个主项目,其他库都是之后因为重构或者因为新的需求进行拆分或者新建而产生的。</p> <h3>分层</h3> <p>随着项目逐渐臃肿,代码难以维护,需要我们进行解耦,而实现解耦常见有两种手段,一种是 模块化 ,另一种则是 分层 。通过上面的描述来看,我们已经实现了模块化,下面我们就来看看如何实现分层。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/3567a01b4dbae6549f59b5225f59e616.png"></p> <p>大风车主项目是基础的 MVC 结构,采用这样的设计大部分原因是历史遗留问题,随着业务复杂度的提升,我们进行了上述的分模块开发,而MVC的局限性在于会让业务代码塞满 Activity 的各个角落。拿我们的车辆详情页举例,由于各种车辆操作加上账号资源角色的判断,现在的车辆详情页Activity代码行数已有1930行,夸张的技术债务带来的代价是旧代码难以维护,新需求难以迭代。</p> <p>业务驱动技术,技术服务业务。故以现在流行的 MVP 框架为导向,结合 <a href="/misc/goto?guid=4958987558570479788" rel="nofollow,noindex">CleanArchitecture</a> 的思想,通过 RxJava 解耦视图与数据的通信,同时也很好的支持了单元测试。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/724ff38febd7c8dc9ca4be387ecc96d9.png"></p> <h3>从协议到路由</h3> <p>在上面我们进行了模块化和分层,而另一大常见的问题就是Android中的 视图跳转 。因为业务页面越来越多,有些共用的页面可能只是参数传值或者启动方式的上的区别,需要不同的开发去重复写 Intent ,这些差异极小的 Intent 会遍布在项目里各个角落。有时候改了一个地方会因为遗漏等原因而牵一发而动全身。我们的处理方式是约束了统一的跳转协议格式,所有的业务视图都通过给定的协议去跳转,而跳转协议由统一的协议处理工具类去解析。</p> <p>但随着不断编写同样的协议我们发现这样的开发体验不太好,毕竟协议是字符串,不断硬编码字符串需要不断查询协议文档,所以之后我们的计划是用注解实现的路由系统来辅助当前协议的解析方式,通过编译时生成代码的方式来改善开发体验。</p> <h3>小结</h3> <p>所有的架构方案因为设计者的局限性或者项目规模大小的限制,所以可能可以很好的满足当前或者半年后的开发设计和体量,对一年后的需求就难以支撑,所以需要不断的根据业务发展来完善我们的设计。请用发展的眼光看待此类问题,同时我们也将持续改进。</p> <p> </p> <p>来自:https://blog.souche.com/dfc-android-architecture-evolution/</p> <p> </p>