Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Functional Reactive Programming 介绍
Search
Jichao Wu
June 10, 2015
Programming
1
110
Functional Reactive Programming 介绍
介绍了FRP由来 以及其中的一个关键概念 "derived state"
Jichao Wu
June 10, 2015
Tweet
Share
Other Decks in Programming
See All in Programming
SwiftUIで単方向アーキテクチャを導入して得られた成果
takuyaosawa
0
270
2,500万ユーザーを支えるSREチームの6年間のスクラムのカイゼン
honmarkhunt
6
5.2k
『GO』アプリ バックエンドサーバのコスト削減
mot_techtalk
0
140
第3回 Snowflake 中部ユーザ会- dbt × Snowflake ハンズオン
hoto17296
4
370
Flutter × Firebase Genkit で加速する生成 AI アプリ開発
coborinai
0
150
苦しいTiDBへの移行を乗り越えて快適な運用を目指す
leveragestech
0
340
SwiftUI Viewの責務分離
elmetal
PRO
1
220
ファインディの テックブログ爆誕までの軌跡
starfish719
2
1.1k
Software Architecture
hschwentner
6
2.1k
ASP. NET CoreにおけるWebAPIの最新情報
tomokusaba
0
360
Pythonでもちょっとリッチな見た目のアプリを設計してみる
ueponx
1
530
密集、ドキュメントのコロケーション with AWS Lambda
satoshi256kbyte
0
190
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3k
Build The Right Thing And Hit Your Dates
maggiecrowley
34
2.5k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
Java REST API Framework Comparison - PWX 2021
mraible
28
8.4k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
9
430
Optimizing for Happiness
mojombo
376
70k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Writing Fast Ruby
sferik
628
61k
VelocityConf: Rendering Performance Case Studies
addyosmani
328
24k
Why You Should Never Use an ORM
jnunemaker
PRO
55
9.2k
Transcript
Functional Reactive Programming 公司刚开始的时候 就我⼀一个⼈人做iOS这块 后来来了两个pm 以及两个开发⼩小伙伴 产品进⼊入快速迭代时期 随着需求越来越多越来越复杂 开发的⼩小伙伴
越来越多 ⽔水平也不⼀一样 开发新功能和维护变得越来越困难 我意识到 由于我的经验不⾜足 没有给⼯工程做好⼀一个完整的架构设计 所以才遇到了这些问题
Model View Controller 这是apple期待我们的mvc架构 层次分明 责任明确
Massive View Controller 这是我的代码的架构 数据 和业务 全在vc ⾥里⾯面
Move Fast => App Growing 其实刚开始写的时候 代码全写在⼀一起 , ⼀一次写好所有的功能, 感觉还不错
但是 我们在创业啊 我们要迭代 这时候问题就来了 我刚刚说 随着需求越来越多 开发新功能和维护变得越来越困难 为什么越来越困难啊 这个要从源头说起
Input & Output 我们的app从根本上就是接受输⼊入 经过处理整合然后输出⼀一些东⻄西 那什么是输⼊入 什么是输出
input Taps Keyboard events GPS events Web service responses 输⼊入:
⽤用户的点击 输⼊入啊 UI时间 web服务的相应 等等 输出: ⼀一般就是ui的变化
State BOOL dataLoaded; BOOL refreshing; BOOL enabled; BOOL selected; 那我们⼀一般怎么处理这些input呢
我们⼀一般⽤用⼀一些state去记录处理这些input visible enabled selected loaded refreshing
New feature? New state. New complexity. New bugs. 这有⼀一个什么问题呢 有新的需求
带来新的state 代码就越来越复杂为了什么越来越复杂了 {翻⻚页}
State BOOL dataLoaded; BOOL refreshing; BOOL enabled; BOOL selected; BOOL
visible; 2 states 4 states 8 states 16 states 32 states 我们有四个状态 看起来只有四个 其实有16种可能 我们再加⼀一个 就是32种可能了 ⽤用到state两种情况 ⽐比如我们有bug了 往往要跟踪⼀一个state变量 我经常会⽤用状态名字全局搜索 这些状态往往散落在各个⽅方法⾥里 因为我不知道那个⽅方法有副作⽤用改了这个state state 散落在各处 对调试简直是噩梦 所以说 新的需求 带来新的state state越多代码越复杂 复杂就容易出bug 我们怎么去避免使⽤用state 或者我们有没有⼀一种⽅方法能预测state的变化
Functional Programming 有⼀一个 input 经过 函数作⽤用 输出⼀一个 f(x) 这为啥能避免引⼊入state呢
Functional Programming • pure function • 函数结果不依赖任何state • 函数不改变外部state •
high-order function • 函数做参数, 函数返回函数 • tail recursion • composition • y = f(g(x)) 在我看来 函数式编程的作⽤用就是把⼀一个个函数函数串在⼀一起 因此消灭了状态 ⽐比如说gx直接做f的input 就可以避免⼀一个state出现
Model View View-Model 状态消除了 我刚刚还说的⼀一个问题就是vc干了太多事情, 这个好办 就是分层 在MVC的基础上,把C拆出⼀一个ViewModel专⻔门负责数据处理的事情
View-Model (UI events, web response) (UI) 更重要的是 viewmodel作为input 和output之间的桥梁 它还负责数据的合并和转化
这时候 我们的data flow就很清晰了
Data Flow Ownership view 持有 view model, view model 持有
model ⼀一个view可以持有多个view model view model 可以组合起来⽤用 对 view-model, view是不可⻅见的, 两者不耦合 这样view-model 就可以重⽤用 还可以⽅方便测试 那我们怎么把view-model和view连起来呢 view怎么拿到input经过view model 合并转化处理过的值? input往往都是⼀一些接连不断的进来的东⻄西 像⽤用户的点击 输⼊入啊, socket的不断接收数据啊 我们可以在每次有新的output的时候 通知view更新 但是我们上⼀一张图 viewmodel是看不到view的 (为什么? 分层啊? 便于脱离ui层测试 ) 那么view怎么知道什么时候更新? ⽐比如view-model发全局通知 或者view observer view-model, kvo 这时候 我们就可以引⼊入reactive programming
Reactive Programming “programming around data flows and the propagation of
change”
把b改成3 在reactive programming⾥里 c就会相应的变成5 这⾥里看起来没什么⼤大⽤用 但是把前⾯面functional programming 和 reactive programming
结合起来 就成了⽕火了好⼀一阵的 functional reactive programming
Functional Reactive Programming ReactiveCocoa FRP 在 iOS 上的⼀一个实现, 由 Github
开发 为了避免状态我们⽤用了函数式 为了view绑定view-model的值 我们⽤用了响应式编程 合起来就是frp ReactiveCocoa是⼀一个将函数响应式编程范例带⼊入Objective-C的开源库。由Josh Abernathy和Justin Spahr-Summers在对GitHub for Mac的开发过程中建⽴立
INPUT (signal) • UI events • web service responses •
timer triggers • GPS events } 让我们重新回到input和output上 看看他们是怎么结合的 ui 事件 (点击啊 输⼊入啊) web services 响应 这些都是input 他们都有个特点是 他们的值都会随着时间变化(time-varying value) 在reactive cocoa⾥里 他们都被包装成 signal
derived state derived state 是绑定到signal上的state derived state 意味着你不能去直接设置它的值 它的值依赖于signal把input的值转化合并⽽而成 说完了输⼊入
说说处理 什么是derived(衍⽣生) state 刚刚不是说state不好吗? state在函数式编程中可以避免, 但是在cocoa编程中⽆无法避免 在reactive cocoa⾥里 只要derived state绑定在⼀一个signal上(若干个input的组合) 它就是可以接受的 它意味着你不能去直接改变他的值, 它的值根据 input的值转化合并⽽而⾃自动⽣生成 ======================================== 实际上 derived state 就是 view-model 和 view之间的桥梁 我们再回到input和output上
在理论上 函数式编程 给它⼀一个x 经过f() 输出⼀一个f(x) 不带任何副作⽤用 不引⼊入什么state
View-Model (UI events, web response) (UI) 在ui编程中 我们希望把(ui 事件, web
相应 这些input 经过view model转化合并处理后 在view上展现
signals derived states views derived states <= view-models(signals) views <=
derived states view = view-models(signals) 在iOS的frp的⼀一种实现 reactive cocoa 把 input 统⼀一成了signal (随着时间变化的value), 然后在view-model上转化合并这些inputs成derived states, 之后view绑定到这些 derived states上 在刚看看rac时 我经常会好奇 为神⻢马model的属性 要在viewmodel上重新写⼀一遍 然后再绑定到view上, 多⿇麻烦啊 后来看资料看到了dervied state 英语不好死活理解不了 看了好多资料才知道 dervied state 就是view model上的那些属性, 在最简单的情形下就是model的属性, ⽐比如⼀一个整数年龄转化成⼀一个年龄字符串 xx岁, 来⽅方便view显⽰示 但是复杂情形下 derived state 就是对 好多input做⼀一些复杂的转化和合并 最终合成了derived state 供view绑定 说了这么多虚的 我们来个demo
derived states <= view-models(signals) views <= derived states view <=
view-models(signals)
Demo
输⼊入时⾃自动搜索关键词 ⽤用户输⼊入关键词时 ⾃自动进⾏行搜索 且只有在关键词⻓长度⼤大于2 并且0.3s内的输⼊入请求⼀一起发出 最后显⽰示结果 ⾃自动搜索 特点是⽤用户输⼊入是不断变化的 特别适合使⽤用rac来处理 我们的要求是
⽤用户输⼊入关键词时 ⾃自动进⾏行搜索 且只有在关键词⻓长度⼤大于2 并且0.3s内的输⼊入请求⼀一起发出 加⼊入⽤用户输的太快的话 我们不能⼀一直请求吧 最后显⽰示结果 input 就是⽤用户的输⼊入 处理就是 过滤 忽略 搜索 我们甚⾄至可以借助 switchToLatest 把上次输⼊入的但还未完成的请求拍抛弃掉 取消⽆无⽤用请求
总结 - Design Information Flow - Define Clear Responsibilities (分层,
分模块) - Simplify with Immutability (最⼩小化使⽤用的状态 最⼩小化函数的副作⽤用) 最后今天我想说的就是 不管哪⼀一种编程 哪⼀一种架构 借⽤用wwdc⼀一个演讲的总结 是⼀一个关于架构的总结 对应今天我讲的 第⼀一个就是 我们需要理清 data flow 2 适当分层 分模块 3 最⼩小化使⽤用的状态 最⼩小化函数的副作⽤用
[subscriber sendNext:@"Thank you ~"]; [subscriber sendCompleted]; // Any Question?