♻️

デプロイ頻度を向上させることへの誤解

2022/10/31に公開約6,500字

デプロイ頻度(deployment frequency)とは

組織のパフォーマンス(収益性・市場占有率・生産性)と、デリバリのパフォーマンスとは高い相関があります。
デリバリのパフォーマンスとしては、Four Keysと呼ばれる4つの尺度が有名です。

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

そのうちの1つであるデプロイ頻度(deployment frequency)とは、文字通り本番環境に変更が反映された頻度のことを指します。
2022年の State of DevOps Report によると、高パフォーマーと低パフォーマーには雲泥の差があることが記されています。

  • high performerのデプロイ頻度はおよそ1日4回、1年間で1460回。
  • low performerは1ヶ月に1回〜6ヶ月に1回の頻度でしかデプロイを行っておらず、1年間の平均デプロイ頻度は約3.4回。
  • この比を取ると417倍もの差。

一方で、デプロイ頻度を向上させることは無意味・リスキーと考えている方々も多いと思います。
この記事では、デプロイ頻度を向上させることに対する誤解を扱います。

デプロイ頻度を向上させることへの誤解

多くのバグはデプロイに起因する。デプロイを頻繁に行うなんて頭がおかしい。

バグはデプロイがトリガーであるというのはその通りかもしれませんが、デプロイが根本的な原因であるというのは因果関係が誤っていると思われます。
バグは、ソースコードの変更が原因で起こるのであり、デプロイはそのトリガーになっているだけです。
「交番数の多い地域では検挙件数が多い傾向にあるので、犯罪を少なくするためにも交番数は少ない方が良い」と言っているようなものかもしれません(ちょっと違う?笑)。

LoCが1000行のやや大きな変更をしたとして、中にはリファクタリングが3件、機能的な追加が1件が混ざっていたとします。
その中の、リファクタリングと機能追加でそれぞれバグが1個ずつ、計2個のバグがあったとします。
これをデプロイすると、本番稼働するサービスでも計2個のバグが発生します。

LoC1000で一度にデプロイするとバグは2個

これを仮に250行×4回のデプロイに分けたとします。
4回のデプロイのうち、2回のデプロイでバグが発生することになりますが、結局は計2個のバグしか発生しません。
当たり前ですが、デプロイする変更総量が同じであれば、発生するバグの総量も原則として変わらないはずです。

LoC250×4でデプロイしてもバグは2個

デプロイ頻度を指標に置くと、ひたすらに小さいプルリクエストを作る輩が発生する。

もちろん、あまりにも無意味な分け方をしているというのであれば、あまり健全とは言えません。
しかし、意味のある単位でプルリクエストを小さく分割するのは様々な効果があり、むしろ歓迎されるべきことです。

LeanとDevOpsの科学 でも、バッチサイズ(≒プルリクエストの大きさ)の代わりとしてデプロイ頻度を測定基準にすることに決めたと書いてあります。

第2の測定尺度はバッチサイズ(一度に進める作業のサイズ)である。
これの削減も、「リードタイムの削減」と並んでリーン手法の目玉であり、現にトヨタ自動車ではこれを生産方式の基本要素の1つにして成果を上げた。
バッチサイズの削減によって得られる効果は、サイクルタイムの短縮とフローにおける変動の低減、フィードバックの高速化、リスクと諸経費の軽減、効率、モチベーション、緊急性の認識の向上、コストとスケジュールの膨張の抑制である。
ただ、ソフトウェアの場合は目に見える商品が存在しないため、バッチサイズを測定してその結果を伝えるということが難しい。
そのため、我々は「バッチサイズ」の代わりに「デプロイの頻度」を測定基準とすることに決めた。
デプロイ頻度のほうが測定が容易な上に、通常、変動も小さいからである。

本番環境の挙動が変わらないデプロイをしても、機能が追加されるわけではないから無駄である。

本番環境にはアプリケーションのログ、可用性やレイテンシ、サーバのCPU・ディスクの使用率など、あらゆる監視体制を整えているはずです。
挙動が変化しないデプロイであっても、デプロイ後にそれらのメトリクスが変化しなかったというフィードバックが返ってきます。
これらのフィードバックを得ることで、結果として変更は成功であったと分かります。

変更は成功

逆に、関連するバグ・アラートが報告された場合には、結果として変更は失敗であったと分かります。

変更は失敗

挙動が変わらないデプロイであっても、変更が成功だったというフィードバックを得られるという、十分な価値があります。

デプロイは大掛かりな作業なので、小さい変更量のデプロイは無駄である。

デプロイのパイプラインに改善点があるということだと思います。
フィードバックループを回していくためにも、デプロイは頻繁に行うようにしたいので、デプロイの負荷は限りなく小さくしたいです。

LeanとDevOpsの科学 では、デプロイの負荷を軽減する措置として、以下を挙げています。

・複数の環境に容易にデプロイでき、その環境における不具合を検知・許容でき、システムの各種コンポーネントをそれぞれ独立した形で更新できるよう設計する
・本番システムの状態は、バージョンコントロールの情報に基づき、自動化された方法で再現できるようにする(ただし本番データは除く)
・アプリケーションとプラットフォームをより賢いものにし、デプロイプロセスを極力簡素化する

バッチ実行中はデプロイが出来ないので、デプロイできる時間が決まっている。

同じく、デプロイのパイプラインに改善点があるということだと思います。
このトピックを取り上げていた記事があったので紹介します。

参考: NewsPicksにCTOとして入社して1年でDX Criteriaを大幅改善した話

動作確認・QAの回数が多くなり、大変になる。

逆だと考えています。
デプロイする変更量が少なければ、動作確認すべき項目も明確になり、QAのデバッグ時における問題の切り分けを進めやすいです。
回数は多くなるものの、一回あたりの時間は減少するはずです。

また、動作確認・QAの精度が向上するので、変更失敗率を下げる効果があります。
そもそも変更の失敗をなくすためのフローなのですから、全体としては歓迎されるべきものと考えます。

デプロイ時に毎回動作確認・QA・承認作業等が義務となっていて、それがヘッダとして乗っかってしまう、という事情も考えられます。
解決案としては、動作確認・QA・承認作業をCIなどに組み込めないかを考えるのも手だと思います。
例えば、QAが毎回確認している項目があれば、CIのテスト項目として保証するようにするなどです。

うちはBtoB。顧客のためにもサービスを止める危険は極力減らしたい。

BtoCでもサービスが停止することは収益の大幅な減少に繋がります。
致命度の度合いに大小はあれど、サービスの停止が痛いのはBtoBに限った話ではありません。

また、前述の通りデプロイ頻度を増やすことは、リスクの軽減・緊急性の認識の向上という効果があります。
顧客のためにサービスを極力止めたくないのであれば、むしろデプロイ頻度は増やすべきです。
例えとして適切でないかもしれませんが、自転車は走り続ける方が安定して走行できます。

サービス利用の多い日中 or 取引先の業務時間中にサービスを止めたくないのでデプロイはできない。デプロイ日やデプロイ時間が決まっている。

むしろ、日中や取引先の業務時間中にデプロイした方が良いと考えています。

実際のデータと、開発上で想定していたデータが異なるというのはよくある話です。
また、監視体制は本番環境に集中させる傾向があり、本番環境にデプロイして初めて気付く問題というのは一定存在します。
変更によるバグを絶対に無くすというのは、現実的なコストの範囲内では不可能なので、(もちろん極力なくすよう努めるが)バグは起こりうるという前提で話を進めた方が有意義です。

例えば、サービス利用の多い日中のデプロイを避けると、バグが起きた際に以下のような問題が起きます。

  • 利用者が少なく、アラートも少ない・特殊なケースに引っかからないなどの理由でバグに気付けない
  • あるいはオンコール担当者が気付けても、対応できる実装者が不在のため原因が不明 or 復旧できない

よって、サービス利用の多い日中のデプロイを避けると、結果的にバグ発生の時間が長くなりがちになります。

日中を避けたデプロイはバグ発生時間を長くする

普通に日中にデプロイしていれば、アラートにも気づきやすく、対応できる実装者も残っている可能性が高くなり、バグ発生の時間が短くなります。

日中に行うデプロイはバグ発生時間を短くする

取引先の業務時間中を避けたいとするケースでも、同じ問題が起きます。
すなわち、利用者が少なく、アラートも少ない・特殊なケースに引っかからないなどの理由でバグに気付けないことがあります。
また、デプロイ時間をズラしたとしても結局はバグは発生しています。
取引先が業務を開始したときにはバグが継続しており、怒られが発生するのには変わりません。
厳しい言い方をすると、デプロイ時間をずらすのはただの問題の先延ばしであり、問題をより深刻化させるだけと考えます。

取引先の非業務時間でのデプロイはバグ発生時間を長くする
取引先の業務時間でのデプロイはバグ発生時間を短くする

また、一度デプロイしてしまうと、前の状態に戻すのが難しく(あるいは不可能な)、どのくらいのバグ発生の時間の長さになってしまうかを取引先に説明できない、と心配する方もいると思います。
この問題に対しては、デプロイ後にロールバックできる仕組みをちゃんと整えておくべしという話になるかと思います。
前述の「本番システムの状態は、バージョンコントロールの情報に基づき、自動化された方法で再現できるようにする」という設計にしておけば、この心配は軽減されるかと思います。

まあここは、法令や業界によってはどうしてもデプロイできない時間帯があるケースが存在するというのは認めます。
あとは、業務開始時に障害が起きるのと比べ、業務時間中で突然障害が起きてしまうと心証的によりマイナスになりやすいとか(ただ、取引先と交渉する人にもある程度は頑張って欲しい)。

マージは頻繁に行っている。それを週1回のデプロイで反映しているだけだ。結局は反映する変更量は同じだ。

本番環境への反映でないと、顧客や監視体制からのフィードバックが返ってきません。
本番環境にデプロイすることが大切です。
また、変更をまとめて反映すると、バグ発生時に原因の切り分けが難しいため、復旧までの時間が長くなってしまいがちです。
マージとデプロイはなるべく密結合にするのが良いと思っています。

Git Flowで運用しているし、developへのマージの頻度で良いよね?

本番環境への反映でないと、顧客や監視体制からのフィードバックが返ってきません(2回目)。
ちなみに LeanとDevOpsの科学 でも、トランクベースの開発により、デリバリのパフォーマンスが向上すると書いてあります。
Git Flow以外のフローを検討してみるのも手だと思います。

参考: DevOps 技術: トランクベース開発

今は新機能をたくさん作らなければいけないし、まだそういう指標を気にするフェーズではない。

デリバリのパフォーマンスは言い換えれば、組織が市場にどれだけすぐに反応して新機能をリリースしていける能力があるか、すなわちアジリティの指標となります。
仮に運良くヒットしたプロダクトが出来たとしても、それだけでは成熟した企業に反応されてすぐに潰されてしまいます。
高いアジリティを維持し続けない限りは、成熟した企業には一生追いつけません。
デリバリのパフォーマンスを高くすることで、やっと成熟した企業と戦えるようになるのだと考えています。

また、デリバリのパフォーマンスの改善は早ければ早いほど難易度が低く、効果が高くなります。
人生、今が一番若いです(例えが違う?笑)。

ちなみに成熟度でクラスタリング分析すると、成熟した企業はデリバリのパフォーマンスが悪く、逆に成熟度が低い企業の方がデリバリのパフォーマンスが良いそうです。

参考: Announcing the 2022 Accelerate State of DevOps Report: A deep dive into security

まとめ

デプロイ頻度を向上させることに対する誤解を扱いました。
「うちは事情が違う」と思いたくなるのは理解できますが、一度は「高デプロイ頻度があるべき姿である、それが実現できない原因を取り除こう」という思考をしてみて欲しいと思ってます。
LeanとDevOpsの科学の宣伝記事みたいになってもうたです。
コメント・マサカリなどお待ちしてます。

Discussion

ログインするとコメントできます