GMTC2018 《美团客户端基于响应式的架构实践》 臧成威

2020-02-27 210浏览

  • 1.美团客户端基于响应式的架构实践 臧成威 美团 iOS ⾼高级技术专家
  • 2.关于我 • 美团 iOS ⾼高级技术专家 • 负责美团平台美团 App 客户端的基础架构,流 程管理理系统的设计实施⼯工作。 • QCon 讲师,StuQ ⾦金金牌讲师。 • 构热衷于函数式编程和函数响应式编程,深度 理理解ReactiveCocoa,喜欢研究各类语⾔言和库 的底层实现。
  • 3.TABLE OF CONTENTS ⼤大纲 • EasyReact 和 EasyMVVM 的项⽬目背景 • EasyReact 技术重点 • EasyMVVM 架构重点
  • 4.EasyReact 和 EasyMVVM 的项⽬目背景 • 美团客户端⾯面临的挑战 • 美团客户端架构变迁 • EasyReact 与 EasyMVVM 的初衷
  • 5.美团客户端⾯面临的挑战 • 代码体量量达到数百万代码⾏行行 • 数⼗十个团队协同开发 • 迭代周期越来越快 • 产品质量量要求越来越⾼高 EasyReact 和 EasyMVVM 的项⽬目背景
  • 6.美团客户端⾯面临的挑战 EasyReact 和 EasyMVVM 的项⽬目背景 代码质量量 架构 代码复⽤用 迭代流程
  • 7.EasyReact 和 EasyMVVM 的项⽬目背景 • 美团客户端⾯面临的挑战 • 美团客户端架构变迁 • EasyReact 与 EasyMVVM 的初衷
  • 8.美团客户端架构变迁 01 02 EasyReact 和 EasyMVVM 的项⽬目背景 03 04 05 简易易形态 MVC结构 美团App
  • 9.美团客户端架构变迁 02 01 EasyReact 和 EasyMVVM 的项⽬目背景 03 04 05 业务拆分架构 Tuangou Waimai Movie Hotel … Base Business SDK Account Payment SDK SDK Push SDK Share SDK … Base Library CustomU IKit Network Foundation Crypto …
  • 10.美团客户端架构变迁 01 02 EasyReact 和 EasyMVVM 的项⽬目背景 03 04 05 响应式引⼊入 基于 ReactiveCocoa
  • 11.美团客户端架构变迁 01 02 EasyReact 和 EasyMVVM 的项⽬目背景 04 03 05 MVVM 架构 (基于ReactiveCocoa) View ViewModel Model
  • 12.美团客户端架构变迁 01 02 EasyReact 和 EasyMVVM 的项⽬目背景 05 03 04 MVVM + 模块化架构 复⽤用模块 复⽤用模块 复⽤用模块
  • 13.EasyReact 和 EasyMVVM 的项⽬目背景 • 美团客户端⾯面临的挑战 • 美团客户端架构变迁 • EasyReact 与 EasyMVVM 的初衷
  • 14.EasyReact 与 EasyMVVM 的初衷 EasyReact 和 EasyMVVM 的项⽬目背景 让⼈人⼜又爱⼜又恨的 ReactiveCocoa • 概念烦杂 • 调试困难 • 易易出错 • ⻛风格不不统⼀一
  • 15.EasyReact 与 EasyMVVM 的初衷 EasyReact 和 EasyMVVM 的项⽬目背景 让⼈人⼜又爱⼜又恨的 ReactiveCocoa FRP 函数式编程的天然⻔门槛 基于 OOP 设计的响应式编程框架
  • 16.EasyReact 与 EasyMVVM 的初衷 EasyReact 和 EasyMVVM 的项⽬目背景 RP 基于 OOP 设计的响应式编程框架 简单、易易⽤用
  • 17.EasyReact 与 EasyMVVM 的初衷 EasyReact 和 EasyMVVM 的项⽬目背景 View ViewModel Model RP For MVVM • 理理解不不⼀一致 • ⻛风格不不统⼀一 • 层次划分不不明 • 缺乏框架⽀支持
  • 18.EasyReact 与 EasyMVVM 的初衷 EasyReact 和 EasyMVVM 的项⽬目背景 MVVM Framework 统⼀一的 MVVM 框架 简单、易易⽤用 丰富的⼯工具⽀支持
  • 19.TABLE OF CONTENTS ⼤大纲 • EasyReact 和 EasyMVVM 的项⽬目背景 • EasyReact 技术重点 • EasyMVVM 架构重点
  • 20.• 声明式编程中的响应式编程 • 基于图和⾯面向对象的 EasyReact • 主流框架对⽐比 EasyReact 技术重点
  • 21.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程
  • 22.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 EasyReact 技术重点 开始 准备环境 监测是否成功? 协调解决 执⾏行行环节 结束
  • 23.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 地址 省 市 街道 楼牌号 +登记地址 - 地址更更名 EasyReact 技术重点 家庭 ⽗父亲 ⺟母亲 孩⼦子们 住址 +登记家庭(⽗父亲、⺟母亲) - 搬家(新地址) ⼈人 年年龄 性别 - 结婚(配偶) - 成⻓长 程序员 职级 编程语⾔言 - 编码 - 加班
  • 24.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 <<接⼝口>> 可表示地址的 - 地址更更名 - 获取地址信息 地址 省 市 街道 楼牌号 +登记地址 - 地址更更名 EasyReact 技术重点 家庭 ⽗父亲 ⺟母亲 孩⼦子们 住址 +登记家庭(⽗父亲、⺟母亲) - 搬家(新地址) <<接⼝口>> 可表示⼈人的 - 获取信息 - 吃饭 ⼈人 年年龄 性别 - 结婚(配偶) - 成⻓长 机器器⼈人 ⽣生产⽇日期 型号 - 固件升级 - 充电 程序员 职级 编程语⾔言 - 编码 - 加班
  • 25.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 EasyReact 技术重点 y = f(x) a = b.method(c) 状态1 命令 状态2
  • 26.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程
  • 27.声明式编程中的响应式编程 “ 约束编程(Constraint programming)是⼀一种编程典范,在这种编程范式 中,变量量之间的‘关系’是以约束的形式陈述(组织)的。这些‘关系(约 束)’和命令式编程语⾔言元素不不同的是:它们并⾮非明确说明了了要去执⾏行行的步 骤中的某⼀一步,⽽而是规范其解的⼀一些属性。这样看来,约束编程是⼀一种声明 式的编程范式。 ——维基百科 给定约束、范围 约束计算框架 得到结果 EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程 UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10); [view1 mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler make.left.equalTo(superview.mas_left).with.offset(padding.left); make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom); make.right.equalTo(superview.mas_right).with.offset(-padding.right); }];
  • 28.声明式编程中的响应式编程 EasyReact 技术重点 • 领域特定语⾔言指的是专注于某个应⽤用程序领域的计算机语⾔言。⼜又译作领域专⽤用语⾔言。 不不同于普通的跨领域通⽤用计算机语⾔言(GPL),领域特定语⾔言只⽤用在某些特定的领域。 “ ⽐比如⽤用来显示⽹网⻚页的 HTML 语⾔言,以及 Emacs 所使⽤用的 Emac LISP 语⾔言。 ——维基百科 声明式编程 • 约束式编程 • DSL GPL vs DSL • 函数式编程 • 逻辑式编程 SQL
  • 29.声明式编程中的响应式编程 内嵌 DSL DSL 外部 DSL platform :ios, '9.0' inhibit_all_warnings! target 'MyApp' do pod 'ObjectiveSugar', '~> 0.5' target "MyAppTests" do inherit! :search_paths pod 'OCMock', '~> 2.0.1' end end post_install do installer installer.pods_project.targets.each do target puts "#{target.name}" end end DROP TABLE IF EXISTS `table_test_one`; CREATE TABLE `table_test_one` ( `id` int(11) NOT NULL AUTO_INCREMENT, `student_no` varchar(10) NOT NULL, `student_name` varchar(10) NOT NULL, `subject_no` varchar(10) NOT NULL, `subject_name` varchar(10) NOT NULL, `score` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程
  • 30.声明式编程中的响应式编程 EasyReact 技术重点 • 声明式编程 “ 函数式编程,特别是纯函数式编程,尝试最⼩小化状态带来的副作⽤用,因此被认为 是声明式的。⼤大多数函数式编程语⾔言,例例如 Scheme、Clojure、Haskell、 OCaml、Standard ML和Unlambda,允许副作⽤用的存在。 • 约束式编程 ——维基百科 • DSL • 函数式编程 • 逻辑式编程
  • 31.声明式编程中的响应式编程 EasyReact 技术重点 • 逻辑编程(逻辑程序设计)是种编程典范,它设置答案须匹配的规则来解决问题, ⽽而⾮非设置步骤来解决问题。过程是 事实+规则=结果。 “ 不不同的⽅方法,可以看 Inductive logic programming。 ——维基百科 声明式编程 • 约束式编程 • DSL 规则 事实 • 函数式编程 friend(X,Y):-likes(X,Y),likes(Y,X). human(kate). human(bill). likes(kate,bill). • 逻辑式编程 举例例(sort)q:-L=[33,18,2,77,18,66,9,25], (sortcsj(L,P), write(P), nl). sortcsj(L,S) :- permutation(L,S), ordered(S). ordered([]). ordered([_ []]). ordered([A [B T]]) :- A =< B, ordered([B T]). :- initialization(q).
  • 32.声明式编程中的响应式编程 声明 关系与逻辑 框架进⾏行行计算 结果 EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程
  • 33.声明式编程中的响应式编程 • 命令式编程 • 过程式编程 • ⾯面向对象编程 • ⾯面向接⼝口编程 EasyReact 技术重点 • 声明式编程 • 约束式编程 • DSL • 函数式编程 • 逻辑式编程
  • 34.声明式编程中的响应式编程 • 命令式编程 EasyReact 技术重点 • 声明式编程 响应式编程 ?
  • 35.声明式编程中的响应式编程 • 命令式编程 EasyReact 技术重点 • 声明式编程 响应式编程 “ 在计算机中,响应式编程或反应式编程(英语:Reactive programming)是⼀一种⾯面向数据流和变化传播 的编程范式。这意味着可以在编程语⾔言中很⽅方便便地表达静态或动态的数据流,⽽而相关的计算模型会⾃自动将 变化的值通过数据流进⾏行行传播。 例例如,在命令式编程环境中,a:=b+c表示将表达式的结果赋给 a,⽽而之后改变 b 或 c 的值不不会影响 a。 但在响应式编程中, a 的值会随着 b 或 c 的更更新⽽而更更新。 A := B + C ——维基百科
  • 36.声明式编程中的响应式编程 • 命令式编程 内嵌 DSL 响应式编程 let searchResults = searchBar.rx.text.orEmpty .throttle(0.3,scheduler:MainScheduler.instance) .distinctUntilChanged() .flatMapLatest { query -> Observable<[Repository]> in if query.isEmpty { return .just([]) } return searchGitHub(query) .catchErrorJustReturn([]) } .observeOn(MainScheduler.instance) EasyReact 技术重点 • 声明式编程 DSL 外部 DSL A1 B C 2 6 7 3 =B2+C2
  • 37.EasyReact 技术重点 • 声明式编程中的响应式编程 • 基于图和⾯面向对象的 EasyReact • 主流框架对⽐比
  • 38.基于图和⾯面向对象的 EasyReact • 基于图的数据结构 • ⾯面向对象的设计 • 使⽤用示例例 EasyReact 技术重点
  • 39.基于图和⾯面向对象的 EasyReact • 基于图的数据结构 node edge edge edge node edge node node edge edge node edge node EasyReact 技术重点 node edge node edge edge node edge edge node node node
  • 40.基于图和⾯面向对象的 EasyReact • 基于图的数据结构 node a map link take node b link node e EasyReact 技术重点 listener a listened by node h combine listened by listener b node d flatten map filter listened by listener d node i combine listened by listener c node c node g
  • 41.基于图和⾯面向对象的 EasyReact • 基于图的数据结构 • ⾯面向对象的设计 • 使⽤用示例例 EasyReact 技术重点
  • 42.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • ⾯面向对象的设计 — 类型定义 <> EdgeNode๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T ๏from() -> Node๏setFrom(Node) ๏to() -> ToType ๏setTo(ToType) ๏next(FromItemType) <> Transform:Edge<> ListenEdge:EdgeMutableNode: Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏from() -> Node๏setFrom(Node) ๏to() -> TNooTdyep๏setTo(TNooTdyep) ๏next(FromItemType) ๏from() -> Node๏setFrom(Node) ๏to() -> ToType ๏setTo(ToType) ๏next(FromItemType) ๏value() -> T ๏setValue(T)
  • 43.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • ⾯面向对象的设计 — 构建连接 <> EdgeNode๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T MutableNode: Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T ๏setValue(T) <> Transform:Edge<> ListenEdge:EdgeSomeTransform:Transform, Node> ๏from :Node๏to :Node(weak) ๏next(FromItemType)
  • 44.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • ⾯面向对象的设计 — 构建监听 <> EdgeNode๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T MutableNode: Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T ๏setValue(T) <> Transform:EdgeSomeTransform:Transform, Node> ๏from :Node๏to :Node(weak) ๏next(FromItemType) <> ListenEdge:EdgeSomeListenEdge:ListenEdge, Any> ๏from :Node๏to :Any(weak) ๏next(FromItemType) AnyObject + ListenExtension ๏listenEdges
  • 45.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • ⾯面向对象的设计 — 数据流动 Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T MutableNode: Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T ๏setValue(T) SomeTransform:Transform, Node> ๏from :Node๏to :Node(weak) ๏next(FromItemType) Weak 链条作为传播链条 SomeListenEdge:ListenEdge, Any> ๏from :Node๏to :Any(weak) ๏next(FromItemType)
  • 46.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • ⾯面向对象的设计 — 内存管理理 Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T MutableNode: Node๏value :T ๏upstreamTransforms[] ๏downstreamTransforms[](weak) ๏listenEdges[](weak) ๏value() -> T ๏setValue(T) SomeTransform:Transform, Node> ๏from :Node๏to :Node(weak) ๏next(FromItemType) Strong 链条作为内存管理理 SomeListenEdge:ListenEdge, Any> ๏from :Node๏to :Any(weak) ๏next(FromItemType) AnyObject + ListenExtension ๏listenEdges
  • 47.基于图和⾯面向对象的 EasyReact • ⾯面向对象的设计 • 类型定义 • 构建连接 • 构建监听 • 数据流动 • 内存管理理 EasyReact 技术重点
  • 48.基于图和⾯面向对象的 EasyReact • 基于图的数据结构 • ⾯面向对象的设计 • 使⽤用示例例 EasyReact 技术重点
  • 49.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • 使⽤用示例例 • 创建节点 • 创建变换 • 连接节点 • 创建监听 • 连接监听者 • 改变节点值 let nodeA = MutableNode(1) let nodeB = Node() let transform = MapTransform { $0 * 2 } transform.set(from:nodeA) transform.set(to:nodeB) let listenEdge = BlockListenEdge{ print($0) } nodeB.listened(by:self).with(listenEdge) nodeA.set(5)
  • 50.基于图和⾯面向对象的 EasyReact EasyReact 技术重点 • 使⽤用示例例 • 创建节点 • 创建变换 • 连接节点 let nodeA = MutableNode(1) let nextNode = nodeA.map { $0 * 3 } nextNode.listened(by:self).with { print($0) } • 创建监听 • 连接监听者 • 改变节点值 • 变换衍⽣生 • 便便捷监听
  • 51.• 声明式编程中的响应式编程 • 基于图和⾯面向对象的 EasyReact • 主流框架对⽐比 EasyReact 技术重点
  • 52.主流框架对⽐比 EasyReact 技术重点 易易⽤用性 性能 排错能⼒力力
  • 53.主流框架对⽐比 EasyReact 技术重点 易易⽤用性 性能 排错能⼒力力
  • 54.主流框架对⽐比 易易⽤用性对⽐比 RAC & RxSwift • Immutable • Cold signal & Hot signal • Signal, Producer and Subject • Functor, Applicative, Monad EasyReact 技术重点 EasyReact • Mutable • Link, sync • Node, Edge, Listener • OOP designed
  • 55.主流框架对⽐比 EasyReact 技术重点 易易⽤用性 性能 排错能⼒力力
  • 56.主流框架对⽐比 性能对⽐比 500,000,000 EasyReact(Objc) EasyReact 技术重点 ReactiveCocoa 375,000,000 250,000,000 125,000,000 0 listener map filter fattenMap combine zip merge syncTo
  • 57.主流框架对⽐比 EasyReact 技术重点 易易⽤用性 性能 排错能⼒力力
  • 58.主流框架对⽐比 排错能⼒力力——ReactiveCocoa 调试堆栈 EasyReact 技术重点
  • 59.主流框架对⽐比 排错能⼒力力——ReactiveCocoa 调试堆栈 EasyReact 技术重点 • 5次变换 • 50层堆栈 • 堆栈内容⽆无法参考
  • 60.主流框架对⽐比 排错能⼒力力——EasyReact 调试堆栈 EasyReact 技术重点
  • 61.主流框架对⽐比 排错能⼒力力——EasyReact 调试堆栈 EasyReact 技术重点 • 5次变换 • 10层堆栈 • 堆栈内容与变换相符
  • 62.主流框架对⽐比 排错能⼒力力——追溯 EasyReact 技术重点
  • 63.TABLE OF CONTENTS ⼤大纲 • EasyReact 和 EasyMVVM 的项⽬目背景 • EasyReact 技术重点 • EasyMVVM 架构重点
  • 64.• EasyMVVM 框架简介 • EasyMVVM 解决的问题 • Rubik 模块化⽅方案 EasyMVVM 架构重点
  • 65.EasyMVVM 框架简介 EasyMVVM架构重点 整体架构 EasyMVVM UIKit Category Binder Model Event ModelCenter Container Handler Rubik Framework ContentView Cell ListView GridView Presentation ContainerView ContentView ListView GridView Controller Controller Controller Presentation Provider RubikView Controller EasyDebug Toolbox Vis.js Kitura WebSocket Sqlite3 EasyReact Node Operation Mutable Node Node EasyAction Operation’s operation Action EasyNetwork ServiceManager Operation Service Plugins OperationQueue Transform Edge Cancelable ListenEdge EasyFoundation Sequence Thread-safe Collection Tuple Enumerate Useful Blocks
  • 66.• EasyMVVM 框架简介 • EasyMVVM 解决的问题 • Rubik 模块化⽅方案 EasyMVVM 架构重点
  • 67.EasyMVVM 解决的问题 • 声明式的绑定 • 聚合类视图的绑定 • ⻚页⾯面间的依赖 EasyMVVM 架构重点
  • 68.EasyMVVM 解决的问题 • 声明式的绑定 EasyMVVM 架构重点 View Binding ViewModel Invoke Model
  • 69.EasyMVVM 解决的问题 • 声明式的绑定 View (VC) Node Event Handler Binding ViewModel Node Event Handler EasyMVVM 架构重点 Invoke Model Operation Result Error
  • 70.EasyMVVM 解决的问题 • 声明式的绑定 View (VC) Node Event Handler ViewModel Node Node Event Node Node Handler EasyMVVM 架构重点 Model Operation Result Error
  • 71.EasyMVVM 解决的问题 • 声明式的绑定 优惠买单 PaymentVC • rootView ┣ consumeTextField ┃┗ textNode ┣ QRCodeButton ┃┗ clickEvent ┣ excludeCheckbox ┃ ┗ checkedNode ┣ discountLabel ┃ ┗ textNode ┣ couponButton ┃ ┗ clickEvent ┣ paymentLabel ┃ ┗ textNode ┗ conformButton ┗ clickEvent • didAppearEvent • errorMessage EasyMVVM 架构重点 PaymentVM •consume:Node•showQR:Handler •isExclude:Node•discount:'>discount: