SlideShare a Scribd company logo
1 of 92
Download to read offline
Safe Area@johnlinvc
為什麼 App 卡卡的?
John Lin ( @johnlinvc )
Safe Area@johnlinvc
John Lin (@johnlinvc)
• 從 iPhone OS 2 開始寫 Obj-C。

• 目前在 West Pharmaceutical 當 DevOps。

專門寫給開發者(包含自己)用的工具。

還有修別人的 Bug。
Safe Area@johnlinvc
喜歡參加社群活動
Functional Tuesday
Ruby Taiwan
Elixier Taiwan
Taipei.py
Clojure Taiwan
Safe Area@johnlinvc
Swift Taipei
• 從 2016 年 1/14開始,在每個月的第一個禮拜二舉辦。到目前已經辦了
接近 60 次聚會。

• 提供大家一個能夠放鬆討論 Swift 的地方。

• 強力徵求講者中。只要和 Swift 稍微有相關的都非常歡迎。
Safe Area@johnlinvc
常常在研討會上分享
RubyConf CN
Safe Area@johnlinvc
iPlayground
• 去了 iOSDC Japan 後覺得台灣也應該有

• 當場買了 iosdc.tw 網域。

• 後來決定要叫 iPlayground。

iosdc.tw 會導到 iplayground.io
Safe Area@johnlinvc
第一次講 Keynote
• 國內外講了十幾次,感謝主辦方給我 個機會來當 Keynote 講者。

• 終於可以用 Keynote 來做 Keynote 了。
Safe Area@johnlinvc
Safe Area@johnlinvc
iPlayground 的主題
• 當然還是圍繞在 App (不是ㄟㄆ一ㄆ一) 上,。

• 分享相關的實務(踩雷)經驗。

• 探索更多開發上的可能性。
Safe Area@johnlinvc
一個好 App 的條件
1. 符合商業需求。

2. 用起來順手。

3. Optional<漂亮的程式碼>。
Safe Area@johnlinvc
一個好 App 的條件
1. 符合商業需求。

2. 用起來順手。

3. Optional<漂亮的程式碼>。
Safe Area@johnlinvc
做過一陣子的人機介面研究
Safe Area@johnlinvc
什麼是順手
• 外觀漂亮

• 沒有反人類的操作流程

• 行為符合使用者預期
Safe Area@johnlinvc
什麼是順手
• 外觀漂亮

• 沒有反人類的操作流程

• 行為符合使用者預期
Safe Area@johnlinvc
使用者預期的行為
• 使用者的輸入要有適當的回饋。

• 力回饋。

• 視覺回饋。
Safe Area@johnlinvc
力回饋
• 打 盤的時候通常不會看 盤。

機械 盤的力回饋讓我們按起來比較真實。

• iPhone 7/8 上的Home 。

其實是固定的,靠震動讓我們感覺有按下去的感覺。
Safe Area@johnlinvc
視覺回饋
• 螢幕上的使用者介面都是視覺回饋的一部分。

• 點擊後的回饋,像是選擇後的變色,

或是移動到下一個畫面。

• 動後的回饋,像是顯示額外的內容,

或是移動畫面上的物體。
Safe Area@johnlinvc
什麼是卡卡的?
• 老 說卡卡的。

• 畫面不連續。

• 輸入到視覺回饋的時間差太長。
Safe Area@johnlinvc
畫面的連續性
• 真實世界的物體的移動是連續的。

• 在顯示物體移動時,如果人眼能夠發現

中間有被跳過的畫面。就會覺得卡卡的。
Safe Area@johnlinvc
人眼的敏銳度
• 1991 年的研究。視神經細胞對螢幕閃爍的反應。

• 用電極偵測人體視神經對 CRT 螢幕閃爍的反應。

• Human electroretinogram responses to video displays,

fluorescent lighting, and other high frequency sources
Safe Area@johnlinvc
人眼可以看到 76 Hz 的閃爍
Safe Area@johnlinvc
輸入到視覺回饋的時間差
• 真實世界的物體受力後會立刻移動,

沒有任何時間差。

• 使用者操作後過了太久才產生視覺回饋的話,

就會覺得卡卡的。
Safe Area@johnlinvc
回饋要多快才夠快
• 2015 年的研究,

測試使用者對觸控輸入的視覺回饋延遲

的容忍度。

• How Much Faster is Fast Enough? 

User Perception of Latency &

Latency Improvements in

Direct and Indirect Touch
Safe Area@johnlinvc
回饋要多快才夠快
• 對於點擊和 拉有不同的容忍度。

• 點擊 69 ms

• 拉 11 ms
Safe Area@johnlinvc
為什麼會卡卡的?
Safe Area@johnlinvc
> 我們來問一個很簡單的問題:我們所寫過的程式,大多都是從頭到尾、
一行一行往下執行,執行完畢,程式就結束;那麼,一個 GUI 應用程式
—無論是我們現在正在學習的 iOS 與 Mac OS X、還是其他平台—為什麼
不是打開之後一路執行到底結束,而是會停留在螢幕中等待我們操作?

KKBOX iOS/Mac OS X 基礎開發教材
Safe Area@johnlinvc
Run loop
Safe Area@johnlinvc
一個 loop 裡面要做的事
更新畫面
Auto Release
觸發 Timer
接收事件
處理事件
Safe Area@johnlinvc
Run Loop 沒有固定的週期
• 要等到現有的 loop 完之後,才會 下一個 loop。

• 如果在 Event Handler 裡面做了太多事,就會讓下一個 loop 延後開
始。



0 35 70 105 140
Loop 1 Loop 2 Loop 2
Safe Area@johnlinvc
一個 loop 花了太多時間
• 處理滑動超過 11 ms => 滑動卡卡的

• 處理點擊超過 69 ms => 點擊卡卡的
Safe Area@johnlinvc
解決方法
• 重複利用 view/cell/asset 。

• 好好利用多核心處理器。
Safe Area@johnlinvc
解決方法
• 重複利用 view/cell/asset 。

• 好好利用多核心處理器。
Safe Area@johnlinvc
重複使用 View/Cell
• UICollectionView

dequeueReusableCell(withReuseIdentifier:for:)

• UIImage

Cached: init(named:)

Not Cached: init(contentsOfFile:)

• MKMapView

dequeueReusableAnnotationView(withIdentifier:)
Safe Area@johnlinvc
Reusable
• https://github.com/AliSoftware/Reusable

• 可以用 Type Safe 的方法來定義 Reuse identifier.

final class CustomCell: UITableViewCell, Reusable
tableView.register(cellType: theCellClass.self)
let cell = tableView.dequeueReusableCell(for: indexPath) as
MyCustomCell
Safe Area@johnlinvc
解決方法
• 重複利用 view/cell/asset 。

• 好好利用多核心處理器。
Safe Area@johnlinvc
多核心處理器
• iPhone 12 上有 6 個 CPU 核心。

• 可以同時執行多個執行緒。

• 只要把事情分散到各個核心,就可以縮短 run loop 處理時間。
Safe Area@johnlinvc
在別的 thread 做事的方法
• Dispatch

• Combine
Safe Area@johnlinvc
在別的 thread 做事的方法
• Dispatch

• Combine
Safe Area@johnlinvc
Dispatch
• 使用 Obj-C block & Swift closure 來封裝 Thread API。

• 基本上就是把 code 丟到 queue 裡,它就會幫你執行。
Safe Area@johnlinvc
Dispatch
• 用 DispatchQueue.async 就可以讓 code 在別的 Thread 。

DispatchQueue.global(qos: .background).async {
// code to run
}
Safe Area@johnlinvc
Refactoring legacy and concurrent thread API
with Testing
Safe Area@johnlinvc
在別的 thread 做事的方法
• Dispatch

• Combine
Safe Area@johnlinvc
Combine
• 用宣告式的語法來定義資料與事件處理流程。

• Scheduler 可以設定想要在 一個 Thread 上處理資料與事件。
Safe Area@johnlinvc
Combine
• 可以用 receive(on:) 切換 Thread/Queue

Just(1)
.map { _ in print(Thread.isMainThread) } // true
.receive(on: DispatchQueue.global())
.map { print(Thread.isMainThread) } // false
.sink { print(Thread.isMainThread) } // false
Safe Area@johnlinvc
打開 Combine 的引擎蓋來看看
Safe Area@johnlinvc
UIKit 只能在 main Thread 呼叫
• UIKit 沒有 Thread Safety。

• 在別的地方呼叫的話會有 Error 。

• UI API called on a background thread: -[UIView initWithFrame:]
Safe Area@johnlinvc
避免 UIKit thread 問題
• 在 Dispatch 裡用 DispatchQueue.main 切換回 Main Thread

• 在 Combine 裡用 receive(on:) 切換回 Main Thread

• 使用 SwiftUI
Safe Area@johnlinvc
避免 UIKit thread 問題
• 在 Dispatch 裡用 DispatchQueue.main 切換回 Main Thread

• 在 Combine 裡用 receive(on:) 切換回 Main Thread

• 使用 SwiftUI
Safe Area@johnlinvc
Swift UI
• 宣告式的 UI Framework。

• 跨平台。

• Auto Layout。
Safe Area@johnlinvc
使用 Swift UI
struct ContentView: View {
@State var clickCount : Int = 0
var body: some View {
Button(action: add) {
Text("(clickCount)")
.font(.system(size: 120))
}
}
func add() {
clickCount += 1
}
}
Safe Area@johnlinvc
使用 Swift UI
struct ContentView: View {
@State var clickCount : Int = 0
var body: some View {
Button(action: add) {
Text("(clickCount)")
.font(.system(size: 120))
}
}
func add() {
clickCount += 1
}
}
Safe Area@johnlinvc
使用 Swift UI
struct ContentView: View {
@State var clickCount : Int = 0
var body: some View {
Button(action: add) {
Text("(clickCount)")
.font(.system(size: 120))
}
}
func add() {
DispatchQueue.global().async{
clickCount += 1 }
}
}
Safe Area@johnlinvc
使用 Swift UI
struct ContentView: View {
@State var clickCount : Int = 0
var body: some View {
Button(action: add) {
Text("(clickCount)")
.font(.system(size: 120))
}
}
func add() {
DispatchQueue.global().async{
clickCount += 1 }
}
}
Safe Area@johnlinvc
使用 Swift UI
• 更新UI 通常都是透過 @State property wrapper。

• @State 是 Thread safe 的。可以從任何 Thread 修改他的值。
Safe Area@johnlinvc
解決方法
• 重複利用 view/cell/asset 。

• 好好利用多核心處理器。
Safe Area@johnlinvc
不知道從 開始改?
Safe Area@johnlinvc
封裝!封裝!再封裝!我要成為封裝大師!
Safe Area@johnlinvc
放開那個 MVC
Safe Area@johnlinvc
手把手帶你用 Clean Swift 重構 MVC, 並替核心程式碼
寫單元測試
Safe Area@johnlinvc
怕改壞?怕改太久?
Safe Area@johnlinvc
從獨立開發到大型專案的 CI/CD 攻略
Safe Area@johnlinvc
iOS 開發者 13 倍速技巧
Safe Area@johnlinvc
在別的 thread 做事的方法
• Dispatch

• Combine
Safe Area@johnlinvc
如果核心也全滿了?
• 真的有太多事情要做,就算用了 Dispatch/Combine/async 也會卡?

• 真的沒有辦法了 ?
Safe Area@johnlinvc
你有沒有想過?
• 當程式卡住的時候,所有的操作都會卡住。

• 只有一種操作不會,系統內建的。像是 Home 。
Safe Area@johnlinvc
為什麼 Home 總是有用?
• 理論上,當程式卡在 run loop 中的時候,是沒辦法接收觸控事件的。

• 既然沒辦法接收事件,向上滑的手勢應該沒有任何作用才對?
Safe Area@johnlinvc
電腦科學警告
電腦科學 最新的框架
軟體工程師 

Safe Area@johnlinvc
Darwin-XNU
macOS & iOS 等等使用的底
層核心

Mach 是微核心

BSD 提供 POSIX & Unix API
Safe Area@johnlinvc
分時系統
• iPhone 12 有六個核心,但是我們卻可以同時 上百個
DispatchQueue/Thread。

• 因為一個核心上可以透過分時系統 超過一個thread。
Safe Area@johnlinvc
分時系統
Thread
Safe Area@johnlinvc
Context Switch
• 把目前程式的記憶體和暫存器的內容

記錄起來。

• 把下一個程式的記憶體和暫存器的內容

從記錄裡回覆。

• 把 PC (Program Counter)指向下一個程式,

也就是把控制權交給下一個程式。
Thread
Safe Area@johnlinvc
Context Switch
• 作業系統要怎麼把控制權拿回來?

• 合作式切換:在特定作業時切換

• 非合作式切換:作業系統決定
Thread
Safe Area@johnlinvc
Context Switch
• 作業系統要怎麼把控制權拿回來?

• 合作式切換:在特定作業時切換

• 非合作式切換:作業系統決定
Thread
Safe Area@johnlinvc
合作式切換
• 當程式執行 system call 時 ( IO, 建立 Thread)會把控制權交還給作業
系統, 個時候就有機會做切換。

• 當程式執行非法指令時 (1/0, 讀不合法的記憶體位置)會觸發 trap,
時候系統也會取得控制權,也有機會做切換。
Safe Area@johnlinvc
合作式切換的問題
• 如果程式永遠不呼叫system call 。像是下面 樣,就會永遠沒辦法切
換。

• for true { 1+1}

• MacOS 9 以前是使用合作式切換,所以單一程式有可能卡住整個系統
Safe Area@johnlinvc
Run loop 是一種合作式切換
• 每一次的 loop 都要等 Event Handler 處理完才會進下一個 loop。

• Dispatch 要等現在的 task 處理完才會交出控制權。

• 所以有任何一個 Event/Task 處理太久, App 就會卡住。
Safe Area@johnlinvc
Context Switch
• 作業系統要怎麼把控制權拿回來?

• 合作式切換:在特定作業時切換

• 非合作式切換:作業系統決定
Thread
Safe Area@johnlinvc
非合作式切換
• 系統要把控制權交給下一個時,會設定一個硬體計時器。

• 計時器時間到後會觸發一個Trap,把控制權強制交給系統。

• 如果時間到前就交回控制權的話,就重置計時器。
Safe Area@johnlinvc
0x8BADF00D
• 如果有程式過了很久都沒有進展。

• Darwin 會啟動 WatchDog Timer。把那個程式終止。

• 錯誤代碼就是 0x8BADF00D, ate bad food。
Safe Area@johnlinvc
Darwin-XNU 使用非合作式切換
• 當單一程式卡住的時候,不會影響其他程式。

• 當 App 卡住的時候, SpringBoard 不會被影響,所以 Home 還是可以
正常運作。
Safe Area@johnlinvc
讓 Run loop 用非合作切換?
• 設定每個 loop 可以用來處理 Event 的時間。當時間到的時候就強制交
出控制權。

• 下一個 loop 再繼續剛剛沒做完的事。
Safe Area@johnlinvc
Bringing Theory Into Practice: A Userspace Library for Multicore
Real-Time Scheduling
• 在 Linux 的 Userspace 上執行的 noncooperative scheduler。

• 可以在使用者的程式內模擬 OS 的切換。

• 也就是說,可以讓 UI 不會卡住。
Safe Area@johnlinvc
可能的實作方法
• 特製的 Combine Scheduler ,當時間到就停止,下一個 loop 自動重
試。

• Swift main branch 實驗中的 Async/Await + Actor,當沒有共享記憶體
時,task 就可以重試且沒有不想要的副作用。
Safe Area@johnlinvc
run loop 非合作切換的缺點
• 沒寫好的話,可能會有多次的副作用,像是 print 了兩次。

• 畫面可能會有不完整的更新。因為更新到一半就被中斷了。
Safe Area@johnlinvc
UIKit SwiftUI
非合作式 

run loop
優點 最成熟
可以把所有的事都
移到其他 Thread
寫出來的App一定不
會卡卡
缺點
最難寫出不會卡卡
的App
還不成熟
畫面可能更新不完全

好像還沒有人做
Safe Area@johnlinvc
什麼是 App 卡卡 ?
• 畫面的更新頻率低於 76Hz

• 滑動超過 11 ms 沒有回饋

• 點擊超過 69 ms 沒有回饋
Safe Area@johnlinvc
App 卡卡的
• Run loop 的一個 loop 了太久。 到了下一個 loop。

• 沒辦法更新畫面。

• 沒辦法接收輸入。
Safe Area@johnlinvc
App 卡卡的處理方法
• 縮短運算時間,使用快取,Cell Reuse。

• 使用 GCD, Combine 來把事情移到 run loop 外執行。
Safe Area@johnlinvc
未來展望
• Async / Await 可以讓我們更容易把事情移到其他 Thread 處理。

• 說不定可以在 App 內做非合作式 scheduling,有興趣的可以等等來一
起研究研究。
Safe Area@johnlinvc
References
• https://stackoverflow.com/questions/18738453/how-does-the-compiler-
know-a-button-has-been-pressed/18739381

• https://www.objc.io/issues/3-views/moving-pixels-onto-the-screen/ 

• https://zonble.gitbooks.io/kkbox-ios-dev/content/responder/run_loop.html 

• http://pages.cs.wisc.edu/~remzi/OSTEP/ 

• https://yuriktech.com/2020/03/07/User-Space-Scheduling/ 

• Apple Developer Documentation
Safe Area@johnlinvc
References
• https://semianalysis.com/apples-a14-packs-134-million-transistors-
mm2-but-falls-far-short-of-tsmcs-density-claims/

• https://ckitakishi.com/2016/08/17/WatchDog-
%E6%9C%BA%E5%88%B6/
Safe Area@johnlinvc
Q&A
• 投影片的位置在

• John Lin

Twitter: @johnlinvc

• 歡迎來 Swift Taipei 分享或聊聊

More Related Content

Similar to 為什麼 App 卡卡的

PyCon China 2012 孙毅
PyCon China 2012 孙毅PyCon China 2012 孙毅
PyCon China 2012 孙毅Yi Sun
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享zenyuhao
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩Wen-Tien Chang
 
Automate with Ansible basic (2/e)
Automate with Ansible basic (2/e)Automate with Ansible basic (2/e)
Automate with Ansible basic (2/e)Chu-Siang Lai
 
Angular 开发技巧 (2018 ngChina 开发者大会)
Angular 开发技巧 (2018 ngChina 开发者大会)Angular 开发技巧 (2018 ngChina 开发者大会)
Angular 开发技巧 (2018 ngChina 开发者大会)Will Huang
 
使用 Pytest 進行單元測試 (PyCon TW 2021)
使用 Pytest 進行單元測試 (PyCon TW 2021)使用 Pytest 進行單元測試 (PyCon TW 2021)
使用 Pytest 進行單元測試 (PyCon TW 2021)Max Lai
 
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰Scourgen Hong
 
MySQL自动切换设计与实现
MySQL自动切换设计与实现MySQL自动切换设计与实现
MySQL自动切换设计与实现orczhou
 
主库自动切换 V2.0
主库自动切换 V2.0主库自动切换 V2.0
主库自动切换 V2.0jinqing zhu
 
Java SE 8 技術手冊第 11 章 - 執行緒與並行API
Java SE 8 技術手冊第 11 章 - 執行緒與並行APIJava SE 8 技術手冊第 11 章 - 執行緒與並行API
Java SE 8 技術手冊第 11 章 - 執行緒與並行APIJustin Lin
 
2014暑期訓練之Linux kernel power
2014暑期訓練之Linux kernel power2014暑期訓練之Linux kernel power
2014暑期訓練之Linux kernel power冠宇 陳
 
Html5移动网站开发实践
Html5移动网站开发实践Html5移动网站开发实践
Html5移动网站开发实践Web Zhao
 
出了问题不要靠猜
出了问题不要靠猜出了问题不要靠猜
出了问题不要靠猜LI Daobing
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代scott liao
 
該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?Andy Dai
 
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & WindowsChu-Siang Lai
 
基于 lucene 的站内搜索
基于 lucene 的站内搜索基于 lucene 的站内搜索
基于 lucene 的站内搜索fulin tang
 
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)JoXuZi
 

Similar to 為什麼 App 卡卡的 (20)

PyCon China 2012 孙毅
PyCon China 2012 孙毅PyCon China 2012 孙毅
PyCon China 2012 孙毅
 
IOS入门分享
IOS入门分享IOS入门分享
IOS入门分享
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
 
Automate with Ansible basic (2/e)
Automate with Ansible basic (2/e)Automate with Ansible basic (2/e)
Automate with Ansible basic (2/e)
 
Angular 开发技巧 (2018 ngChina 开发者大会)
Angular 开发技巧 (2018 ngChina 开发者大会)Angular 开发技巧 (2018 ngChina 开发者大会)
Angular 开发技巧 (2018 ngChina 开发者大会)
 
使用 Pytest 進行單元測試 (PyCon TW 2021)
使用 Pytest 進行單元測試 (PyCon TW 2021)使用 Pytest 進行單元測試 (PyCon TW 2021)
使用 Pytest 進行單元測試 (PyCon TW 2021)
 
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰
从林书豪到全明星 - 虎扑网技术架构如何化解流量高峰
 
I os 07
I os 07I os 07
I os 07
 
MySQL自动切换设计与实现
MySQL自动切换设计与实现MySQL自动切换设计与实现
MySQL自动切换设计与实现
 
主库自动切换 V2.0
主库自动切换 V2.0主库自动切换 V2.0
主库自动切换 V2.0
 
Java SE 8 技術手冊第 11 章 - 執行緒與並行API
Java SE 8 技術手冊第 11 章 - 執行緒與並行APIJava SE 8 技術手冊第 11 章 - 執行緒與並行API
Java SE 8 技術手冊第 11 章 - 執行緒與並行API
 
2014暑期訓練之Linux kernel power
2014暑期訓練之Linux kernel power2014暑期訓練之Linux kernel power
2014暑期訓練之Linux kernel power
 
Html5移动网站开发实践
Html5移动网站开发实践Html5移动网站开发实践
Html5移动网站开发实践
 
出了问题不要靠猜
出了问题不要靠猜出了问题不要靠猜
出了问题不要靠猜
 
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
DevOpsDays Taipei 2018 - Puppet 古早味、新感受:改造老牌企業進入自動化時代
 
該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?該怎麼樣(認真的)部署你的 Python Web 應用程式?
該怎麼樣(認真的)部署你的 Python Web 應用程式?
 
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
現代 IT 人一定要知道的 Ansible 自動化組態技巧 Ⅱ - Roles & Windows
 
基于 lucene 的站内搜索
基于 lucene 的站内搜索基于 lucene 的站内搜索
基于 lucene 的站内搜索
 
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)
Scrum gathering 2012 Shanghai_精益与持续改进分会场演讲话题: 大型企业ci平台建设和实施分享(陈小光)
 
LabView with Lego NXT
LabView  with Lego NXTLabView  with Lego NXT
LabView with Lego NXT
 

為什麼 App 卡卡的