架构总览与闲聊

终於到了最後一天了,不知道把这三十天看完的人有多少呢?希望看到最後一天的人,有感受到我对於这系列文章中想传达出去的理念,感受到架构设计的取舍是什麽,不是只有选择 MVP 、 MVVM 或是 Clean architecture 这种非黑即白的选项,更多的是每一个小小的选择都会影响着程序码的运作方式,这些选择是为了更优雅的解决当下所碰到的问题。有碰到问题,才需要解法,程序还不够复杂的时候,不需要因为要追求“潮流”而使用厉害的架构,相对的,还有可能因为过早的套用厉害的架构而导致後期修改的障碍。

在这系列文章中,看到了早期简单的 MVVM ,只有一个简单的拖拉便利贴功能,到後来功能越加越多,ViewModel 的职责渐渐多了起来,最後甚至遇到了使用单个 ViewModel 无法解决的问题,所有这一切都是慢慢发生的,在没有过早设计的情况下,很顺利的转换到新的架构,同时这个架构也是符合产品未来的走向,在设计以及讨论过程产生了 ViewPort 这个新观念,在之後我们也利用了这个新观念来更好的组织程序码,在未来如果要增加平移以及放大缩小功能时,大家在第一个时间都知道这功能应该是属於哪个元件的范畴。

对於这个产品来说,“共编器”的聚合力是非常高的,大家在讨论需求或是发现 bug 时,一定第一时间就会讨论它,但是如果使用比较符合潮流的 Use case 为核心的设计,“共编器”的聚合例就会大大降低,各种使用案例四散在各不同的类别中,甚至在 Domain 层还不会出现一个可以作为“共编器”的类别,只会出现像是 “删除便利贴”、“更改便利贴颜色”、“更改便利贴位置” 这种看起来可重用度很高的 Usecase ,但是本身没有描述到最重要的“共编器”相关领域知识,另外,像选择便利贴这种 UI 状态也会因为留在 ViewModel 层而造成理解上的阻碍。

Living Documentation 这本书上有一段话:『 DDD 提倡“用程序码设计模型”作为基本的解决方案。基本想法是程序码本身就是知识的表现。只有当程序码不够才需要其他东西。』。这也是我现在阶段喜欢而且认同的,我相信目前的便利贴程序的架构就算是给一个非工程师来看,也大概猜得到这些元件在做什麽事。

不过!还是得要说一定有 App 非常适合以 Use case 为核心的设计,不能因为便利贴应用程序就否定了这种做法,不同的应用程序的特性有可能相差不大,也有可能天差地远,选择最适合该专案的架构才是最重要的,我这系列文章故意让 Use case 看起来不好用只是想发出一个讯息:主流的架构无法套用在任何一个应用程序上,请三思而後行。

状态(State)到底要多大?

现在还有流行着一种架构模式: MVI ,基本上就是把所有有关 UI 的状态全部塞在一起变成一大包,而且所有的事件都只会流向同一个地方,有了这样的架构方式,加新功能就会如同有着 SOP 准则似的一样简单。如果是新的事件,只要继承自 BaseEvent 就好,并且为这个 Event 在另一个地方写下相对应要处理的逻辑,这边通常来说应该会是个 kotlin 的 when ,如果有新的 UI 状态要显示,就在 State 里多新增一个栏位即可。正因为如此统一又好掌控,所以也受不少的开发者喜爱。

我在便利贴专案中示范的案例中,其实就有做类似的事情,有着一个相对巨大状态,但是後来却把这个状态给拆掉了,这个状态就是 allNotes 。将所有的状态全部绑在一起最大的缺点是,即使只是更新了一个超级不起眼的数值,只占了这个巨大状态的不到百万分之一,还是会因为们是绑在一起的状态而有“连坐”的效应,很多栏位都要一起跟着复制,产生新的实例。这其实部分也是因为语言的限制,如果有一天 kotlin 正式支援 Structure sharig 的复制方式,这可能就不是一个大问题了。

关於 Structure share 可以看我去年写的文章:https://ithelp.ithome.com.tw/articles/10247008?sc=rss.iron

所以话说回来,到底该不该把全部的状态塞成一整包呢?这部分应该也要靠读者自己决定了,如果专案成员都已经很熟悉这种开发模式而且不太会有效能问题的话,那这就是一种好的模式。但是如果现在开发的是一个很复杂的 feature,没有上千行程序码无法解决的话,我会建议你多想想,因为这种开发模式不利於建构“模型”,使用单一的巨大状态无法好好的描述模型内各自的职责与交互关系,使用单一的事件入口也会限制了想法,最後 MVI 反而是造成技术限制的来源。

Android 工程师的价值在哪

其实我不太喜欢 Clean architecture 或是 MVI 的框架函式库有一个原因是因为,如果这就是你的全部的工作内容的话,这样代表你的可取代性很高,只要有新人把这套版学起来了,就可以让新人马上上工,老板可以把薪水比较高的你给踢掉,反正照样做就对了。那这时候就要想想,身为一个 Android 工程师,而且如果你还挂上一个 Senior 的 title,每天在做的工作都大同小异,接到新需求,新增一个 Usecase,开 room DB entity ,接接 API ,一个 sprint 的工作就这样又做完了,那麽你比别人厉害的地方在哪里呢?可能你会说,我在用最新的技术 Jetpack Compose + Flow + Room + Retrofit + Clean architecture,但是现在要是再隔个几年,又出现更新更潮的技术(有人还记得 Airbnb 前阵子出的 MvRx 吗?),你还要为了不被淘汰而去继续学习这些新框架吗?

根据我这几年来学习的心得,以及我所观察到的,个人觉得有高价值的工程师应该是这样的:

  • 有着别人无法轻易学习的领域知识,例如资安、影音编辑、影像处理等等,而且一直有持续的在跟上最新资讯。
  • 有办法快速掌握新知识,触类旁通以及独立思考的能力。
  • 厉害的沟通技巧,有能力掌握 stakeholder 的需求而且尽力避免掉无谓的浪费。
  • 解决复杂问题的能力,化复杂为简单,有能力开发自己的 Glide 或是 Okhttp 这种跟“画面”或是“流程”无关的函式库。

致谢

很可惜的到最後没办法把第三阶段的新功能给实作出来,但我觉得这也是好事,可以留给读者一些想像的空间:如果是你,你会先补完测试再继续写新功能吗?还有会从哪个新功能开始写呢?

最後再次谢谢看到这里的大家,尤其是有留言的读者,其实我非常希望各位多留言,这样我才能知道写的内容有没有人看,或是有没有看懂,没看懂的话,我应该用其他方式来描述才对,好拉,祝各位在未来的开发路上一切顺心,人人都设计出心目中最棒的架构!

补充:其实这系列文章的内容很大一部份是启发自我们公司 CTO 的想法,有兴趣的可以看看他写的文章:https://tech.pic-collage.com/mddv-white-paper-43c00868b8b9


<<:  D25 - 用 Swift 和公开资讯,打造投资理财的 Apps { 三大法人成交比重 资料分析 }

>>:  虹语岚访仲夏夜-21(专业的小四篇)

闭包 跟 scope chain

人脑编译器 来一遍1 var a=1; function outerFun(){ let b=2; ...

Day 23. 透过 Constraints 机制,实作出能够拉伸的响应式卡片设计

前一篇我们实验 Constraints 各种设定会造成的影响後,相信大家已经对於 Constrai...

网路是怎样连接的(九)TCP的性能优化(下)

思考重点 流量控制的原理以及实现目的? 壅塞控制的原理以及实现目的? 核心知识 流量控制 流量控制的...

Day 27. Zabbix 实际报警案例分享 - 执行绪异常飙高

计画性停电後, Zabbix 一直疯狂跳警报,因为我们有设置只要警报有被触发 Line 群组 就会跳...

30天轻松学会unity自制游戏-新增死亡画面

通常游戏会有一个死亡画面,询问要重新开始,离开,增强能力(看广告)…等,先一样在画布上点右键给一个i...