從 Clean Architecture 我們學到要把程式架構畫出來,把核心邏輯與其它細節分開來, 避免核心被汙染,達到最終目標:「最小化軟體生命周期的總成本+最大化程式設計師的生產力」。書本裡面給了一個四層的架構圖:Enterprise Business Rules, Application Business Rules, Interface Adapters, Frameworks & Drivers。簡單說前面兩個就是策略、業務規則、核心價值,後面兩個則是細節、資料庫、框架、通訊協定…等等。在這樣的分層規劃下,我們得以確認依賴關係是由外向內的。如果有需要,我們會利用依賴反轉(Dependency inversion principle,DIP)來維持核心的整潔,這樣的架構也允許我們延遲細節的決定。
事件風暴
第二堂課, Teddy帶我們體驗事件風暴(Event Storming),事件風暴是一種快速讓群體進入狀況, 跨部門達成共識的方法,不限於軟體,其實可以應用在各種業務領域,協助建構模型。事件風暴的介紹網路上可以查到很多,規則與範例就不在此贅述,因為事件風暴最重要的是溝通的過程,使用文字敘述很難體會,課程後我與YK(同事)為了讓更多同事也能了解這個溝通方法,因此辦了一個小workshop,邀請了三個不同部門的同事,其中包含測試部門、韌體研發、新技術開發部門一起共同討論「韌體自動化測試工具」這個主題。
共通語言
首先,大家想的真的都不一樣。我們先把12個人分成四個小組,讓大家各自列出這個系統中應該存在的Entity再來互通有無一下,結果發現:有一些東西大家都有共識(每一組都有塞一個專家),一定會有test case,也一定會有report,有一些東西則是我有你沒有,你有我沒有。但是即使是一樣的東西,各自表述之後就會發現,你的report跟我的report可能又不一樣,A組的包山包海,測試結果/細節步驟/結果統計圖,B組的只有成功與失敗,另外還有一個叫做debug log的會包含細節,沒有一個絕對的答案, 重要的是我們要找到共同的語言(ubiquitous language)。共通語言除了釐清彼此的想法以外,還有加速溝通的效果,建立共通語言後,可以提升溝通效率,不論是文件、程式或開會。例如當要做一個跟影像有關的專案的時候,我們可以在早期建模的溝通過程中,發現是不是所有成員都有3A的觀念,知道AE, AF, AWB是什麼,避免專案走到後期,才發現彼此有很大的誤解。
可視化流程
除了共通語言以外,事件風暴還提供了一個全面的可視化流程,我們同步大家的共同語言後,把四組合併成兩個組進行事件風暴,我們故意讓大家先用傳統方法從Entities開始發想,再補充上use cases,讓大家先跑一次流程。
事件風暴跟從核心出發不一樣,而是從領域事件開始展開(我們認為有點像是從use cases展開),兩組分別列出我們在乎的領域事件,看到大家不斷的貼上、移動、調整,對整個流程重新順一次,我想這就是事件風暴要的效果,最後產生一個看得到的用戶故事(User stories)。
我感覺event storming有點類似非coding版本的mob programing,用一種方法把群體的思維聚焦在同一個問題上,並且利用交流讓整體意識調整到相同頻率取得共識,共識後的產物是經過大家認可的業務邏輯與範圍,所以真正執行或實作的時候大家是朝同一個目標努力的。
|
在我們團隊快要一年了
一年的時間
寶寶可以長牙
台灣可以賣出 10 億杯飲料
營業額可以突破千億…
營業額可以突破千億…
經濟部統計處: 飲料店營業額在台灣逐年攀升 |
不說飲料
最近回顧了這一年的行事曆
我是有點吃驚的
我是有點吃驚的
OMG!
原來工作的方式,可以這樣影響生活
越工作越有活力
原來工作的方式,可以這樣影響生活
越工作越有活力
如何影響呢?
我先賣個關子,先來看幾個大部分的組織會遇到的現象。
第一個常見現象:開週會
Why are meetings so ineffective?
一個規模不大的四人團隊
一人報告一小時
一場 weekly meeting 就是四個小時
一人報告一小時
一場 weekly meeting 就是四個小時
如果你曾經有在電影院睡著的經驗
應該不難體會四個小時以上的會議有多累
應該不難體會四個小時以上的會議有多累
為什麼 weekly meeting 要開這麼久?
畢竟是一週的進度回報,如果每個人報告一個小時
相當於把他五個工作天,一天八小時的工作量
用 40 倍速的快進,講給你聽
奇怪的是,我們心理從來沒有出現這樣的聲音
“哇! 我聽到了 1/40 的超級濃縮精華/乾貨耶! ”
我們只希望他能再快個 40 倍
這不能怪同事,就像在電影院睡著其實也不能怪導演
這不能怪同事,就像在電影院睡著其實也不能怪導演
沒有哪個導演拍片是為了讓觀眾睡的
比較可能的是 —
那個議題和你沒有共鳴
Great movies tell stories that have deep emotional resonance
|
第二個常見現象:同事間的工作互換困難
Why is collective work difficult?
我們很常因為負責了某個案子,後續的東西都交給你來處理
因為這是短期看來最省時間的做法
因為這是短期看來最省時間的做法
當你在公司一陣子了,你會自然而然地有一個對照表:
“X module 的問題要找同事 A
Y module 的問題找同事 B”
“X module 的問題要找同事 A
Y module 的問題找同事 B”
你應該也對這種情況不陌生 —
同事 B: “A 請假耶,這問題要等他回來才能處理喔! ”
很少同事 B 會說: “A 請假,那你先把東西給我,我可以處理”
同事 B: “A 請假耶,這問題要等他回來才能處理喔! ”
很少同事 B 會說: “A 請假,那你先把東西給我,我可以處理”
但其實,這種工作互換、集體協作的例子,在生活中明明很常見
比如說便利商店的店員,A 忙著做咖啡、B 來幫忙結帳
從沒見過哪個店員跟你說:
“不好意思我不能幫您結帳,負責收銀的今天請假,我只會泡咖啡”
“不好意思我不能幫您結帳,負責收銀的今天請假,我只會泡咖啡”
上述這種情況在組織裡卻很常發生,原因是什麼呢?
可能是訓練文化
不知不覺把 ”人” 訓練成一台 “機器” (咖啡機/收銀機)
不知不覺把 ”人” 訓練成一台 “機器” (咖啡機/收銀機)
因此當我發現這裡的 team member 可以輕鬆的交換手頭上的工作
我是很驚訝的
我是很驚訝的
Machine learning or human learning?
|
第三個常見現象: 加班
Why work overtime?
你有玩過比手畫腳這類的傳話遊戲嗎? 通常結果都是各種歪樓
你可能會說,如果大家都能看到題目就不會有問題
No,還是不行
比如先前 U Think I Do 系列
就把朋友、家人、社會、學校、自己
看到一件事情的不同面向
放在一張圖裡,非常有趣
比如先前 U Think I Do 系列
就把朋友、家人、社會、學校、自己
看到一件事情的不同面向
放在一張圖裡,非常有趣
不同角度的生命科學系
|
撇除那種時程明顯不合理的情況
大多數的加班來自於
每個人對事物的理解不同:
大多數的加班來自於
每個人對事物的理解不同:
以為自己了解對方想要的功能
↓
發現不是對方想要的功能
↓
“盡量” 修改,改不完就加班
↓
發現不是對方想要的功能
↓
“盡量” 修改,改不完就加班
這個 “盡量” 可能妥協了很多事情
如果前面幾次靠著加班,都很幸運的在 deadline 前完工了
如果前面幾次靠著加班,都很幸運的在 deadline 前完工了
再遇到這種情況的時候,就會習慣性的把加班變成解決方法
而忘了去想該修正哪些流程
而忘了去想該修正哪些流程
又下班了?! 我還想工作
|
PM、RD、UX 都用自己的角度去理解、開發功能,在溝通不足、流程不透明的情況下,這個專案就會越來越像一個黑盒子
當老闆問這件事情什麼時候可以做完
是不會有人知道的
是不會有人知道的
高中物理就告訴我們,根據不確定性原理
專案的完成和沒完成,是同時存在的
只有打開黑盒子的一瞬間才會塌縮到一種可能性上
這種 “既完成又沒完成”
把人逼的 “既死又活” 的現象
把人逼的 “既死又活” 的現象
我們稱之為 —
薛丁格的專案
Schrödinger’s Cat 薛丁格的貓
|
本篇文章未完,你可以現在前往 Part2
也可以往下滑留下一些意見
The Year of Being Agile (Part 1)
我們再歸納一下,一般的組織常遇到三個現象:
1. 開冗長的週會
2. 同事間工作互換很困難
3. 加班
2. 同事間工作互換很困難
3. 加班
而我們 team 恰恰相反,有這三個很獨特的地方:
1. 不用開週會
2. 協作容易,你的同事就是你的分身
3. 不用加班
2. 協作容易,你的同事就是你的分身
3. 不用加班
這些特徵好像很難同時並存,你想,不開會怎麼知道同事在做什麼?
同事之間不了解,溝通成本就大
人越多就越複雜,花的時間也多
怎可能不用加班事情還能準時做完?
敏捷開發
Why OverCooked can teach you agile?
來講講 OverCooked 這個遊戲
一開始食物的訂單不多,每個人可以各司其職
專門切肉,專門煮菜,專門洗碗
而隨著訂單暴增和廚房地形改變
如果還是一個人只負責做一件事,時間肯定是不夠用的
一款具備敏捷精神的遊戲
|
Get back in sync
左上角可以看到現在的訂單有哪些
一回合的時間完成越多訂單得分越高
這是一款用嘴巴打仗的遊戲
你準備要拿料還是煮菜
需要什麼幫忙
哪邊需要修正
都要即時說出來
每個玩家都可以看到夥伴的狀況
這種快速 team sync 的方式就是 —
daily scrum meeting / standup meeting
Realtime review
這款遊戲一次最多四位玩家
如果有八個人玩呢?
一般情況就是多出來的四個會在旁邊
觀戰並且嘴砲給建議
等到下一回合再換這一組人拿搖桿
這種 driver & navigator 的方式 —
pair programming / mob programming
The programmer as navigator
|
介紹完遊戲,應該就不難回答我們一開始的問題
How to avoid boring meetings?
這個 team 不是不開會
而是不開沒有效率的會
daily meeting 有一些限制:
最多 15 分鐘,站著開
類似遊戲一回合的計時制
講求快速同步最新狀況
How to develop a cohesive team?
再來講協作:
關心不等於了解
想要了解一件事情
沒有什麼比實際參與還有效的
針對複雜的 task 安排 pair / mob
提倡 collective code ownership
簡單說就是共榮共享
但這樣講可能有點土
所以來看一下維基百科的定義:
合作或協作(英語:Collaboration)是指一種由兩個或兩個以上的個人或團體作為一個共同的目標而交集或在一起共同工作,舉例說明:一個知識分子可以透過合作的關係而去分享知識,再而經過學習和共識達到創作的目標
從上面描述看的出來
合作和凝聚力脫不了關係
那怎樣才能有好的凝聚力呢?
借用本公司的四大核心價值
誠信、 關懷、創新、當責
誠信、 關懷、創新、當責
肯定每個人的付出
讓每個人都看到自己的貢獻 —
一個人走得快一群人走得遠
Why collective intelligence matters?
電影環太平洋裡面
龐大的機器人無法由一人駕駛
需要兩位駕駛員連接彼此的腦神經
共享對方的情感、記憶、經歷
並且認同對方的處境之後
才能同步操控
Pacific Rim: Uprising (2018)
|
好的溝通和協作
就是用心和時間
灌溉的共同記憶
他會形成一個生命體
持續成長
或者說他就是一個生命
你們必須承擔起照顧這個生命的責任
也是這份承擔
讓你們之間的關聯
獨一無二
True collaboration yields better results
|
Iteration based method
Iteration 翻成中文『迭代』
在敏捷方法中是指
把一個大任務切成許多小週期可以完成的的任務
把一個大任務切成許多小週期可以完成的的任務
騰訊創始人馬化騰說:
小步快跑、快速迭代
小步快跑、快速迭代
這是他的產品思路
也成為互聯網創業法則
也成為互聯網創業法則
敏捷開發裡的迭代週期是一個 sprint
sprint 這字有短跑衝刺的意思
很符合迭代的概念
一個 sprint 一般為 2 ~ 4 週
sprint 這字有短跑衝刺的意思
很符合迭代的概念
一個 sprint 一般為 2 ~ 4 週
由團隊討論這個 sprint 能完成的功能
並在 sprint 結束時做個『試營運』
並在 sprint 結束時做個『試營運』
拿到客戶的 feedback
並且快速的衡量修正
並且快速的衡量修正
為了好懂,借個圖舉例
比較了傳統方法與敏捷開發法
如何在三個迭代週期完成蒙娜麗莎
如何在三個迭代週期完成蒙娜麗莎
Jeff Patton did an Iterative Mona Lisa.
|
先來看傳統的開發方法:
在第一階段可以看到蒙娜麗莎的頭
第二階段能看到蒙娜麗莎的左下半身
第三階段是完整的蒙娜麗莎
在第一階段可以看到蒙娜麗莎的頭
第二階段能看到蒙娜麗莎的左下半身
第三階段是完整的蒙娜麗莎
換成用敏捷開發會怎樣呢?
在第一階段是極簡主義派的蒙娜麗莎
第二階段是簡單上色派的蒙娜麗莎
第三階段是佛羅倫薩畫派的蒙娜麗莎
第二階段是簡單上色派的蒙娜麗莎
第三階段是佛羅倫薩畫派的蒙娜麗莎
不論哪個階段都是最小可行產品
很傳神地描述了敏捷的精神 —
很傳神地描述了敏捷的精神 —
接受反饋、迅速擴張
盡快給客戶有價值的產品
盡快給客戶有價值的產品
敏捷帶來的影響
How does agile affect my work and daily life?
所以回到一開始我賣的關子
那個讓我吃驚的行事曆
那個讓我吃驚的行事曆
我發現從以前到現在
晚上時間的利用有了很大的改變
從同事電腦辦公桌變家人散步吹吹風
以前晚下班總要負責關公司的門
有時候關得太順就會不小心鎖到別人
下圖的例外就是我補充的
關門 SOP
|
這一年有了固定的下班時間後
我開始能每天帶著媽媽去運動
我開始能每天帶著媽媽去運動
運動的地方是學校的操場
晚上學校警衛要關門的時候
看著警衛一邊關燈一邊趕人
看著警衛一邊關燈一邊趕人
這種熟悉又親切的感覺 —
等我退休了或許可以來當警衛吧 😝
前是把家當旅館現在是家事盡量管
The Year of Being Agile (Part 2)
從擔任ScrumMaster九個月以來,經歷了三個時期的轉變,
猶如禪宗《指月錄》裡,「見山是山,見山不是山,見山還是山」 的三重境界。
我是以R&D team leader的角色轉職ScrumMaster,
是團隊成員的直屬主管,擁有人事的管理權(招募、解雇及績效考核等…)。
在Scrum的相關介紹裡,都會建議讓ScrumMaster單純化,不要擁有管理權,
這會讓團隊成員對他頭上戴的帽子是ScrumMaster或是主管感到困惑,
甚至妨礙自組織團隊的形成。
往好處想,由於有主管的職權,在推動一些政策或改變時會比較容易,
前提是你必須確保自己要推行的事情是正確的。
既然這是無法避免的問題,我告訴自己要學會竭盡所能解決任何潛在的利益衝突,
尤其是要保持開放的心態鼓勵溝通,避免以威權領導團隊的情況發生。
即使有了心理準備,工程師畢竟是一種過於樂觀的生物,
執行時仍是遭遇了合併角色時可能會犯的那些錯誤。
首先遇到的是我們在doing agile而不是being agile,
我們遵照Scrum的規則執行必要的活動,但活動的進行卻不夠符合其背後的精神。
從Scrum第一天的planning meeting開始,我主導了如何將sprint backlog item拆成task的過程。
daily meeting時我站得太前面,像是傳統的那些會議,
部分團隊成員習慣直接對我報告,而不是其他成員。
當進度落後時,我會主動提出「建議」改變工作的進行方式,
理智上知道sprint是可以失敗的,仍然將sprint是否成功作為我的職責,
想方設法的讓團隊可以在時間內完成。
retrospective meeting時我會幫團隊寫下會議紀錄,作為下次retrospective meeting時的依據,
檢視列為action plan的項目是否有被執行,讓自己變為一個秘書或監督者的角色。
接著是第二階段,我參加了呂毅老師CSM的課程。
在兩天的課程中我學到最多的不是ScrumMaster該做什麼,而是ScrumMaster「不該做」什麼。
課程結束後我期許自己往教練的角色前進,以引導來取代教導;
列出了ScrumMaster該有的特質貼在螢幕前常常提醒自己,尤其是要有耐心,
不要認為自己比集體智慧還要聰明,給團隊足夠的時間,讓他們自己找到答案。
我開始站在團隊成員背後,不再參加planning meeting part.2,
daily時看到問題不會急著指正,只是記下來作為retrospective meeting的準備。
不再由我負責retrospective meeting的紀錄,由團隊自行決定到底要不要寫,
兩個團隊討論後各有各的作法,但都決定不再像之前一樣記在OneNote上。
團隊在這階段有更多的自主性,更符合自組織團隊的定義;
作為交換我們付出了一些代價,例如sprint失敗的機率增加,
在產品開發有些欠缺考慮的地方,造成品質下降。
來到今年,由於新人陸續的加入(佔了1/3),兩個團隊重新分組。
Scrum的核心在於隨時檢驗與調適,依據上階段的成果和團隊目前的情況,
我又調整了自己的工作模式。
扮演理想ScrumMaster的前提在於你有理想的團隊成員,Scrum對此沒有明確定義;
就我的認識,我會以《Google模式》裡的智慧創做者(smart creatives)作為標準,
具有深厚的技術或專業能力,還有創造力與實踐執行的能力,
而且充滿好奇、質疑現狀,以不一樣的方法來應付問題與挑戰。
新人比例偏高加上重新分組,讓團隊的發展回到第一階段的成形期,
除了教練的身份外,我更需要的是老師的角色,傳承我的能力和經驗。
我又開始全程參與planning meeting part.2,只是我不再主導而是提醒,
在團隊的討論中丟出問題,提醒他們沒考慮的地方。
重點不在於討論出什麼樣的解決方案,而在於提問以引發討論,
藉由一個一個問題去淬鍊出越來越好的作法;
必要時我會補充技術上的專業,只有我具備而其他人不知道的資訊來協助討論。
在daily meeting和retrospective meeting時,我依循相同的精神和團隊互動,
依據要處理的課題切換我頭上戴的帽子,可能是ScrumMaster或是資深工程師。
Scrum沒有標準作法,在不同的環境(context)中會有不同的應變,
一切都是trade off,只要想清楚每一個決定的得失,是否合乎敏捷的精神?
最忌諱憑直覺作出反應,讓自己習慣於過往的工作模式。
ScrumMaster的角色衝突
DataMagnet 是讓客戶能夠透過 HTTP POST 傳送 JSON data 並儲存各種資訊到我們的錄影軟體 VAST2, 再透過 VAST2 來搜尋內容的功能客戶用我們的 data magnet 功能, 一天下來會有好幾萬筆的資料,而且內容是夾帶著 image 的 data (base64 format)
而如果這樣的 data 有幾百萬 or 幾千萬筆的資料在 db 裏頭,
雖然我們在 UI 有限制結果的筆數 (50 results/page),也不會針對 snapshot column 去搜尋
但若搜尋條件的範圍一大,例如: 1s 一筆資料,那麼半年範圍就會有高達一千五百萬筆資料,造成搜尋的速度很慢。
而且這樣的 database size 也是很驚人的,以上面的欄位來看 (include image data: 128px*128px) ,15 million 筆數的資料就高達 60G 左右的大小。
所以中間我們就找了幾種作法:
1. Fast text search: https://blog.kapeli.com/sqlite-fts-contains-and-suffix-matches
這做法有幾個流程要改:
首先 Create Table 的方式不一樣了
還有 SELECT 找 string 的方式也不一樣 (match)
也因為我們要 search 的文字是要 match prefix, middle, postfix
原本 fts 只有 prefix mapping, 而上面的 link 跟我們說可以透過 uncompress string 的方式來做到搜尋中間的字串, 但這有幾個缺點:
- 每個 column 個都要多一個 column 來儲存 uncompress 的 string (除了不用搜尋的 snapshot & timestamp column), 但這會增加整個 database 的 size
- or 要增加 compress, uncompress function 在 Create Table 時加入 https://www.sqlite.org/fts3.html#the_compress_and_uncompress_options , 但這要直接使用 SQLite 的 API function, 對我們使用 Qt 包一層的 API 不好實作
重要的是, 我們改了一版用 fts 的 table 來搜尋, 並沒有特別的好....
2. 後來回頭想原本的瓶頸在哪, 拆解一下傳進去的內容...
看到 snapshot 的 column 其實佔了 db 很大的容量
若少了 snapshot 這欄位, 原本的 search 數度就會很快 (5~6 個月的搜尋範圍, 搜尋某個字串, 1s 左右)
所以我們就把 snapshot 的 context 想辦法不要放進去 db 裡面
這樣的好處就是搜尋速度變快好幾倍。
DataMagnet Performance tuning
針對常用的match role, 可利用QHash (or QMap) 多存一份, 來加快 search 效率我們在設計model通常都會定義一個存unique string value的IdRole當作model item的索引, 且會很頻繁對這個role作match, 從"flags對QAbstractItemModel::match的效能影響"中的實驗中可知,
針對string value去作match在效率上是很糟的, 所以只要model數量大到一個程度, 就會很容易使UI thread hang住. 針對這部分的參考解法大致如下,
- maintain一個QHash把每個model item的IdRole value跟相對應的model index存起來
- 複寫match, 如果是是要查IdRole, 就直接從QHash找以提升效率
- 由於QStandardItemModel::clear本身不會觸發rowsAboutToBeRemoved, 所以即使呼叫clear, 還是要主動去清掉hash
#include <QHash>
#include <QModelIndex>
#include <QPersistentModelIndex>
#include <QStandardItemModel>
#include <QVariant>
class MyListModel : public QStandardItemModel
{
Q_OBJECT
public:
enum Roles
{
IdRole = Qt::UserRole + 1,
DataRole
};
MyListModel(QObject *parent = nullptr)
{
// 把每個model item的IdRole value存到QHash裡, key是id, value就是model index (必須用QPersistentModelIndex)
// 如果是tree model記得要recursive把childrn也加進來,
// 主要是如果使用者是先把model item的children都append好, 再append本身進來的話, 只會觸發一次rowsInserted.
QObject::connect(this, &QAbstractItemModel::rowsInserted, [=](const QModelIndex &parent, int start, int end) {
for (int row = start; row <= end; row++)
{
auto mdIndex = index(row, 0, parent);
auto id = data(mdIndex, MyListModel::IdRole);
m_idModelIndexHash.insert(id, QPersistentModelIndex(mdIndex));
}
});
QObject::connect(this, &QAbstractItemModel::rowsAboutToBeRemoved, this, [=](const QModelIndex &parent, int start, int end) {
for (int row = start; row <= end; row++)
{
auto mdIndex = index(row, 0, parent);
auto id = data(mdIndex, MyListModel::IdRole);
m_idModelIndexHash.remove(id);
}
});
}
virtual ~MyListModel() = default;
// 覆寫match function, 如果針對IdRole就去QHash以提升效率
virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override
{
if (role != MyListModel::IdRole)
{
return QStandardItemModel::match(start, role, value, hits, flags);
}
// todo, !m_idModelIndexHash.contains just return empty can enhance performance, but m_idModelIndexHash must be 100% correct
if (!m_idModelIndexHash.contains(value))
{
return QModelIndexList();
}
return QModelIndexList() << m_idModelIndexHash.value(value);
}
// 由於QStandardItemModel::clear本身不會觸發rowsAboutToBeRemoved, 所以clear記得要主動清掉hash
void clearIdHash()
{
m_idModelIndexMap.clear();
}
QHash<int, QByteArray> roleNames() const override
{
QHash<int, QByteArray> hash;
hash[MyListModel::DataRole] = "dataRole";
hash[MyListModel::IdRole] = "idRole";
return hash;
}
protected:
QHash<QVariant, QPersistentModelIndex> m_idModelIndexHash;
};
延續"flags對QAbstractItemModel::match的效能影響"中的實驗方法,
如果利用QHash得到的結果如下,
match from | elapsed (ms) |
---|---|
QStandardItemModel::match | 55194 |
QHash | 63 |
如何提升 QAbstractItemModel::match 的效能
秘訣: flags 只要用 Qt::MatchExactly 即可, 如果是 tree model 則再加上Qt::MatchRecursive
QModelIndexList QAbstractItemModel::match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const
QAbstractItemModel::match中 flags 參數其實是蠻巨大的.
一般我們在輸入這個 flags 通常都是 copy / paste 舊有的 code , 所以最常看到的組合就是"Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive"如以下所示,
model.match(model.index(0,0), IDRole, value, 1, Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive);
這用法如果遇到value(QVariant)原本的型別是非字串, 例如int, 會導致所有比對都會先轉型成字串再作字串比對,
這是很沒有效率的, 例如對100000筆資料的list model中針對int value作match得到以下的結果,match for int value flags | elapsed (ms) |
---|---|
Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive | 125593 |
Qt::MatchFixedString | Qt::MatchCaseSensitive | 120216 |
Qt::MatchExactly | 22162 |
還有一點就是如果是list model的話, 就不必要下Qt::MatchRecursive, 這樣又可增進一點效能.
另外對string value作match得到的結果如下,
match for string value flags | elapsed (ms) |
---|---|
Qt::MatchFixedString | Qt::MatchCaseSensitive | 56188 |
Qt::MatchExactly | 55194 |
flags 對 QAbstractItemModel::match 的效能影響
VIVOTEK Digest
這裡是 VIVOTEK 晶睿通訊 的技術部落格,我們在這裡分享與敏捷、Qt/QML及其它軟體相關技術
Trending
-
「不要試圖覆蓋所有使用案例。Spec.不是用來替代組合回歸測試的。」 - Spec by Example 中文版 p.151 但我們明明覺得現在用 Robot Framework 實現自動化 UAT 來替代組合回歸測試是很正確的做法,為什麼作者覺得這樣不對? 我認為...
-
平常 C++ 的開發工具是 Microsoft Visual Studio,然後現在的測試框架是使用 Google Test,以前都是一邊寫,一邊手動執行 test case 來驗證,沒有辦法跟 VS 內建的 Test Explorer 做整合,真的蠻原始的 =.= 最近因為...
Categories
Programming
19
Culture
11
Testing
6
scrum
6
Agile
5
performance tuning
4
Book
3
Code Quality
2
Qt
2
Event Storming
1
database
1
file system
1
virtual machine
1
聯絡我們
與我們交流
如果你有任何想法、問題,歡迎在這裡留言與我們連絡 :-)