還記得 CFD 的概念嗎?其實他就是把每天各階段的 PBI 張數疊加起來的一個趨勢圖,用之前繪製的圖協助讀者喚醒回憶。
為了產出這個圖表,會需要想辦法從數據推算出每天各階段的 PBI 的張數,也就是以下階段的張數。那難不成要想辦法每天做個快照紀錄當時的數字嗎?過去在玩 Kanban 相關桌遊的時候,的確是採取這樣的實踐,但事實上在前面某篇分析需求的文字介紹裡,就有提到其實可以透過時間戳來反推當時的張數。假設某天為 X,以 Development 階段為例,只要在所有 PBI 中,找到 began to develop at
有時間戳,且其日期早於 X,並且 developed at
無時間戳或是其時間戳晚於 X,就可以知道 X 時,有幾張 Development 的 PBI。以此類推:
created at
≤ X < refined at
refined at
≤ X < selected at
selected at
≤ X < began to develop at
began to develop at
≤ X < developed at
developed at
≤ X < tested at
tested at
≤ X < reviewed at
reviewed at
≤ X < deployed at
deployed at
≤ X一樣先建立推算某日張數所需數據的標題列,第一列是階段名稱,第二列是用來計算該階段某日張數所需要的數據名稱。這邊為了能夠好維護,儘管資料會重複,還是透過欄位將各階段的算法寫在標題列上。
要引用這些數據,可以參考下方數據。有一個 trick 值得分享的是底下公式中的 73051
這個數字,這個數字若用日期去顯示就是指 2100-01-01
。也就是若是引用的數據來源是空值時,則使用 2100-01-01
取代之。這樣的好處是未來在編寫計算張數的公式時,就只需要判定指定日期是否晚於時間戳,而不用再另外寫判斷檢查是否為空,讓 FILTER()
函式的判斷變得簡單很多。填入公式後如下圖,為了方便參照,也將每個欄位的公式顯示在截圖中。完成後一樣將這些公式套用在下方列中。
// Formula
=IF(B3="", , IF(時間戳欄位="", 73051, 時間戳欄位))
// Backlog / Options
=F3 // Created
=IF(B3="", , IF(G3="", 73051, G3)) // refined at
// Ready
=IF(B3="", , IF(G3="", 73051, G3)) // refined at
=IF(B3="", , IF(H3="", 73051, H3)) // selected at
// Selected
=IF(B3="", , IF(H3="", 73051, H3)) // selected at
=IF(B3="", , IF(I3="", 73051, I3)) // begin to dev
// Development
=IF(B3="", , IF(I3="", 73051, I3)) // begin to dev
=IF(B3="", , IF(J3="", 73051, J3)) // developed at
// Testing
=IF(B3="", , IF(J3="", 73051, J3)) // developed at
=IF(B3="", , IF(K3="", 73051, K3)) // tested at
// Reviewed
=IF(B3="", , IF(K3="", 73051, K3)) // tested at
=IF(C3="", , IF(L3="", 73051, L3)) // reviewed at
// Deployment
=IF(C3="", , IF(L3="", 73051, L3)) // reviewed at
=IF(D3="", , IF(M3="", 73051, M3)) // deployed at
// Done
=IF(E3="", , IF(M3="", 73051, M3)) // deployed at
套用後如下圖,為了讓取代空值的 2100-01-01
不要干擾資料的檢視,筆者將其套用條件化格式,當日期為 2100-01-01
時,文字以淺灰色顯示。
接下來要生出用來繪製 CFD 的張數資料,一樣先建立所需資料的標題列。
使用 FILTER()
函式按照上面講到的張數計算條件寫入,接著使用 COUNTA()
函式計算符合條件的張數即可。
// Options
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AF$3:AF <= $AW3, AG$3:AG > $AW3), )), )
// Ready
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AH$3:AH <= $AW3, AI$3:AI > $AW3), )), )
// Selected
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AJ$3:AJ <= $AW3, AK$3:AK > $AW3), )), )
// Development
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AL$3:AL <= $AW3, AM$3:AM > $AW3), )), )
// Testing
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AN$3:AN <= $AW3, AO$3:AO > $AW3), )), )
// Reviewed
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AP$3:AP <= $AW3, AQ$3:AQ > $AW3), )), )
// Deployment
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AR$3:AR <= $AW3, AS$3:AS > $AW3), )), )
// Done
=IF($AW3<>"", COUNTA(IFNA(FILTER($B$3:$B, AS$3:AS <> "", AS$3:AS <= $AW3), )), )
// All
=IF(AW3="", , SUM(AY3:BF3))
套用後結果如圖
接著選取資料,使用累積圖圖表繪製,就可以得到 CFD 了!這邊筆者有稍微調整顏色。另外因為是透過 ChatGPT 產生的資料,顯示出來的圖形特徵比較不是常見的特徵。
可以參照用另一組數據繪製出來的圖片。