现代化编程思考和UI框架实践思考
随着这些年编程技术的发展,编程技术在蓬勃发展,新技术得以快速落地,很大一部分要归因于微服务/组合这一对儿孪生兄弟。18年以前,我们思考编程大部分停留在填充好用的utils, 在Android领域我们使用最多的是基于Guava封装自己的工具库。或者深入一点的,基于Okhttp分装各色各样的,有所侧重的特色网络封装。当是的开发侧重是以项目为单位。
云服务(组合软件)
以项目为基本单位当系统简单时,是没有问题的,那是云服务估计也是一个新鲜词儿。
笔者视角里有两个主要的推手,共享软件和技术变缓,我们稍微展开来聊一下。
这其实不是软件开发领域独有的概念,以笔者观察,任何工业相关的领域,都会走向这一最终趋势,我们以另一个发展成熟的汽车工业作为类比,
- 手工打造汽车(单一)(高成本)
- 早期独立生产线
- 稳定且冗余的生产力/提工代工
- 汽车零部件要求提高,复杂度提高,单独领域生长成型
- 主机厂按预算成本等因素采购不同厂商的零部件
- 多样的,差异化服务(多样)(低成本)
汽车领域的发展,我们可以大致抽象为这几个步骤,这些在软件开发领域都是能找到对应的状态, 其中共享概念我们并不陌生,因为开源运动和Github使开源运动之后的从业者没有感受到这件事对软件世界的改变有多大,身处洪流之中的我们,也会忽略云服务和共享单车理念类似。
- 阿里巴巴(亚马逊)非双11期间冗余的服务器,可以提供出来付费租用,方式可以包月包年,也可以按量付费。
- 自行车生产力冗余,制造成本极低,可以极低成本购买大量自行车,提供出来付费租用,方式可以包月包年,也可以按量付费
这两者另外的共同点则是共享和方便,这种类比也许是不准确的,朴素的道理往往是复杂事物和逻辑的底座。
- 云原生我了解不多,仅仅听过一些课程,就不大放厥词了,笔者印象中的云原生是更好实现微服务的工具。
Coding级别的组合
提到代码级别的组合,我们很容易联想到火了很久单使用起来却并不常见(区分领域,这里特指应用开发)的函数式编程方法,单子(Monad),柯里化(Curried),组合器(Combinator)这些概念在不可变性概念的基础上生根发芽,笔者从事客户端开发,又是偏应用方向,所以难免和复杂的状态打交道,函数式除了性能上存在一些问题,对状态的处理也不是很在行,好在一切都在向这个方向发。fpdart[pub.dev/packages/fp…] 已经在这些方面有所尝试。
- 函数式编程是一个相对狭窄的领域,代码级别组合思想其实已经存在了很久。
我们回想Flutter的那句名言,亦是基石,一切皆Widget(Everything is Widget), Flutter这个相对于原生Android和IOS移动端开发而言,就是代码级组合软件的变革。例如,一个简单的例子:
- 展示一张图片,宽高3/4
在旧的体系中,我们倾向于对图片组件设置比例属性,新的组合体系中,我们使用AspectRatio + Image 组合解决这个问题。这种方式的强大其实不必多言,因为很少有人尝试过新的写法,人就愿意去使用旧的写法(当然,原生也有新的对应实现,这不在我们讨论范围)。
这是一个好的开始,但显然还有很长的路要走,实际项目当中,惯性思维仍旧让我们写出不那么符合`一切皆Widget的代码。例如:
...
onPressed: () {
analytics.log({"id": 1, xxxxx})
ref.read(authProvider.notifier).logout();
other...
},
...
AnalyticsUpdate(
analyticsParams: {"id": 1, xxxxx},
onPressed: () {
ref.read(authProvider.notifier).logout();
}
)
这两种方式优势和略式读者可以自己评估,笔者大多数情况下更喜欢AnalyticsUpdate, 符合组合的思想, 单一职责等优势。笔者不再一一列举。
幂等和不可变性
在Flutter开发实践中,笔者觉得这两个是关联很多的概念,不可变性为幂等提供了基础,幂等使用不可变性并产生不可变对象。熟悉Bloc的读者应该深有体会,简单说明就是复杂状态的可控和可回溯。这个相关的可以查看我其他的文章。
我们来聊,StatelessWiget 是不是一种不可变性具体应用?,我们回忆一下StatelessWiget 的定义,对于无状态(即不可变)的组建,我们使用StatelessWiget。具体原因我们也清楚,这种Widget一次构建(Construct),不需要再次生成。我们会惊讶的发现,不可变性其实已经在现代UI框架中被应用了很久。
Channel多线程模型
对于Android开发中,Kotlin协程是一个当是相较于Java一个巨大的进步,目前在Future, async/await这种模式被大部分主流语言使用,协程已经不是一个新奇的概念,Flutter中的EventLoop模型和携程实现我们在此不过多展开,笔者想更多一点文字在Isolate, 以及与mpsc模式的关联。
Isolate相关使用的文章请检索其他文章,我们只讨论现代化的客户端多线程模式,当然,这个现代化并不准确,JsV8解释器也是单线程模型,这种应该已经存在很久了(偷懒没查)。我们来尝试分析这种为什么更现代化。Java或之前多线程并发的焦点问题在于共享内存, 共享内存需要引入很多新的概念,例如互斥(Mutex), ABA和CAS, 这种多线程模型在基于Java的Android中也很常见(面试重点)。我们重新看一下Isolate的介绍。
- Concurrent programming using isolates: independent workers that are similar to threads but don't share memory, communicating only via messages.
我们发送消息(数据)到Isolate实例,Isolate接管或拷贝这份数据,Isolate处理数据并发送消息(数据)到receiver,完成一次类多线程并发调用。是否感觉到很简单,没有同步关键字,没有互斥, 没有CopyOnWrite集合。这极大的简化了并发操作,降低了错误率。这一切也和后台新的线程模型mpsc有同样的概念基础。
ffi, 组件化
组件化
这两个其实不需要过多介绍了,组件化在Android中就有,为了解决业务复用,扩展等,我们可以通过快速组合不同的业务组件, 打造一个新的App。无需多言,flutter复杂项目可以使用melos解决组件化以及依赖管理。
ffi
ffi如今已经被各种主流语言所大力支持, ffi也在语言的介绍书籍,官方文档上被放在高级这个目录里,我们不妨以组合这种模式的角度去观察这个切面。
不同的语言擅长不同的领域,这一点是共识,比如python在人工智能,Java和Go在Web, C/C++/Rust在系统等底层项目中。他们历时多年,很多积累(包括人才)是很难复刻的,比如ffmpeg, 比如pytech和springboot等。语言的变更稳定和软件财富(do not repeat yourself)的两方面,使我们与其使用一门新的语言创造一个软件的偏向选项,变为,偏向和已有软件组合。
例如,web+rust, flutter + rust, python + rust 等。
涉及的现代化概念
- 微服务
- 云原生
- 组合
- 函数式
- 幂等
- 不可变性
- channel多线程模型/生产者消费者模式
- ffi
- 组件化
- 依赖管理
总结
以上仅为笔者的一点思绪,仅仅是现代化的编程的一个小小的切面,笔者通过以软件和代码的组合关系作为视角,以偏概全的思考了一些2024年自己的所思所悟,希望于读者也有一些启发。
help
其实不知道写一些什么,一些Flutter开发基础,有很多博主写的很好,我就没有太大欲望去写,晦涩的,总害怕自己理解的不对,表述不清,误人子弟。希望读者可以给我一些建议,最好是客户端相关或者工程相关,不胜感激。