こんにちは。プラットフォーム開発部 のthorです。
プラットフォーム開発部では、生産性を測定して継続的に向上させる事を目標としています。どのような指標で測定するかは各チームに任されていて、私のチームでは以前のchikaの記事で紹介されていた、Four keys指標を使って生産性を測定する事にしました。
そこで、今回はFour keys指標とはどのようなものか、私のチームではどのように測定する事になったかをご紹介したいと思います。
Four keys指標
Four keys指標(メトリクス)とは、Devops Reseach & Assessment(DORA)が確立したソフトウェア開発チームのパフォーマンスを示す以下の4つの指標のことです。この指標を使って、チームのパフォーマンスを確認する方法の説明はこちらのブログがあります。
- デプロイの頻度 - 組織による正常な本番環境へのリリースの頻度
- 変更のリードタイム - commit から本番環境稼働までの所要時間
- 変更障害率 - デプロイが原因で本番環境で障害が発生する割合(%)
- サービス復元時間 - 組織が本番環境での障害から回復するのにかかる時間
(『エリート DevOps チームであることを Four Keys プロジェクトで確認する』より)
パフォーマンスのレベルは、各指標について上記のように分類されるそうです。出来れば、エリートになりたいですね。
なぜFour keysが重要か
DORAは毎年「State of DevOps Report(DevOpsの現況に関するレポート)」を出しています。このレポートで報告している研究の調査・分析手法を紹介・解析する本が『LeanとDevOpsの科学[Accelerate] テクノロジーの戦略的活用が組織変革を加速する』として出版されています。
この本では「Four keys」でのハイパフォーマーは、以下の3つの「組織のパフォーマンス」のパフォーマンス結果でもローパフォーマーを上回る傾向にあり、両者の対比は一貫して2倍を超えていると報告(P. 31)しています。
- 収益性
- 市場占有率
- 生産性
つまり「組織のソフトウエアデリバリの能力は、組織に競争上の優位性をもたらす」ので重要だという事です。
なお本には、ソフトウエアデリバリの能力はどのようなプラクティスと関連があるかについての分析も述べられています。
指標の測定の自動化
指標の測定は自動化している組織もかなりあるようです。また、データ指標の測定用のオープンソースプロジェクトが、GitHubで公開されています。
(『four keysプロジェクトのGitHub』より)
このfour keysプロジェクトでは、GoogleのCloud RunやBigQueryを使って自動化された測定がされています。
指標の計算方法
指標の計算方法の解説は、英語ですがfour keysプロジェクトのGitHubで解説されています。BigQueryのコードもコメント付きで解説されています。本ブログでも大まかな内容を説明します。
デプロイ頻度
原文のデプロイ頻度の解説はこちらです。頻度の計算は平均値ではなく中央値を用いています。平均値は外れ値の影響を受けやすいので、中央値を使っているのでしょう。
下記のBigQueryの拡張のSQLを使って、まず最初に3ヶ月分のカレンダー・テーブルを生成します。
WITH last_three_months AS (SELECT TIMESTAMP(day) AS day FROM UNNEST( GENERATE_DATE_ARRAY( DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH), CURRENT_DATE(), INTERVAL 1 DAY)) AS day -- FROM the start of the data WHERE day > (SELECT date(min(time_created)) FROM four_keys.events_raw) )
上記のクエリで以下のようなテーブルが生成されます。
day |
---|
2022-12-11 |
2022-12-12 |
... |
2023-03-10 |
上記のテーブルを以下のテーブルと後述のSQLで外部結合して、日毎、週毎のデプロイ頻度の中央値を求めて、デプロイ頻度を分類しています。
フィールド名 | 型 | 説明 |
---|---|---|
deploy_id | 文字列 | デプロイのID |
changes | 文字列の配列 | デプロイに含まれる変更のID(バグトラッキングシステムのチケットID等) |
time_created | タイムスタンプ | デプロイの完了日時 |
SELECT CASE WHEN daily THEN "Daily" WHEN weekly THEN "Weekly" -- If at least one per month, then Monthly WHEN PERCENTILE_CONT(monthly_deploys, 0.5) OVER () >= 1 THEN "Monthly" -- 半分以上の月でデプロイしている ELSE "Yearly" END as deployment_frequency FROM ( SELECT -- If the median number of days per week is more than 3, then Daily PERCENTILE_CONT(days_deployed, 0.5) OVER() >= 3 AS daily, -- 週のデプロイ日数の中央値が3以上 -- If most weeks have a deployment, then Weekly PERCENTILE_CONT(week_deployed, 0.5) OVER() >= 1 AS weekly, -- 半分以上の週でデプロイしている -- Count the number of deployments per month. -- Cannot mix aggregate and analytic functions, so calculate the median in the outer select statement SUM(week_deployed) OVER(partition by TIMESTAMP_TRUNC(week, MONTH)) monthly_deploys FROM( SELECT TIMESTAMP_TRUNC(last_three_months.day, WEEK) as week, MAX(if(deployments.day is not null, 1, 0)) as week_deployed, -- その週にデプロイしたら1 COUNT(distinct deployments.day) as days_deployed -- その週にデプロイがあった日の数 FROM last_three_months LEFT JOIN( SELECT TIMESTAMP_TRUNC(time_created, DAY) AS day, deploy_id FROM four_keys.deployments) deployments ON deployments.day = last_three_months.day GROUP BY week) -- まず週ごとにまとめる ) LIMIT 1;
これによって
- 週に3日以上デプロイしていれば、Daily
- 3ヶ月の半分以上の週でデプロイをしていれば、Weelky
- 3ヶ月の半分の月でデプロイしていれば、Monthly
- 上記でなければ、Yearly
と判定されます。 また、上記のSQLで
PERCENTILE_CONT(days_deployed, 0.5)
が、週に何日デプロイしているかPERCENTILE_CONT(monthly_deploys, 0.5)
が、月に何回デプロイしているか
の値になります。
変更のリードタイム
原文でのリードタイム解説はこちらです。
まず、デプロイに関する、全ての変更(commit)のリードタイムを以下のように求めます。
SELECT d.deploy_id, TIMESTAMP_TRUNC(d.time_created, DAY) AS day, -- Time to Change TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) AS time_to_change_minute -- デプロイ時刻 - コミット時刻 FROM four_keys.deployments d, d.changes -- changesは配列型なので注意 LEFT JOIN four_keys.changes c ON changes = c.change_id;
上記のクエリから更に以下のように中央値を求めて、変更のリードタイムを算出します。
SELECT day, median_time_to_change FROM ( SELECT day, PERCENTILE_CONT( -- Ignore automated change (デプロイした時の副作用で起きるコミットは除外している) IF(time_to_change_minutes > 0, time_to_change_minutes, NULL), 0.5) -- Median OVER (partition by day) AS median_time_to_change FROM ( SELECT d.deploy_id, TIMESTAMP_TRUNC(d.time_created, DAY) AS day, -- Time to Change TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) AS time_to_change_minutes FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.changes c ON changes = c.change_id ) ) GROUP BY day, median_time_to_change;
リードタイムの分類は以下のように、過去3ヶ月分のデプロイに関する変更(commit)の中央値を計算しています。
SELECT CASE WHEN median_time_to_change < 24 * 60 then "One day" WHEN median_time_to_change < 168 * 60 then "One week" WHEN median_time_to_change < 730 * 60 then "One month" WHEN median_time_to_change < 730 * 6 * 60 then "Six months" ELSE "One year" END as lead_time_to_change FROM ( SELECT IFNULL(ANY_VALUE(med_time_to_change), 0) AS median_time_to_change FROM ( SELECT PERCENTILE_CONT( -- Ignore automated pushes IF(TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) > 0, TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE), NULL), 0.5) -- Median OVER () AS med_time_to_change, # Minutes FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.changes c ON changes = c.change_id WHERE d.time_created > TIMESTAMP(DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH)) -- Limit to 3 months ) )
このように、全て変更(コードのコミットやマージ)の中央値を算出して評価しています。
変更障害率
原文の変更障害率の解説はこちらです。
日毎に、その日のデプロイ失敗数 / デプロイ数
を計算しています。
SELECT TIMESTAMP_TRUNC(d.time_created, DAY) as day, SUM(IF(i.incident_id is NULL, 0, 1)) / COUNT(DISTINCT deploy_id) as change_fail_rate FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.changes c ON changes = c.change_id LEFT JOIN(SELECT incident_id, change, time_resolved FROM four_keys.incidents i, i.changes change) i ON i.change = changes GROUP BY day;
Four keys指標の分類は、以下のように日毎ではなく過去3ヶ月のデプロイから計算します。
SELECT CASE WHEN change_fail_rate <= .15 then "0-15%" WHEN change_fail_rate < .46 then "16-45%" ELSE "46-60%" end as change_fail_rate FROM (SELECT SUM(IF(i.incident_id is NULL, 0, 1)) / COUNT(DISTINCT deploy_id) as change_fail_rate FROM four_keys.deployments d, d.changes LEFT JOIN four_keys.changes c ON changes = c.change_id LEFT JOIN(SELECT incident_id, change, time_resolved FROM four_keys.incidents i, i.changes change) i ON i.change = changes -- Limit to 3 months WHERE d.time_created > TIMESTAMP(DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH)) ) LIMIT 1;
サービス復元時間
原文のサービス復元時間の解説はこちらです。
以下のように、日毎に障害発生時刻から解決のデプロイ時刻までの時間の中央値を求めています。
SELECT TIMESTAMP_TRUNC(time_created, DAY) as day, -- Median time to resolve PERCENTILE_CONT( TIMESTAMP_DIFF(time_resolved, time_created, HOUR), 0.5) -- 解決用デプロイ時刻 - 障害発生時刻 の中央値 OVER(PARTITION BY TIMESTAMP_TRUNC(time_created, DAY) ) as daily_med_time_to_restore, FROM four_keys.incidents;
分類方法は以下の通り、3ヶ月分の復元時間の中央値を計算しています。
SELECT CASE WHEN med_time_to_resolve < 24 then "One day" WHEN med_time_to_resolve < 168 then "One week" WHEN med_time_to_resolve < 730 then "One month" WHEN med_time_to_resolve < 730 * 6 then "Six months" ELSE "One year" END as med_time_to_resolve, FROM ( SELECT -- Median time to resolve PERCENTILE_CONT( TIMESTAMP_DIFF(time_resolved, time_created, HOUR), 0.5) OVER() as med_time_to_resolve, FROM four_keys.incidents -- Limit to 3 months WHERE time_created > TIMESTAMP(DATE_SUB(CURRENT_DATE(), INTERVAL 3 MONTH))) LIMIT 1;
どのようにFour keys指標を向上させるのか?
まだ指標の測定を開始したばかりですが、どのように取り組んで指標を向上させることができたかのご紹介をできるようになればと思います。
みらい翻訳では、一緒に開発を進めてくれるエンジニアを募集しています!
チームで協働しながら開発を進めたいと思っているエンジニアを探しています。
ご興味のある方は、ぜひ下記リンクよりご応募・お問い合わせをお待ちしております。