見出し画像

ブラックボックスになりがちな開発チームの内部状況を指標を用いて可視化する

自社ソフトウェアプロダクトを内製する組織であっても、開発チームがそれをどうやって作り上げているか、開発者ら以外にとってはブラックボックスであり、不可視です。それだけに、開発チームのパフォーマンスや内部状況の良し悪しは、各々の主観や興味によって、不統一な認識を持ってしまうことも多いでしょう。そしてそのような認識のばらつきは、開発する当人たちにとっても実は同じです。

しかし、例えブラックボックスであっても、自動車のダッシュボードのように様々な指標によってその内部が数値化され、可視化されていれば、チームのパフォーマンスに統一的な認識を持たせやすくなります。

本記事では、どのような指標を可視化すべきか、その代表的なものについて取り上げます。


リードタイム(開発、製造)

リードタイムは、開発項目ごとの作業期間を計測したもので、短いほど優れていることを示す指標です。計測対象となるプロセス全体を「開発」と「製造(デリバリ)」の2つのフェーズに分けて扱うことが、リードタイムを上手く扱うコツです。

「開発」フェーズの範囲は、設計や実装の開始から、その変更内容を、全ての変更の統合先となるコードセット(統合ブランチ)にマージするまでです。

「製造(デリバリ)」フェーズの範囲は、変更をマージしてから、それをデプロイするまでであり、以前の記事では「生産」と呼んでいました。何をもって「デプロイ」と言うのかはいくつか考えられますが、いずれにしても、いつでも本番稼働が可能な状態に置かれるか、あるいは実際に本番稼働を始めたタイミングを指します。成果物がアプリケーションではなく、ライブラリやSDK, フレームワークなどであれば、新しいバージョンを利用可能な状態にすることがデプロイとなります。

このように2つのフェーズに分ける理由は、両者のリードタイムのばらつき方に違いがあるからです。

開発フェーズのリードタイムは、開発項目ごとの計測値に大きなばらつきがあることが特徴です。開発項目の開発規模や、担当者の稼働状況・スキルなどに大きな影響を受けるからです。これは、このフェーズのプロセスに含まれるタスク(設計・実装、コードレビュー)が現状では多くを人手に頼らざるを得ないからだとも言えるでしょう。見積りによる予測は行うものの、その通りになるとも限らず、予測困難で不確実な指標だとも言えます。また、計測値は正規分布とならないため、平均値を代表値として扱えないことにも注意が必要です。

製造フェーズのリードタイムは、開発フェーズとは違い、プロセスが洗練するほどばらつきが小さく、一定になる傾向があります。それは、このフェーズのプロセスに含まれるタスク(ビルド、テスト、デプロイなど)の多くが自動化可能だからです。テストは人手に頼るべき領域が多少は残るものの、全体的な自動化が進むほど予測可能で不確実性の低い指標となるのが特徴です。

開発フェーズのリードタイムは、設計・実装やレビューといったタスクに要する時間を無理に短くしようとすると外部品質・内部品質の悪化を招く結果になりかねません。ここでのリードタイム短縮で注力すべき点の1つは、タスクとタスクの間の待ち時間をなくすことです。コード実装は完了したけれど、数日経ってもコードがレビューされないといったこともよくあります。この無駄をなくすことが、後述する「フロー効率」を高め、リードタイムを縮めることにつながるということです。

開発フェーズで注力すべきもう1点は、1つあたりの開発項目の規模を小さく分割することでしょう。そうすれば、後続の製造フェーズでのビルドやテストの手戻りコストを小さくでき、また、デプロイのコストやリスクを下げることができます。

一方の製造フェーズのリードタイムは、自動化をもって短縮することに努めます。

リードタイム(企画)

開発と製造の2つのフェーズに加え、企画フェーズのリードタイムを計測することもできます。このフェーズを「ファジーフロントエンド(FFE)」や「フェーズ0」と呼ぶこともあります。

バリューストリーム上で開発フェーズより前に位置するこのフェーズでは、個々のアイデアに関する企画の開始から企画の終了、あるいは開発の開始までを計測します。プロダクトバックログにアイテムを追加してから、開発に着手するまでの期間を計測する方法が簡単ですが、組織によっては、それより前のタイミングを開始点とする方が有用な情報になることもあり得ます。

企画フェーズのリードタイムは、開発フェーズと同様、計測値に大きなばらつきがあることが特徴であり、また、必ずしも短いことが良いことであるとも限らない点に注意が必要です。適切な長さがはっきりしないため、計測したところで持て余すだけになるかもしれません。それを踏まえた上で、計測するかどうかを判断すべき指標です。

むしろ、企画フェーズのリードタイム短縮を試みるより、アイデアが実際に価値を生み出したのか、A/Bテストをはじめとする対象テストで検証し、その上で企画や開発に費やした時間やコストが適正だったか振り返ってみた方が良さそうにも思えます。

フロー効率

フロー効率は、リードタイムに含まれる待ち時間を明らかにする指標で、主に、リードタイムの改善を目的とした分析に利用します。その観点から、リードタイムと同様に、フロー効率も、開発と製造の2つのフェーズに分けると扱いやすくなります。

例えば、ある開発項目に対する開発フェーズのリードタイムが2.5日だったとします。その内訳が、設計および実装に0.5日、コードレビュー待ちに1.5日、実際のコードレビューに0.5日だったとすると、タスクに要した期間はたった1.0日で、リードタイムの40%しか占めておらず、残りの60%が待ち時間であったことが分かります。この40%という数字が、フロー効率です。値が100%に近づくほど優れていることを示します。

フロー効率が悪いとリードタイムが長くなり、リリースするタイミングがそれだけ遅くなります。ビジネスにとって、それは機会費用や機会損失となります。

フロー効率については、大きなコストをかけて計測しなくても、様々な施策を通して改善することも可能です。その手法については、前回の記事『エンジニアの稼働率を上げれば上げるほど機能リリースが遅くなっていく』で詳しく解説していますので、そちらを参照ください。

フロー効率改善には、次節で解説するように、デプロイの頻度を高めることを通してバッチサイズを削減することが有効です。

デプロイの頻度

デプロイの頻度は、任意の期間あたりのデプロイ回数を計測する指標で、その計測値が大きいほど良いとされます。

そう聞くと、「1回のデプロイに含める開発項目の数を減らしたり、開発規模を小さくすれば、指標が改善してしまうじゃないか」と、問題点を指摘する人もいます。つまり、10個の開発項目を4週間かけて開発して1回でデプロイするところを、はじめの2週間で5個を開発・デプロイし、次の2週間で残りの5個を開発・デプロイすれば、デプロイ頻度が倍になるといった話です。どちらの場合も4週間で10個の開発項目をデプロイしているので、パフォーマンスに優劣はない、という主張です。

でも、それで良いのです。この指標は、いわゆる「バッチサイズ」を計測するための代替指標で、その削減状況をモニタリングするものだからです。

バッチサイズとは、開発からデプロイまでの1度のサイクルに含める開発項目の数のことを指します。もとは製造業の用語ですが、ソフトウェア開発は製造業とは違い、1回のサイクルに含まれる開発項目それぞれの開発規模に大きなばらつきがあります。そのため、バッチサイズという言葉は、開発項目の数ではなく、開発規模の総計を指すこともあります。

バッチサイズを小さくすることで得られる効果は様々です。

その1つはリスクとストレスの低減です。大きなバッチサイズでのデプロイは、ビッグバンリリースとも呼ばれます。ビッグバンリリースは、デプロイ時や本番稼働開始後に障害を起こす可能性が非常に高くなり、リスクを伴います。チームのストレスも、そのリスクに比例するように高くなります。バッチサイズを小さくすれば、そういったリスクやストレスも小さくなります。

また、バッチサイズが大きいほど、開発項目単位でのフロー効率が悪化してリードタイムが長くなります。早くに開発を終えた開発項目も、その他の全ての開発項目の開発が完了するまでリリースすることができず、待ち時間が長くなるからです。

さらに、バッチサイズを小さくすれば、仮説検証のサイズも小さくなります。いくら素晴らしいアイデアだと思えても、それをリリースしてユーザーの反応を見るまでは、単なる仮説でしかありません。大規模開発を経てリリースした結果、ユーザーから不評を買ったなんてことになったら、そこにかけたコストも、手直しするコストも大きくなります。だったら、もう少し小分けでリリースし、ユーザーフィードバックを得ながら方向性を調整していく方が無駄が小さくなります。また、バッチサイズが小さくなり、デプロイ頻度が高まることで、こういったフィードバックのサイクル自体も高速化されます。

時間をかけて綿密に分析すれば、アイデアの成功確率が高まると考えるかもしれません。しかし、はてなブログにも書いたように、マイクロソフトの実験によると、「アイデアの1/3は価値がある」が、「残りの2/3は価値がないか、逆に価値を損なわせる」という結果が出ています。アイデアの良し悪しに対する人間の感覚は、それほどまでに信用できないものだということでしょう。むしろ、時間をかけるほど、あれもこれもと機能要件が洗い出され、スコープは膨らんでいき、リスクは高まるばかりです。このようなスコープクリープに陥らないためにも、デプロイ頻度を指標として導入することをおすすめします。

変更失敗率

リードタイムやデプロイの頻度は、開発スピードに関する指標です。スピードだけをやみくもに追い求めてしまうと、品質を軽視し始め、障害を起こしかねません。デプロイする度に障害を起こしていてはユーザーからの信頼も失います。また、こうした障害多発による度重なる修正リリースが、数十分から数時間程度の短いリードタイムの実績値を増やしたり、デプロイの頻度を押し上げてしまうこともあり得ます。そうすると、リードタイムやデプロイの頻度といった指標が、見かけ上は改善し、実体を誤認させるおそれがあります。

そのような事態に陥っていないかをモニタリングする指標が「変更失敗率」です。変更失敗率は、デプロイする度にどの程度の割合で障害が発生したかを示し、値が小さいほど優れている指標です。

週次や月次など、周期的に変更失敗率を集計すると、悩ましいことが1つあります。障害をどの時点の集計にカウントするかです。これには4通り考えられます。1つめは、その障害の原因となる変更を本番環境にデプロイしたタイミングです。2つめは、障害の発生開始日です。3つめは、障害を検知した日です。そして4つめは、障害から復旧した日です。

私のおすすめは検知日ベースでの計測です。本質的には、デプロイ日ベースが正しい選択だと思いますが、集計値を過去にさかのぼって修正するケースが発生する点がイマイチなのです。

例えば、月次で集計している中、当月6月に障害を検知し、その原因となった変更のデプロイが4月に行われていたとします。これを4月の変更失敗率に反映すると、6月になってから4月の集計値を変更することになります。こういった状況はしばしば起こり得ますが、その都度、過去の集計値を変更していては、指標の信頼性が低下してしまいます。これは、2つめとして挙げた障害発生開始日ベースのカウントでも同様です。

一方で、検知日や復旧日ベースでカウントすれば、過去の集計値が変わることはありません。変更失敗率の分子と分母の関連が弱くなりますが、そこを割り切って集計した方が利便性も良く、かつ集計も簡単になります。1点だけ問題があるとすれば、デプロイが1回もない期間に障害が発生すると、分母が0になってしまい、計算できないことでしょう。この問題は、そうならない程度には十分に長い期間を集計対象とすることで、問題の発生確率を低減させられます。

変更失敗率が高い状況は、開発者らがそれだけ障害対応に時間を割いているということです。その対応に開発時間が奪われるため、仕掛中の開発項目のフロー効率が落ち、リードタイムが悪化します。また、障害が頻発するほど開発者の注意力が削がれることも、リードタイム悪化の原因となるでしょう。このように、品質に注力しなかったばかりに後から大きなコスト(フェイラーデマンド、失敗要求)を支払うはめに陥るような事態は避けたいところです。

Four Key Metrics

ビジネスでは収益性や市場占有率といった指標を用いて成果を計測しますが、DORAの調査によると、それらの指標が示す組織パフォーマンスに対し、ソフトウェアデリバリのパフォーマンスが影響を及ぼすという結果が出ています。そして、そのソフトウェアデリバリのパフォーマンスを計測する指標が、「Four Key Metrics(FKM)」と呼ばれるものです。

FKMは、「デプロイの頻度」「変更のリードタイム」「変更失敗率」「サービス復旧時間」の4つの指標を指しています。デプロイの頻度と変更失敗率は既に述べた通りですので、変更のリードタイムとサービス復旧時間について少し深掘りします。

まずは変更のリードタイムです。この指標については、開始点が何であるかの定義が曖昧なところがありますが、計測範囲はおそらく先述した製造フェーズのリードタイムと一致します。その理由は、DORAによる調査に関わった著者らの書籍『LeanとDevOpsの科学』に書かれた次の一文です。

本調査研究では「製品デリバリのリードタイム」を「コードのコミットから本番稼働までの所要時間」として回答を求め、(以下略)

ニコール・フォースグレン, ジェズ・ハンブル, ジーン・キム著
『LeanとDevOpsの科学』

ここで言う「製品デリバリのリードタイム」が変更のリードタイムのことですが、その範囲は「ビルド、テスト、デプロイ」であることが明記され、「製品の設計と開発」とは分離されています。前者は先述した「製造(デリバリ)」にあたり、後者は「企画」と「開発」にあたります。したがって、「変更のリードタイム」は、製造フェーズのリードタイムと一致します。

サービス復旧時間は、「MTTR(Mean Time To Recovery, 平均復旧時間)」とも呼ばれます。本番環境で障害を検知してから、復旧するまでに要する時間を指します。この指標は、変更のリードタイムで代替できるところもあり、私自身としては計測しなくて良いだろうと考えています。もちろん、変更のリードタイムだけでは、障害を検知してから復旧方法を見つけ出すまでの時間は計測できません。そこに課題があるならば計測対象となります。

FKMを計測する利点は、それらの良し悪しを決める基準が、DORAの調査によって明らかにされている点です。それは、年次のState of DevOps Reportとして公開されています。例えば、2021年のレポートを見てみると、デプロイの頻度であれば、チームの計測値が「オンデマンド、あるいは日に複数回」に相当するなら「エリートパフォーマー」と呼ばれるクラスタに相当し、半年に1回を下回るようであれば「ローパフォーマー」に相当することが分かります。

ベロシティ

チームがスクラム開発を始めとするアジャイル開発手法を導入しているのなら、ベロシティの変化を観察することも有効です。ベロシティは、チームの進行速度とも呼ばれ、1回のイテレーション(スプリント)で完了させた開発項目の見積り合計値のことです。

イテレーションごとのベロシティを計測し続けていると、下降傾向を示すこともあります。そういった時は、チームが扱うソフトウェアやチーム自身に何か問題が生じている可能性があります。その兆候を見つけたらすぐに原因を分析し、問題解決に努めます。

開発者のエンゲージメントや幸福度

高い従業員エンゲージメントは、顧客評価、生産性、収益性、品質を高めます。したがって、開発者らのエンゲージメントは優れたプロダクトを作り出す原動力であり、その定点観測を続けることは有用でしょう。

エンゲージメントの計測は、おそらく有料のサービスを利用することになるため、その予算確保が導入の障壁になるかもしれません。それならば、アンケートを作成して自組織やチーム、プロダクトに対するeNPSスコアを定期的に計測してみる方法もあります。

もっと簡単に、チームでファイブフィンガーを導入して、振り返りごとに、現状を1から5のスケールで評価してもらうのも良いでしょう。ファイブフィンガーでの評価を振り返りの一環として実施できれば、そこで得たスコアを有効な指標として活用できるはずです。

その1つの成功例が、スクラムの提唱者であるジェフ・サザーランドが書籍『スクラム』で紹介した「幸福度の計測」という手法です。厳密にはファイブフィンガーではありませんが、チームメンバー全員が5段階で評価するという点が似ています。イテレーションごとの振り返り時に、それぞれの幸福度について5段階で答え、何を変えれば次のイテレーションでもっと幸せだと感じられるのかをチームで話し合うというものです。

ジェフ・サザーランドによれば、これを続けて幸福度を上げていくことで、ベロシティが3倍になったということです。また、幸福度が下がると、しばらくしてベロシティも下がる傾向が見られたそうです(下図は書籍『スクラム』内の図をもとに作成)。つまり、幸福度を定点観測すれば、ベロシティだけを定点観測するよりも早いタイミングで問題を検知することが期待できるということです。

このような幸福度やファイブフィンガーでの計測は、従業員エンゲージメントやeNPSと違い、匿名によるアンケート形式での計測ではなく、チームメンバーが揃った場で互いの評価を見せ合うものである点に注意が必要です。「低い評価を付けたら、周囲から非難の目で見られるのでは……」といった不安感を抱いてしまい、それが現状を反映しない評価につながる可能性があるからです。上手くいくかどうかは、チーム内に築かれた心理的安全性が鍵を握ります。

テストカバレッジ

ソフトウェア業界には、「レガシーコード」という言葉があります。理解できず、変更が難しいソフトウェアコードを指す俗語として用いられます。自社のチームが扱うソフトウェアプロダクトのコードがそのような状態にあるなら、開発フェーズのリードタイムを悪化させ、デプロイの頻度も低く、変更失敗率も悪い状態になるでしょう。

書籍『レガシーコード改善ガイド』の著者であるマイケル・フェザーズは、レガシーコードを単に「テストのないコード」と定義しています。ここで言うテストとは、もちろん自動テストのことです。

テストのないコードは悪いコードである。どれだけうまく書かれているかは関係ない。(中略)テストがあれば、検証しながらコードの動きを素早く変更することができる。テストがなければ、コードが良くなっているのか悪くなっているのかが本当にはわからない。

マイケル・C・フェザーズ著『レガシーコード改善ガイド』


コードの変更は、常にデグレのリスクを抱えています。コード品質を改善しようとするリファクタリングにしても、機能追加や機能改善にしても、あるいはバグフィックスであっても、その危険性が常についてまわります。自動テストがあれば、それを実行するだけで、変更したコードが仕様を満たすことを検証することができます。

わざわざコストをかけて自動テストを作成しなくても、手動によるテストで品質は担保できると思うかもしれません。しかし、デプロイの頻度が上がれば、それに比例して手動テストの実施コストも上がります。また、手動テストは主に製造フェーズで実行されることに対し、自動テストは開発フェーズ中でも大部分の実行が可能です。早い段階で欠陥を見つけられれば、それだけその修正コストや手戻りコストを減らすことができます。

自動テストと言っても、その粒度によって3つに大別できます。ユニットテストとインテグレーションテスト、そしてE2Eテストです。テストケース数という観点で、これらはピラミッドで描かれることがあります。

ピラミッドの下にいくほどテストケース数を多く、上に行くほど少ない状態がバランスとして良いということを表現しています。また、自動テストの実行に要する時間は、ピラミッドの下の方が短く、上の方が長くなります。したがって、E2Eテストに頼りすぎたテスト自動化は、時間がかかりすぎ、リードタイムやデプロイの頻度にも悪影響をおよぼす可能性があります。この点を理解しつつ、テストの自動化を進めることになるでしょう。

前置きが長くなりましたが、ここで登場する指標がテストカバレッジです。ユニットレベルのテストコードがプロダクトのコードをどれだけカバーできているかをパーセントで表すもので、ツールを使って簡単に計測することができます。

カバレッジを高めることは重要なのですが、100%を目指すのは、その効果に対してコストが見合いません。80%から90%ぐらいが妥当な範囲に感じますが、どの程度のカバレッジが適切であるかは、チームで判断することになるでしょう。

コード品質

テストコードを書く目的は、究極的には、「ソフトウェアプロダクトの持続可能性を高めることである」と考えています。テストコードを書くことで、コード品質が高まります。コード品質が高ければ、コードの理解と変更が容易になります。コードの変更が容易である限り、ソフトウェアプロダクトに新たな価値を追加することが可能です。これが、「持続可能性を高める」という意味です。逆に、コードの変更が困難であれば、価値の追加も難しくなり、ソフトウェアプロダクトの持続可能性が失われます。

ここで1つ、説明が不足している点がありました。「テストコードを書くことで、コード品質が高まる」という点です。欠陥が少なくなることは理解しやすいと思いますが、なぜコード品質が高まるのでしょうか。それは、劣悪な設計に基づくコードに対しては、十分なテストが書けないからです。既存のコードに対してテストを書くためには、コード設計を見直すことが要求され、それがコード品質の改善につながるのです。

また、新規のコードを書く時であれば、先にテストを書くことを前提に置きます。先にテストコードがあることで、その仕様を満たすコードを書くだけでなく、コード品質を高めるためのリファクタリングを即座に実施できるからです。これをプログラム開発手法としたものが「TDD(テスト駆動開発)」です。

しかし、残念ながら、テストカバレッジが高いことが、必ずしもコード品質が高い状態を表すとは限りません。なにごとにも抜け穴はあります。単にテストカバレッジが高いだけで、酷いコード品質となっていることも考えられます。

そこで、コード品質が高まっているかを計測するために、テストカバレッジとあわせて、コード品質を評価する指標も導入したいところです。主な指標としては、コードの複雑性や重複度、コードサイズ(コンパクトな方が良い)などがあります。

こういった指標は、ツールを使って計測可能ですので導入も難しくありません(採用しているプログラミング言語によっては、ツールが非対応のケースや、有償のケースもあります)。ただし、ツールを使った機械的な計測を信頼し過ぎることはできません。良い設計かどうかを完全に評価することができないからです。その前提を理解した上であれば、ツール導入には大きな価値があるでしょう。

信頼性

ソフトウェアシステムの「信頼性」といえば、直感的に、「可用性」を思い浮かべるのではないでしょうか。99.9%とか、99.99%とか言うあれです。可用性は、ユーザーがソフトウェアシステムを利用できる時間の比率を表した指標です。99.9%や99.99%という数値は、可用性をその値以上に維持することを約束する目的で定義されたしきい値です。

この「可用性」のような、サービスレベルを計測する指標を「SLI(Service Level Indicator)」と呼びます。SLIには他にも、リクエストのレイテンシやスループット、エラー率など、ユーザーエクスペリエンスに強く影響する指標が用いられます。そして、SLIの目標値を「SLO(Service Level Objective)」と呼びます。例えば可用性で言う99.9%といった値がそれにあたります。

SLIとSLOを定義する背景には、サービスレベルに対する期待値を関係者の間で一致させることがあります。それが、ソフトウェアシステムに対する「正常な状態」の定義となります。チーム(開発チーム、あるいは運用チーム)は、SLIの計測値がSLOを下回って信頼を失わないよう、時には機能追加を止めてでも信頼性向上に努めることもあります。

また、SLIを選定して計測してみると、そもそも期待値とするSLOを大きく下回っていることもあり得ます。そういったケースでは、期待値に到達させるための計画を立て、改善に取り組むことになります。

ところで、先のState of DevOps Reportでは、指標として前述のFKMの4つを扱っていましたが、2021年から5つめの指標として信頼性が追加されています。開発だけでなく、運用のパフォーマンスも重視するようになったということです。

指標の改善が組織的な能力を高める

ソフトウェア開発という仕事を進める中で、「生産性を高める」という言葉を私はあまり使いません。この言葉は、とても曖昧だからです。何をもって「生産性が高い」と判断できるのか、その基準がそもそも存在せず、そのため、改善に取り組むことも、その効果を観測することもできません。また、この言葉は、チーム外の人からチームへの指示や期待として発せられることも多く、どこか他人事のようにも感じます。

しかし、本記事で挙げたような具体的な指標を計測することで、ソフトウェア開発の内部状況は高い可視性を持つようになり、開発者らだけでなく、組織の関係者皆の認識が揃い始めます。そうすれば、「生産性を高める」ための活動はもはや開発者らだけの課題ではなく、組織全体の課題に位置づけられ、具体性を持った取り組みにかわります。

このようにして鍛え上げられた「組織的な能力」が、ソフトウェアプロダクトのユーザー価値やビジネス価値といった「市場価値」を、持続的かつ効率的に高める原動力となるのでしょう。

この記事が気に入ったらサポートをしてみませんか?