面向页面的移动端架构设计

前言

本文非常长,阅读需要勇气。

作者尝试在移动端总结出一套面向页面的架构设计,暂定命名为POA(page-oriented architecture),因为核心的关注点在于page,阅读本文更多的是了解移动端架构的方式方法。

另外,本文主要是方法论层面的阐述,具体案例因为每一种编程语言的不一样实现会有所不同,所以文中代码均为伪代码。作者已经部分实现这套方案,但具体的实现并不重要,重要的是希望这套方法论能给读者带来一些收获。

定义

面向页面的架构的定义:
以页面为自治单元,定义页面的唯一标识,对页面进行模块化,解决页面的注册、页面栈的治理、页面间通信、页面的分层架构、页面的组件化等问题。

这里要先给出模块和组件的相关的定义,本文中所说的这些概念均基于以下的定义:

  • 模块化,根据业务领域的划分进行页面的划分的过程。
  • 模块,模块化的产物,模块尽量保持自治;
  • 页面,页面的构成基本上依赖于产品的设计,不会像模块化或者组件化一样存在划分的灵活性,页面由组件构成,可以且必须保持自治;
  • 组件化,根据业务上的通用程度对页面布局进行划分的过程。
  • 组件,组件化的产物,组件不强调自治,但能自治当然更好,组件之间需要进行组合,最终由多个组件组合成一个页面,组件依赖于页面进行部署到App上。

以页面为自治单元

为什么要以页面为自治单元呢?

首先理解下自治单元,在 SOA 的场景下,一个 service 是一个自治单元,但是 service 的划分是无法标准化的,这增加了 SOA 架构设计的难度,直到出现 FAAS(function as a service)出现,function 是一个很好标准化的自治单元,极大降低了 SOA 架构设计的不确定性。

那么以页面为自治单元有以下一些原因:

  • 页面是天然可标准化的自治单元,模块和组件的划分都存在较多不确定性;
  • 如果以模块为自治单元,还要徒增模块间通信的复杂性,且模块划分不合理可能导致模块间的通信过于复杂;
  • 如果以组件为自治单元,不只是组件的划分的不确定性,组件间的依赖如何解耦也是另外一个难题了;
  • 页面的路由是必不可少的工作,页面间传参可以认为是页面路由的必备功能,对页面间传参的能力进行扩展,就可以实现页面间的通信;
  • 页面可路由的一个前提是页面具有唯一标识(下面会讲到),而页面间通信刚好可以服用这个唯一标识,无序增加更多复杂性;
  • 移动端App天然是页面的集合,以页面为自治单元可以极大的增强页面的可复用性,当然这不是目的,仅仅是一个副作用。

下面附上为POA设计的模块、页面、组件的物理架构图模板,物理架构是树形结构的,从模块到页面,从页面到组件,都是如此。

物理架构图

以页面为自治单元是本文的 POA 架构设计的基石。

页面的唯一标识

在前端领域,一个页面必然对应一个 URL,但是在移动端领域,这个标准不存在的,虽然 iOS 和 Android 系统自身会提供一些 URL 来调用系统页面的能力,但更多时候我们需要自己写一个 UIViewController或者Activity,然后直接通过依赖其类型来打开页面,这就造成了页面间更多的依赖性。

为了解耦页面间的依赖,直接采纳前端的方案,引入 URL 作为页面的唯一标识。通过这个唯一标识,我们可以打开、关闭页面,也可以跟页面进行通信。

需要注意的是,这个唯一标识只是在当前系统上下文内是唯一的,跨系统的情形不在本文的套路范畴之内,或者你可以认为我们主要讨论的是 内链,跨系统的页面 URL 是 外链,内链默认都是可信的,外链才需要关注安全性。外链可以通过转发内链来打开页面。

对 URL 的具体定义可以根据页面在树上的路径来,类似于如下的规则:

  • /[module]/[page]/
  • /[module]/[submodule]/[page]

当页面更复杂的时候,可能需要增加一个 feature 路径

  • /[module]/[feature]/[page]/
  • /[module]/[submodule]/[feature]/[page]

页面的模块化

页面的模块化,我们需要决定哪些页面应该分在哪个模块下面,前面也提到,这是一个存在不确定性的过程。

如何进行模块化

从业务的角度,我们很多时候需要通过面向对象的思想来分析,抽象名词,选出合适的名词作为关键实体,关键实体可能就是我们需要划分出来的模块。再往深一点看,我们需要对业务进行建模,这里不展开,我了解也比较肤浅。

模块划分之后,有一个办法可以用来验证模块划分的合理性。首先模块是由页面组成的,当我们抛弃模块之间臆想出来的依赖之后,剩下的就是这些实实在在物理层面的页面依赖,根据下面的方式来验证:

  • 如果两个模块之间存在较多的页面依赖,那么这两个模块的页面划分可能是存在问题的;
  • 如果一个模块内部存在两组以上基本不依赖的页面,那这个模块可能需要继续进行拆分。

模块化应遵循的原则

模块的划分,在物理层面应该是可以独立发布的包,所以同样适用于以下设计原则,wiki

  • 重用发布等价原则(REP)
  • 共同封闭原则(CRP)
  • 共同重用原则(CCP)
  • 无环依赖原则(ADP)
  • 稳定依赖原则(SDP)
  • 稳定抽象原则(SAP)

前三个原则,较简单,不做阐述,后三个原则在后续章节会有更详细的说明。

模块的模块化编程

模块化编程的具体含义可以参考 wiki

从我们对页面的定义看,一个页面本身就可以是一个最小的模块,页面座位自治单元,完全可以遵循模块化编程的规范,那么模块自然就很好遵循模块化编程的规范。模块的接口即是所有模块包含的页面。最小的模块可以只包含一个页面。遵循模块化编程可以让模块具有以下优点:

  • 易设计,模块经过划分之后,使得模块本身的设计变得更为简单,因为需要关注的范围变小了,需要解决的问题变得简单了;
  • 易实现,模块化适合团队开发,实现模块的成员不需要了解整个系统的全貌,人员的更替也不会带来很高的成本;
  • 易测试,模块可以独立开发,也可以独立测试,到集成测试阶段才需要对整个系统进行测试;
  • 易扩展,增加新功能只需要增加新模块或子模块,偶尔对现有模块的重新划分(就是对模块进行重构),在我们的场景下面,页面本身已经是自治单元
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值