RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

ノバセルで Four Keys の具体的な定義を決めた話

はじめに

こんにちは、ノバセルでサーバーサイドエンジニアをしている者です。

ノバセルでは 2022 年から Four Keys の計測を開始しました。

参考: DevOps Days Tokyo 2023 で Four Keys についての発表
4keys 導入におけるリアル

この記事では Four Keys をシステムから計測するためにその定義をどのように具体化したかを紹介します。

Four Keys とは

Four Keys とは DevOps Research and Assessment(DORA) が提唱する組織のソフトウェア開発の生産性を示す指標で、下記4つの指標から構成されます。

※ DORA とは DevOps の導入状況や効果などを調査・研究する団体

  • デプロイの頻度 - 組織による正常な本番環境へのリリースの頻度
  • 変更のリードタイム - commit から本番環境稼働までの所要時間
  • 変更障害率 - デプロイが原因で本番環境で障害が発生する割合(%)
  • サービス復元時間 - 組織が本番環境での障害から回復するのにかかる時間

引用: エリート DevOps チームであることを Four Keys プロジェクトで確認する

これらの指標はソフトウェア開発の「速度」と「安定性」を計測しており、生産性が高い組織はその2つをトレードオフの関係性にせずに、どちらも高い数値を出しているとの研究結果があります。

ノバセルでは技術的負債やビッグバンリリース、運用負荷など開発生産性を低下させている問題がいくつかありそれらを改善しようとしていました。

しかし、生産性を測定・可視化する仕組みがなかったため、改善活動によってそれらの問題が解消し生産性が向上したのかを確かめる方法がないという問題が生じていました。

そこで、現状の生産性と改善活動の結果を知り、継続的に生産性を改善できる環境を作るために、ソフトウェア開発の生産性の指標のデファクトスタンダードになっている Four Keys を計測することにしました。

この記事で紹介すること

Four Keys はもともとは人が回答するアンケート調査の設問として作られています。

例えばデプロイ頻度は下記の設問となっています。

  • 質問
    • 主要なサービスやアプリケーションにおけるコードのデプロイ頻度
  • 回答
    • オンデマンド(1日複数回)
    • 1時間に1回から1日1回
    • 1日1回から週1回
    • 週1回から月1回
    • 月1回から6ヶ月に1回
    • 6ヶ月に1回よりも少ない

引用: LeanとDevOpsの科学(P24)

そのため、アンケートによる調査ではなく、稼働するシステムの状態をもとに指標を算出するには、システマチックに数値を計測するために指標の定義を具体化しなければなりません。

システマチックに指標を具体化し定義する過程で、いくつかの選択肢が考えられ定義決めに迷う箇所が出てきます。

同じような定義決めの問題に直面するかもしれないこれから Four Keys を導入しようと考えている組織のため、ノバセルの生産性改善活動を記録として残しておくために

この記事では、指標の具体的な定義を決める際に、ノバセルのエンジニア組織の開発プロセスやカルチャーに合わせて、どのように Four Kyes を具体的なシステムの定義に落とし込んでいったのかを紹介します。

Four Keys の定義決め

Four Keys の各指標におけるノバセルの定義とその定義に決めた背景を紹介します。

デプロイ頻度

DORA による定義とノバセルの定義は下記になります。

  • DORA 定義
    • 組織による正常な本番環境へのリリースの頻度
  • ノバセル定義
    • GitHub Pull Request がデフォルトブランチにマージされた日数をチームのスプリントごとに計測

ノバセルではデプロイを GitHub Pull Request のマージとして計測することにしました。

また頻度に関してはデプロイが行われた日をカウントすることにしました。

これは1スプリント1週間で開発をしている場合は頻度の値は0~7になるということです。

この定義決めにおいては下記の論点がありました。

リリースの定義

デプロイの頻度を計測するためには、デプロイの定義を決め、そのデプロイが行われた日時を取得する必要があります。

そこで、デプロイシステムからデプロイ日時を取得しようとしましたが、ノバセルは Jenkins、AWS Code Deploy、GitHub Actions など複数のデプロイシステムでリリースを行なっています。

そのため、それぞれのデプロイシステムに対してデプロイを計測するとそれを計測するための開発工数が大きくなるという問題が発生しました。

その問題を解決するために、それぞれ個別のデプロイシステムからデプロイ情報を取得するのではなく、GitHub の Pull Request のマージをデプロイとみなすことにしました。そして、すべてのデプロイを GitHub から取得することで少ない開発工数でデプロイを計測することにしました。

デプロイ日時を正確に取得することができるためデプロイシステムを直接計測することが理想でしたが、どのデプロイシステムも

  • デフォルトブランチ(main や master)への Pull Request のマージ後にデプロイが実行される
  • Pull Request のマージからデプロイ開始までの時間が短い
  • デプロイ自体にかかる時間が短い

ことから、 「Pull Request がマージされた日時」≒「デプロイが完了する日時」になるため、Pull Request のマージをデプロイとして計測することができました。

リバート

Pull Request をデプロイとして測定することになったことで、変更内容をそのままロールバックするリバート Pull Request を正常なリリースとしてカウントするべきかについて検討をしました。

リバートを正常なリリースとしてカウントすると、障害を起こすほどデプロイが増加しデプロイ頻度が上がってしまうのではないかと危惧したからです。

しかし検討した結果、

  • ロールバックをできるということ自体、そのシステムや機能が疎結合に作られていると評価できること
  • リバートリリースにより一時的にデプロイ数が増加したとしても、障害を頻繁に起こす開発組織は開発フローやシステム構成が悪いため開発が安定せず、長期的に見ればデプロイ数は多くはならないこと
  • リリースの安定性を測定する 4keys の変更障害率、サービス復元時間の2つの指標で障害発生率、障害の度合いが高い場合は検知できること

ことから、リバートリリースは正常なリリースとしてみなし、デプロイ頻度に含めることにしました。

SaaS やノーコードツール

SaaSやノーコードツールの設定変更をデプロイとしてカウントするべきかどうかを迷いました。

デプロイに対して自分たちが作っているシステムのプログラムのソースコード修正をし、それを反映する行為というイメージを持っていたからです。

その判断を行うために、利用している SaaS やノーコードツールを自分たちでスクラッチ開発していると仮定したときにデプロイとしてカウントするかどうかを考えてみました。 下記はノバセルで利用しているツールの一例です。

  • Auth0(IDaaS)
  • Sentry(エラー監視システム)
  • trocco(ETLツール)
  • Redash(ダッシュボードツール)

このように考えてみると、認証基盤、エラー監視、ETL、データダッシュボードのシステムを自分たちで開発をした場合、当然それらのデプロイはデプロイ頻度に含めることになると考えました。

事業で利用しているシステムならば、スクラッチのシステムか、SaaS やノーコードツールなのかを区別をすることなく、そのシステムに対する変更の反映はデプロイとしてみなすべきだからです。

そのため、私たちのデプロイの定義である GitHub Pull Request で計測できるもの、つまりコード管理ができる SaaS やノーコードツールはそのコードの反映をデプロイとしてカウントすることにしました。

頻度の定義

頻度は様々な定義が考えられるのでどのような定義にするのか悩みました。

参考にするために DORA のデプロイ頻度のアンケート調査の回答項目を見ましたが

  • オンデマンド(1日複数回)
  • 1時間に1回から1日1回
  • 1日1回から週1回
  • 週1回から月1回
  • 月1回から6ヶ月に1回
  • 6ヶ月に1回よりも少ない

であり、システムで頻度を出すには文章が曖昧で参考にはできませんでした。

そこで、GCP の 4keys プロジェクトのデプロイ頻度の定義を見てみると「1 週間のうち正常なデプロイが 1 回以上行われた日数の中央値」を定義としていました。

この定義ならば特定の1日に多くのリリースが偏って行われても頻度は向上せず、毎日リリースをしなければ数値が上がらないので、頻度を適切に計測できると考えました。

私たちは 4keys に限らず自分たちの生産性を可視化するという試みをほとんどできておらず現状の状態をまず可視化したかったため、頻度の定義は GCP のプロジェクトよりシンプルにし、チームごとにそのスプリント期間のうちデプロイが行われた日数を頻度の定義としました。

変更のリードタイム

DORA による定義とノバセルの定義は下記になります。

  • DORA 定義
    • commit から本番環境稼働までの所要時間
  • ノバセル定義
    • チームのスプリント内に完了した実装チケットの着手から完了までの所要時間の平均

この定義決めにおいては下記の論点がありました。

commit の定義

DORA による定義の commit を具体的に定義する必要がありました

LeanとDevOpsの科学(P21,P22)では、リードタイムの範囲に要件調整や設計を入れるとどの箇所を開発開始の地点として決めるのかが難しいので、リードタイムの範囲は「実装からデリバリ完了までの時間」とすると記載があります。

そのため、commit は実装の開始を指しているようです。

では実装の開始をどのように計測すればよいでしょうか。

まず思いつくのが開発ブランチに対する最初の Git commit です。

しかし、純粋に開発ブランチの最初の commit を実装開始とみなすと細かな仕様調整や実装方針を考える時間などの時間を計測できず、実装の作業時間を正確に計測できません。

Git にソースコードを commit する前に実装は開始していると言えます。

これを防ぐためには、開発作業を開始したときに空 commit をするという方法が考えられます。

しかしノバセルには開発作業開始時に空 commit をする文化がなく、計測のためだけにエンジニア全員に空 commit を行ってもらうようにするのは難しかったですし、小さな作業であっても計測のためだけに普段の開発作業において手順を増やしたくありませんでした。

そこで、ノバセルでは開発チケットを ClickUp で管理しており、そのチケットのステータスが着手になったときを実装開始とすることにしました。

開発チケットには要件定義や全体設計など実装を行わないチケットもありますが、実装が生じるチケットに関しては ClickUp チケットの単位で Git ブランチを作成するという文化があったため、対応する GitHub の Pull Request がある開発チケットを実装チケットとして判定することができました。

ただ、小さな開発案件や大きな開発案件を小さく分割した案件だと、実装チケットのタスクの範囲に仕様調整や設計も含まれることもあり、LeanとDevOpsの科学(P21,P22)の要件定義や設計は含まず実装の開始地点を計測開始地点とするという定義と異なる場合が出てきます。

しかし、リードタイムを計測する目的はソフトウェアを提供する速度を速めることなので、書籍に書いてある定義とは少しずれることにはなりますが、仕様調整や設計が測定範囲に含まれた方が測定幅が広くなり速度を改善できる箇所が多くなるため、それらを含むことにしました。

計測終了地点の定義

DORA による定義は「本番環境稼働までの所要時間」のため、リードタイムの計測終了地点はシステムデプロイの完了時とするのが一般的です。

しかし、デプロイ後の動作確認やステークホルダーへの連絡など、システムのデプロイが終わったあとにするべき作業の時間も測定し、その作業時間も改善していきたいため実装チケットのステータスが完了になったときを計測終了地点にしました。

ただ 4keys 計測システムにはシステムデプロイの完了時間も記録されているため、チケット完了時だけではなくデプロイ完了時の場合のリードタイムも算出できるようにしておきました。

変更障害率

DORA による定義とノバセルの定義は下記になります。

  • DORA 定義
    • デプロイが原因で本番環境で障害が発生する割合
  • ノバセル定義
    • 直近 N ヶ月の間にデフォルトブランチにマージされた PR のうち、障害を直接引き起こした PR のチームごとの割合

変更障害率の計算式は 「障害を引き起こしたデプロイ数」 / 「全デプロイ数」 です。

ノバセルでは前述したように Pull Request をデプロイとしているので、「障害を引き起こした Pull Request 数」 / 「Pull Request 数」 で障害率を計算することにしました。

障害が発生したら notion に障害チケットを作成するという決まりがすでにあったため、その障害チケットに障害を引き起こした Pull Request を記載してもらうことで、どの Pull Request が障害を起こしたのかをシステムで判定できるようにしました。

この定義決めにおいては下記の論点がありました。

デプロイによって起こった障害の判断基準

例えばプロダクトに表示される情報が間違っているなど、実装が間違っていたことによる障害は明確にその実装のソースコードのデプロイによって生じた障害です。

しかし、運用システムの機能を操作ミスが起こりやすいように作ってしまい機能の使い勝手が悪いせいで誤った操作をしていまいプロダクトに障害が起きた、実装当時の想定以上のトラフィックでサーバーがダウンしたなど該当部分の実装が原因になったと100%言えないような障害もあります。

そのような障害を変更障害率に入れるかどうかを悩みましたが、間接的に障害を引き起こしたデプロイは障害率に入れないことにしました。 4keys において変更障害率はソフトウェアのリリースの安定性を測る指標のため、リリースによって直接的に障害を引き起こしたデプロイのみを計測したかったためです。

サービス復元時間

DORA による定義とノバセルの定義は下記になります。

  • DORA 定義
    • 組織が本番環境での障害から回復するのにかかる時間
  • ノバセル定義
    • 直近 N ヶ月の間に発生した障害の「障害発生日時」から「障害復旧日時」までの平均時間

ノバセルでは notion に作成される障害チケットの情報をもとにサービス復元時間を計算しています。

この定義決めにおいては下記の論点がありました。

計測開始地点をどこにするか

サービス復元時間という言葉を聞いて、計測の開始地点を障害発生時、障害が発生したことを検知して復旧を開始した時点、どちらにするか悩みました。

しかし、復旧にかかる時間だけではなく障害を検知するまでの時間も改善したいこと、LeanとDevOpsの科学(P24)にはサービス復元時間は修正時間を意味する Mean Time to Repair(修復時間)ではなく発生から修正完了までを意味する Mean Time to Restore (復旧時間) との記載があることから、計測の開始地点を障害発生時にしました。

計測終了地点をどこにするか

計測終了地点を障害が復旧した時点、障害に対する再発防止対応が完了した時点のどちらにするか悩みました。

暫定対応までの時間ではなく再発防止対応までの時間を計測することで、根本対応にかかる時間を改善したいとも考えましたが、もともとの定義が Mean Time to Restore であること、障害の種類によっては再発防止対応が完了するまで時間がかかりサービス復元時間のデータが集まりにくくなることから、障害が復旧した時点を計測終了地点としました。

おわりに

このように Four Keys の定義を決める際にはいくつか選択に悩む部分があります。

定義された生産性の指標が高くなるように開発組織は自分たちの行動を最適化していくため、自分たちの開発組織の課題やカルチャーに合わせて組織で認識を擦り合わせながら定義を決めることが大切と考えています。

この記事が参考になれば幸いです。