【読書メモ】継続的デリバリ―① 1章 ソフトウェアデリバリーの問題

[継続的デリバリー　信頼できるソフトウエアリリースのためのビルド・テスト・デプロイメントの自動化](https://www.amazon.co.jp/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%83%87%E3%83%AA%E3%83%90%E3%83%AA%E3%83%BC-%E4%BF%A1%E9%A0%BC%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89%E3%83%BB%E3%83%86%E3%82%B9%E3%83%88%E3%83%BB%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E8%87%AA%E5%8B%95%E5%8C%96-Jez-Humble/dp/4048930583/) を読み始めました。 備忘録としてメモを残します。



## 本書を読む動機

私が現在所属しているチームでは、手動でのデプロイ手順検証・コミットから本番リリースまで1か月以上かかる等 ソフトウェアデリバリーに関する課題があります。

チームの課題を解消・軽減するために本書を読み始めました。


## 第1章 ソフトウェアデリバリーの問題

### 1.1 導入

ソフトウェアの価値を早くユーザに届けるためにはビルド・デプロイ・テスト・リリースのプロセスを改善する必要がある。

本書では**デプロイメントパイプライン**というパターンが中心になっている。デプロイメントパイプラインとはアプリのビルド・デプロイ・テスト・リリースといったプロセスを自動化する実装パターンである。

アプリケーションの設定ファイル・ソースコード・環境・データに対する変更がトリガーとなりパイプラインが実行される。最初にバイナリが生成され、次に生成されたバイナリに対して各種のテストが実行される。
バイナリが全てのテストにパスするとリリース可能とされる。

デプロイメントパイプラインの目的は以下の3点である。

1. ソフトウェアのビルド・デプロイ・テスト・リリースプロセスを可視化して共同作業をやりやすくすること
1. フィードバックを改善してプロセスのなるべく早いタイミングで問題を特定し、解決できるようにすること
1. ソフトウェアの任意のバージョンを任意の環境に対して完全に自動化されたプロセスによってデプロイできるようにすること

### 1.2 リリースによくあるアンチパターン

ソフトウエアプロジェクトの多くではリリースがリスクの大きい作業になり、関係者がリリースに対して神経質になっている。 その原因はプロセスにおいて間違える要素が多いことである。

リリースプロセスを信頼できないものにしてしまうアンチパターンがいくつか存在する。

#### 1.2.1 アンチパターン：ソフトウエアを手作業でデプロイする

手作業でデプロイするとデプロイに必要なステップが個別でアトミックなものになる。
このようなステップは属人化しがちでヒューマンエラーの可能性がある。

##### アンチパターンの兆候

※ 書籍に記載の内容を一部抜粋

- 詳細な手順書を作成し、リリースに必要なステップを記述する
- アプリケーションが正しく動作していることを確認するために手動テストを実施する
- クラスタ内に設定の異なるノードが存在する
- リリースが数分単位では完了しない

##### 代わりにどうすればよいか

デプロイメントを自動化することを目指す。すなわち「デプロイ対象の環境を選ぶ」ことと「デプロイ」ボタンを押すだけで済むようにする。

本書が自動デプロイを本質的な目標とするのは以下の理由がある。

- デプロイメントプロセスが自動化されていないと反復できず、信頼できない。デプロイ時にエラーが発生してもデバッグするのに時間がかかる。
- デプロイメントプロセスが手動の場合、手順書が必要になる。手順書の保守には時間がかかる上、大抵の場合最新化されていない状態になる。
- デプロイメントを自動化すると全てがスクリプトに明記された状態になるため共同作業が促進される。
- 逆に手順書では読み手の知識が少ないことを想定して何等かの前提を置く必要がある
- 手動デプロイの帰結として、デプロイメント職人に依存することになる。その人が休暇を取ったり退職すると辛い。

#### 1.2.2 アンチパターン：開発が終わってから疑似本番環境にデプロイする

開発作業がほぼ完了してから検証環境やステージング環境にデプロイされるのはアンチパターンとされる。
このパターンの特徴は以下のようなことがある。

- ステージング環境にデプロイして初めて運用担当者は新しいリリースに触れる。
- ステージング環境にデプロイするチームと本番環境にデプロイするチームが別の場合、運用担当者がソフトウエアに触れるのが本番リリース当日になる。
- 開発チームがインストーラ・設定ファイル・データベースのマイグレーションファイル・デプロイ用ドキュメント等をまとめてデプロイ担当者に渡す。 しかし、事前に疑似本番環境でテストされていない。


チーム間の協力関係が無いとステージング環境へのデプロイ時に問題が発生することがある。規律正しいチームは当日のトラブル対応もデプロイ計画に組み込んでいるが、このようなプロセスは概して非効率である。

ステージング環境にデプロイした時に新しいバグが見つかることも珍しくない。この頃には本番リリース日も迫っているためバグを修正する時間がない。結局、致命的な不具合のみが修正されて大半の不具合が放置される。

リリースに関して問題を悪化させる事がいくつかある。

- リリースサイクルが長いほどデプロイ時に想定外の問題が発生しやすくなる。また、問題の修正にも時間がかかる。
- 大きな組織ではデリバリーのプロセスが別々のグループに分割されている。(データベース管理者・運用担当者・テスター等) このようにサイロをまたいで協力するコストは膨大なものになる。

##### 代わりにどうすればよいか

テストやデプロイ・リリースといったデリバリープロセスを開発プロセスに統合すればよい。
これらのプロセスを開発時に普通に実施するものとすれば、リリースのリハーサルを行う機会が多く存在することになるため本番リリースのリスクが低くなる。

#### 1.2.3 アンチパターン：本番環境について手作業で構成管理を行う

多くの組織では本番環境の構成管理が手作業で実施されている。例えば データベース接続設定やAPサーバのスレッドプール内のスレッド数を変更する必要が生じると手作業で変更するといったことである。

このアンチパターンの兆候には以下のような例がある。

- ステージング環境へのデプロイは成功するが本番環境へのデプロイには失敗する
- リリースのための環境を整えるのに時間がかかる
- システムを以前の設定に切り戻すことができない
- システムの設定は本番環境の設定を直接修正することで行われる。

##### 代わりにどうすればよいか

検証環境・ステージング環境・本番環境のあらゆる要素、特にサードパーティ要素の設定は自動プロセスを通じてバージョン管理から適用されるべきである。理想を言うと手作業で変更できないようにすべきである。

変更は自動化されたプロセスを通じて本番環境に適用されるべきである。デプロイが失敗した場合には同じく自動プロセスによりロールバックできるようにしておく必要がある。

### 1.3 もっとうまくできないのだろうか？

本書の目標はデプロイメントパイプラインの使い方を説明すると同時に、テスト ・デプロイメント・更に包括的な構成管理を自動化してボタン1つでソフトウエアをリリースできるようにすることである。

小規模なチームだけではなく、大規模なチームでもこのプラクティスを実践することができる。

### 1.4 どうすれば目標を達成できるか？

本書においては**高品質で価値のあるソフトウエアを短いサイクルタイムでユーザに届けること**に主眼を置く。 そのためにはソフトウエアを自動化された方法でこまめにリリースする必要がある。

- 自動化が必要な理由

同じ品質で繰り返し実行できるようにするため。

- こまめなリリースが必要な理由

リリース間の差分を小さくするため。これによりリリースのリスクが小さくなる。
リリースをこまめに行えばフィードバックを素早く得ることができる。

#### 1.4.1 あらゆる変更はフィードバックプロセスを引き起こさなければならない

ソフトウエアを分解すると実行可能なコード・設定・ホスト環境・データの4つになる。これらのいずれかが変更されるとソフトウエアの振る舞いが変化する可能性がある。 したがって、これらをバージョン管理下に置いて変更があった場合はテストする必要がある。

- 実行可能なコード： ソースコードが変更されると変更される。そのたびにビルド・テストしなければならない。実行可能なコードはあらゆる環境で再利用すべきである。
- 設定：環境ごとに変更すべきものは設定情報として管理する。設定を変更したのであればテストする必要がある。
- ホスト環境： 環境が変更された場合、変更を適用したうえでテストしなければならない。この環境にはOSやネットワーク構成・外部システム等が含まれる。
- データ： データの構造が変更されたらテストしなければならない。


フィードバックプロセスとはできる限り自動化された方法で変更をテストすることが含まれる。主なチェック観点は以下のようなものがある。

- 実行可能なコードを生成するプロセスが正しく動作すること。これによりコードのシンタックスが正しい事を担保できる。
- ユニットテストがパスすること。これによりコードが期待通りに動作することを検証することができる。
- ソフトウエアは特定の品質指標(例： テストカバレッジ等)を満たす必要がある。
- ソフトウエアの受け入れテストがパスすること。これにより、業務的価値を満たしていることを担保できる。
- ソフトウエアの性能テストがパスすること。キャパシティや可用性・セキュリティ等の観点から見てアプリケーションが正しく動作することを担保する。
- ソフトウエアの探索的テストがパスすること。このプロセスは手作業で実施される。

#### 1.4.2 フィードバックはできる限り早く受け取らなければならない

プロセスを自動化すると素早くフィードバックを得ることができる。

デプロイメントパイプラインを実装しておけば繰り返し作業をコンピュータに任せることができ、人的リソースが最適化される。

パイプライン序盤のテストには下記の特徴がある。

- 実行時間が短い
- 網羅率が75%以上である
- テストが失敗したらソフトウェアに欠陥があるためリリースしてはいけない。このフェーズにはUIテストを含めてはならない。
- できる限り環境に依存しないようにしなければならない

一方、パイプライン後半のテストには以下の特徴がある。

- 実行に時間がかかる。
- テストの一部が失敗するかもしれないが、状況によってはリリースしてもよい
- できる限り本番に近い環境で実行する必要がある。 これにより、アプリケーションだけではなくデプロイメントプロセスや本番環境に対する全ての変更を間接的にテストすることができる。

テストが成功すればリリース候補に信頼が持てる。逆にテストが失敗したらリリースすることができない。

#### 1.4.3 デリバリーチームは素早いフィードバックを受け取り、それに対応しなければならない

ソフトウェアデリバリーのプロセスに関わる人がフィードバックプロセスに関わることが推奨される。
少なくとも1回のイテレーションにつき1度は振り返りを行ってデリバリープロセスの改善について話しあう必要がある。

### 1.5 どんな恩恵を受けられるのか？

前述したアプローチによる最大の恩恵は反復可能で信頼でき、予測可能なリリースプロセスを構築できる点にある。 それ以外にも次のような恩恵が挙げられる。

1. チームに権限を与える： 常に正しいビルドが用意されており、ボタン1つでデプロイできるためチームのメンバーが任意のタイミングで任意のバージョンをリリースできるようになる。

2. エラーが削減される： 設定ファイル・データベース作成スクリプト・環境設定等変化する可能性のあるもの全てをバージョン管理することで指定した環境に指定した内容を再現することができる

3. ストレスを軽減する： ボタン1つで本番環境にデプロイできるようになればリリースの負荷が低減する

#### 1.5.1 できるようになりたければ、練習しろ

デプロイ先がどこであってもデプロイメントの方法を統一することが望ましい。
こうすることでテスト環境にデプロイするたびに本番環境へのデプロイを予行することができる。



### 1.6 リリース候補

伝統的なソフトウエア開発手法では開発の後半で時間とお金をかけて集中的にテストする。
このような方法をとるとアプリケーションの品質は低下しがちである。

そうではなく、こまめにビルド・テストして開発プロセスの序盤から品質を作り込むべきである。

#### 1.6.1 あらゆるチェックインは潜在的にリリースにつながる

多くのプロジェクトではこまめに統合すると不具合の頻度が増えると考え、先延ばしにする傾向にある。
しかし、痛みを軽減するためには統合をこまめに行うことが望ましい。つきつめると何か変更を加えたら必ずそれを統合すべきである。このアプロ―チを継続的インテグレーションと呼ぶ。

継続的インテグレーションのプラクティスを実践しているプロジェクトでは変更が原因でソフトウエアが壊れた場合、すぐに修正される。このフローが徹底されている限り、ソフトウエアは常に動く状態になる。

継続的インテグレーションが実践されている限りあらゆる変更は事実上リリース候補となる。

### 1.7 ソフトウェアデリバリーの原則

#### 1.7.1 ソフトウエアをリリースするための、反復可能で信頼できるプロセスを作り上げよ

ソフトウエアのリリースには反復可能性と信頼性が重要である。この2点は次の2つの原則から導き出される。ひとつはほとんど全てのプロセスを自動化すること。ふたつめはビルド・デプロイ・テスト・リリースに必要なものをバージョン管理下に置くことである。

#### 1.7.2 ほとんどすべてを自動化せよ

探索的テスト・デモ・承認のように自動化できない作業も存在する。しかし、デプロイメントプロセスにおいて自動化できる作業は多い。受け入れテスト・データベースのアップデートやダウングレード等も自動化できる。

一度に全て自動化する必要はなく、デプロイメントプロセスにおいてボトルネックになっている部分から少しずつ自動化していけばよい。

#### 1.7.3 すべてバージョン管理に入れよ

アプリケーションをビルド・デプロイ・テスト・リリースするのに必要なものは全てバージョン管理するべきである。 これらは一意に識別できる識別子を持つ必要がある。 

#### 1.7.4 痛みを伴うものはこまめに実施し、痛い思いは早めにしておけ

ソフトウエアのリリースが負荷の高い作業であれば変更のたびに本番環境に、それが難しい場合疑似本番環境にリリースする。

変更のたびにリリースすることができない場合、週に一回リリースするなど段階的に進めていけばよい。

#### 1.7.5 品質を作り込め

欠陥を早く見つければ修正のコストも安くつく。 欠陥を早く見つけるためには開発フェーズが終わってからテストを始める手法を辞める必要がある。テストは常に実施する必要がある。

#### 1.7.6 完了したとはリリースしたということだ

フィーチャーがメインブランチに統合された時点では「完了」したとはいえない。本番環境あるいは疑似本番環境にリリースして初めて「完了」したと言える。

#### 1.7.7 誰もがデリバリープロセスに対して責任を負う

開発者・テスター・運用担当者の業務がサイロ化されていると欠陥が生じやすい上に、いざ問題が発生するとお互いに非難し合う事態に陥りがちである。

プロジェクトに関わる全員をデリバリープロセスに巻き込んで積極的にコミュニケーションをとることが望ましい。

#### 1.7.8 継続的改善

アプリケーションによって最初のリリースは最初のステージでしかなく、ほとんどの場合は後に改修される。同様にデリバリープロセスも合わせて改修することが重要である。