目的
書籍「入門 継続的デリバリー」を読む機会ができたので、復習・知識の定着を目的として、学習した内容を殴り書きレベルでアウトプットします。
主観で気になった点をメモり、それをChatGPTで要約してもらうといったアウトプット形式になるので、個人のメモによるAIへのインプットに情報が影響されると思います。間違った解釈の場合もあり得るため、その点はご了承ください。
本記事の対象者は特におらず基本自分のための記事となりますが、もし本書に興味をお持ちの方がおられましたら、この記事が書籍の購入への後押しになれれば幸いです。
書籍紹介
入門 継続的デリバリー
-テストからリリースまでを安全に自動化するソフトウェアデリバリーのプロセス
出版:O'REILLY
発売日:2024/4/24
目次
序文
はじめに
第1部 継続的デリバリーとは
1章 『入門 継続的デリバリー』へようこそ
2章 パイプラインの基本
第2部 常にデリバリー可能な状態に保つ
3章 バージョン管理は継続的デリバリーの成功に不可欠
4章 リントを効果的に使う
5章 ノイズの多いテストに対処する
6章 遅いテストスイートを速くする
7章 適切なタイミングで適切なシグナルを送る
第3部 デリバリーの簡略化
8章 簡単なデリバリーはバージョン管理から始まる
9章 安全かつ信頼性のあるビルド
10章 自信を持ってデプロイを行う
第4部 継続的デリバリーのデザイン
11章 継続的デリバリーを始める
12章 スクリプトはコードでもある
13章 パイプラインのデザイン
付録
付録A CDシステム
付録B バージョン管理システム
章を読み終わり次第、随時更新予定です。
第1部 継続的デリバリーとは
1章 『入門 継続的デリバリー』へようこそ
📦 継続的デリバリー(Continuous Delivery)の概要と重要性
✅ なぜ継続的デリバリーが重要か?
- すべてのソフトウェア開発において有益
- 変更の迅速かつ安全なリリースが可能になることで、
開発の品質・市場対応力・フィードバック速度を向上
📚 継続的デリバリーとは?
▶ 本書の定義
プロフェッショナルな品質のソフトウェアをエンジニアが思い通りに作成できるようにするためのプロセスの集合体
▶ CDF(Continuous Delivery Foundation)の定義
ソフトウェア開発チームが、変更を安全・迅速・持続的にリリースする手法
以下の2点を実現していることが条件:
- いつでも変更をリリース可能である状態を保つ
- リリースプロセスが自動化されている
▶ 継続的デリバリーの2つの目標
- いつでも安全に変更をリリース可能にすること
- ボタン一つで簡単にデリバリできる状態を実現すること
🧱 継続的デリバリーを支える活動
1. 継続的インテグレーション(CI)
- 変更をできる限り早く・頻繁に統合して検証
- 例:料理で新しい食材を加えるたびに味見をする
- コード変更のたびに、ビルド・テスト・静的解析などの自動検証を行う
2. 自動化されたリリースプロセス
- テスト、ビルド、リリース、デプロイなどを繰り返し実行可能な形で自動化
- CIの結果を受けて、そのまま本番環境に近い形でリリース準備を行う
🗂️ 用語と概念の整理
| 用語 | 定義 |
|---|---|
| インテグレーション | 複数人のコード変更を統合して、動作検証する行為 |
| 継続的インテグレーション(CI) | コード変更ごとにビルド・テスト・分析を自動実行して、変更の統合を信頼性の高いものにするプロセス |
| デリバリー | ビルド、リリース、デプロイなどのリリース準備全体を指す |
| 継続的デプロイメント(CD) | コミットごとに自動でユーザ環境へリリースする仕組み |
| 継続的デリバリー | 動作可能なソフトウェアを、いつでも・安全に・意味のあるかたちで提供できる状態を保つ開発手法 |
🎯 結論
継続的デリバリーとは、ソフトウェアを「いつでも・安全に・自動でリリースできる」状態に保つための実践的な開発手法である。
それにより、開発スピード、品質、ユーザへの価値提供を最大化できる。
inputメモ
- 継続的デリバリーは必要か
- Yes、どんなソフトウェアを作っているにせよ、継続的でプリオの原則を適用することで利益を得ることができる
- 継続的デリバリーとは
-
本書の定義
プロフェッショナルな品質のソフトウェアを書く複数のソフトウェアエンジニアが、思い通りのソフトウェアを作成できるようになるために必要なプロセスの集合体
-
CDFによる定義
ソフトウェア開発において、チームがソフトウェアの変更を安全、迅速、かつ持続的にユーザにリリースする手法であり、以下2つを実践している。
- いつでも変更がリリース可能であることを立証している
- リリースプロセスを自動化している
-
以上より、継続的デリバリーを実践するために達成すべき目標は2つ
- いつでも安全にソフトウェアの変更を提供できる
- ボタンを1つ押すぐらい簡単に、そのソフトウェアをデリバリできる
-
上記を達成するための活動
- 継続的インテグレーション
- CIで変更点が検証されたら変更をリリースするプロセスの自動化、繰り返し実行可能性
-
- 用語
-
インテグレーション
複数人によって行われるコードの変更を組み合わせて、そのコードが意図した通りに動くかどうかを検証する行為
-
継続的インテグレーション
- 例え
- 料理で新しい食材を加えるたびに味見する
- できる限り頻繁に、できる限り早く、変更をインテグレーションする
チェックインの際に各変更を検証した上で、コードの変更を高い頻度で結合していくプロセスのこと
エンジニアによるコードの変更をまとめる = CIを利用するエンジニアが、変更を加えるたびにコードをコミットして共有のバージョンコントロールシステムにプッシュすることでテストやリンティングなどの自動化された検証が適用され、変更された複数のコードが結合されても機能を検証している
- 例え
-
デリバリー
- デリバリーする=ビルド、リリース、デプロイ、などを含む
-
継続的デプロイメント
動作するソフトウェアは、コミットごとにユーザへ自動的にリリースされる
-
継続的デリバリーの要素
動作するソフトウェアを、プロジェクトにとって意味のある限り迅速に、いつでも安全にユーザにリリース可能な状態にしておくソフトウェア開発手法
-
2章 パイプラインの基本
✅ 概要
継続的デリバリー(CD)は、ソフトウェアを安全かつ迅速にユーザに届けるための仕組みであり、その中核は パイプラインとタスクによる自動化された処理の流れです。
この要約では、CDパイプラインの構成要素、タスクの種類、自動化トリガー、そして関連する用語について整理します。
📦 CDの前提:バージョン管理
- Gitなどのバージョン管理システム(VCS)を使用することがCDの前提
- コード履歴の管理、変更のトラッキング、マージコンフリクトの解消を自動化するために不可欠
- VCSにコードが存在しない限り、CDパイプラインの構築は困難
🔧 CDパイプラインの基本構成
パイプラインとは?
- コードの変更が入るエントリーポイント
- タスクを適切な順序・タイミングで実行する制御の役割
タスクとは?
- パイプライン内で実行される1つ1つの処理単位
- 例:テスト、ビルド、デプロイ など
🚀 CDパイプラインの基本タスク
| タスク | 説明 |
|---|---|
| リント | 静的解析により、コードのエラーやスタイル違反を検出 |
| 単体テスト・統合テスト | コードが正しく動作するかを確認 |
| ビルド | コンテナイメージの作成などの変換処理 |
| パブリッシュ | 作成したイメージをレジストリにアップロード |
| デプロイ | 新しいイメージで動作中ソフトウェアを更新 |
⚙️ 自動化のトリガーと実行タイミング
- Webhook:コードの更新(pushなど)に応じて、パイプラインを自動実行
- イベントベース:GitHub Actions, GitLab CI などで利用
- トリガーの役割:変更が発生した瞬間から自動でCDプロセスを開始できるようにする
📘 用語の整理
| 概念 | 別名・同義語 |
|---|---|
| パイプライン | ワークフロー |
| タスク | ステージ、ジョブ、ビルド、ステップ |
| パイプライン実行環境 | ノード、ランナー、エグゼキュータ、エージェント |
✅ まとめ
継続的デリバリーを構成する主な要素は次の通りです:
- コードはバージョン管理下にあることが必須
- パイプラインが全体の処理の流れを管理し、タスクが実際の作業を担う
- パイプラインはイベントにより自動的に起動される
- 各タスクはリント → テスト → ビルド → パブリッシュ → デプロイという流れを基本とする
- 「パイプライン」「タスク」といった用語には、実装ごとに別名がある
このように、CDは自動化と一貫性を通じて、高速で信頼性のあるソフトウェア配信を実現する基盤となります。
inputメモ
- ポイント
- 基本的な構成要素であるパイプラインとタスクの扱い方
- 基本的なCDパイプラインの要素(リント、テスト、ビルド、パブリッシュ、デプロイ)の学習
- パイプラインの実行における自動化の役割(Webhook、イベント、トリガー)の理解
- CDの分野における様々な用語について
- 内容
- バージョン管理
- Gitのようなバージョン管理システムを使うことは、CDの前提条件。コードの履歴とコンフリクトの検出が可能な場所に保存しない限り、CDを作成することは実質的に不可能
- 用語定義
- タスク
- 実行する個々の作業
- パイプライン
- コードへのエントリポイントのようなもの、全てのタスクを適切なタイミングで適切な順序で呼び出す
- タスク
- CDパイプラインの基本タスク
- リント
- サービスのコードにある一般的なプログラミングエラーとスタイルエラーを検出。静的解析の最も一般的な形態。
- 単体テストと統合テストの実行
- サービスのコードが開発者の意図した通りに動作することを検証
- イメージのビルド
- 各サービス用のコンテナイメージをビルド
- パブリッシュ
- イメージレジストリにコンテナイメージをアップロード
- デプロイ
- 新しいイメージを使用して、動いているソフトウェアのバージョンを更新
- リント
- パイプラインをいつどのように実行するか
- バージョン管理システムのWebhookによるコード変更の通知自動化
- パイプラインのトリガー
- バージョン管理システムのWebhookによるコード変更の通知自動化
- その他用語の定義
- パイプラインが実行されるマシン=ノード、ランナー、エグゼキュータ、エージェント
- パイプライン=ワークフロー
- タスク=ステージ、ジョブ、ビルド、ステップ
- バージョン管理
3章 バージョン管理は継続的デリバリーの成功に不可欠
✅ 概要
継続的デリバリー(CD)を成功させるためには、バージョン管理と**設定のコード化(Config as Code)**が不可欠です。
コードと設定をすべて追跡可能にし、変更をトリガーにパイプラインを自動実行することで、常にリリース可能な状態を保ちます。
📘 バージョン管理の役割
- **バージョン管理システム(VCS)**は、プレーンテキストの変更履歴を記録するツール(例:Git)
- **変更単位は「コミット」または「リビジョン」**と呼ばれ、リポジトリに格納される
- すべての変更の履歴を保持=ソースコードの信頼できる出典(Source of Truth)
🚀 CDにおいてなぜバージョン管理が不可欠か?
- **変更を統合する方法(インテグレーション)**と、**変更を保存する場所(リポジトリ)**が必須
- バージョン管理により:
- CIを通じて変更が自動でテストされ
- CDパイプラインが最新の変更を契機にトリガーされる
🔄 リリース可能な状態を保つ方法
- バージョン管理を常にグリーン(テストが成功している状態)に保つ
- リモートリポジトリの変更をトリガーにして、自動でパイプラインを実行
- これにより、任意の時点でソフトウェアをリリース可能な状態に保てる
🛠️ Config as Code(構成のコード化)
- 設定ファイルをリポジトリに含めてコードと同様に管理
- 特徴:
- 変更履歴が残る
- 設定変更もコードレビューの対象になる
- 自動デプロイと組み合わせやすい
- 機密データは外部のセキュアな仕組み(例:Secret Manager)で管理
📂 Source of Truth(信頼できる情報源)
- バージョン管理に置かれたコードと設定が、常に正しい状態を示す唯一の情報源
- 手動変更や人の記憶ではなく、リポジトリが「真実のソース」
✅ まとめ
継続的デリバリーを維持・進化させるうえで重要な実践:
- すべてのコードと設定をバージョン管理に保存
- Config as Code を採用し、インフラやアプリ設定も追跡可能に
- リモートリポジトリの変更をきっかけにCDパイプラインを自動実行
- 常にテスト済み・リリース可能な**「グリーンな状態」**を維持する
- リポジトリが唯一の信頼できる情報源(Source of Truth)
このアプローチにより、一貫性・自動化・信頼性の高いリリースサイクルを実現できます。
inputメモ
- ポイント
- 継続的デリバリーにバージョン管理が不可欠な理由を理解する
- バージョン管理をグリーンな状態にし、バージョン管理の変更に基づきパイプラインをトリガーすることで、ソフトウェアをリリース可能な状態に維持する
- 設定をコードとして定義する(Config as Code)
- 全ての設定をバージョン管理することによって自動化を実現する
- 内容
- バージョン管理は、プレーンテキストの変更を追跡するためのソフトウェア
- 各変更はバージョンによって識別され、コミットまたはリビジョンとも呼ばれる
- リポジトリ:保存する中心となる場所
- バージョン:全ての変更の履歴
- バージョン管理は継続的デリバリーの基礎となるもの
- 継続的インテグレーションを行うには、変更を結合する方法と変更を保存する場所が必要
- バージョン管理をリリース可能な状態に保つ
- テストが実行されることを保証すること=自動化
- リモートリポジトリの変更を契機にパイプラインがトリガーされるように設定すること
- Source of Truth
- 信頼できるコードのバージョン
- Config as Code
- 設定ファイルをリポジトリに配置する
- 機密データは別のシステムによって管理させる
- ソフトウェアの設定をソースコードと同じように扱う
- バージョン管理は、プレーンテキストの変更を追跡するためのソフトウェア
4章 リントを効果的に使う
✅ 概要
リント(Lint)はソースコードを静的に解析し、バグ、エラー、スタイルの問題を自動で検出するツールです。継続的デリバリーにおいて、コードベースの品質と一貫性を保つために不可欠な仕組みです。ただし、特にレガシーコードに対しては、すべての問題を即時修正するのではなく、優先順位をつけて段階的に対応する現実的なアプローチが求められます。
ポイント
🧠 リンターが検出する問題の種類
| 種類 | 内容 |
|---|---|
| バグ | 実行時に誤動作を引き起こす恐れのある明確な不具合。修正優先度が高い。 |
| エラー | 動作には直ちに影響しないが、論理的に誤っていたり、予期せぬ結果を招く可能性がある。 |
| スタイル | コーディング規約に違反している、可読性を損なう記述など。保守性向上に寄与する。 |
⚙️ 理想は警告ゼロ、しかし現実と向き合う調整が必要
- 目指すべきは「リント警告ゼロ」の状態だが、レガシーコードでは非現実的な場合もある。
- 古いコードでは警告を一部無視したり、現状維持のまま隔離するという選択肢もある。
- 新規コードから順にルールを厳格に適用していく「段階導入」が有効。
🔁 少しずつ問題に対処していく戦略
- 大規模なリント修正はバグを招くリスクがあるため、小さな変更を積み重ねる。
- 変更内容を可視化しやすくし、リント違反ごとにIssueを切ってチームで分担する。
- チーム全体でルールを共有し、CIにリントチェックを統合して継続的に監視。
⚖️ 問題解決の優先順位とリスク評価
| 優先度 | 問題種別 | 理由 |
|---|---|---|
| 高 | バグ | ソフトウェアの正しい動作に影響。放置すると深刻な不具合につながる可能性がある。 |
| 中 | エラー | 明確なバグではないが、保守や機能追加時の混乱の原因になる可能性がある。 |
| 低 | スタイル | 即時の影響はないが、可読性と一貫性のために重要。新しいコードでは積極的に修正。 |
- 影響の大きい部分やチーム全体で触れる頻度の高い箇所を優先的に修正。
- コードの一部に対しては「今は触らない」戦略をとるのも合理的。
まとめ
リントは、コード品質を保ち、バグや将来的な不具合を防ぐために欠かせないツールです。特にレガシーコードでは、全てを即座に修正するのではなく、優先度を見極め、段階的に対応していくことが重要です。バグに対しては即時対応し、エラーやスタイルの問題は影響範囲や改善効果を考慮して判断するべきです。リントの適用は、継続的改善の文化を育む第一歩になります。
inputメモ
- ポイント
- リントがコードから見つけることができる問題の種類について学ぶ:バグ、エラー、スタイルの問題
- 発見される問題をゼロにするという理想を目指すが、レガシーコードベースの現実に合わせて調節する
- 少しずつ問題に対処していくことで、大規模な既存コードベースのリントを行う
- 新たなバグが発生するリスクと、問題点を解消するメリットを比較する
- 内容
- リントで解決
- リンターを使って埃(リント)を見つける
- プログラミングのエラーも些細なことでも時間が経てば積み重ねとなりバグを引き起こす
- バグを特定して、コードベースの一貫性と保守性を維持するのに役立つ
- リンターによって解析できる問題は3種類
- バグ:コードの誤りによって望んでいない動作につながるもの
- エラー:動作に影響を与えないコードの誤り
- スタイルの問題:一貫性のないコードスタイルの決まりとコードの臭い
- リントの問題を解決するための変更も、どんな変更もさらなる問題を引き起こす可能性がある
- 全てを修正すべきではない
- 場合によってはコードを隔離して放置する
- 最も影響の大きい問題を最初に修正する
- 優先順位は、バグ>エラー>スタイル
- 全てを修正すべきではない
- リントで解決
5章 ノイズの多いテストに対処する
✅ 概要
継続的デリバリー(CD)において、テストはソフトウェアの品質を維持し、安全に変更をデプロイするための重要な要素です。ただし、信頼できないテストは開発の障害になり得ます。このセクションでは、テストから有益な「シグナル」を得て、「ノイズ」を除去し、健全なテスト環境を維持するための考え方を解説します。
ポイント
✅ テストの重要性
- CDでは「常にリリース可能な状態」を保つ必要がある
- テストは安全な変更の前提条件
- すべての変更に対してテストを実行する文化が必要
📡 シグナルとノイズの違い
| シグナル | ノイズ |
|---|---|
| 実際に問題のある失敗 | 理由が分からない・再現しない失敗 |
| 意図通りの成功 | 本来失敗すべきなのに成功してしまうもの |
- 成功・失敗どちらも「情報」だが、文脈によって有用性が異なる
🛠 テスト失敗の扱い
- テスト失敗=全てバグとして調査対象とする
- 原因の可能性:
- テスト自体の誤り
- 実装のバグ
- 環境依存の揺らぎ(フレーキーテスト)
🔁 フレーキーテストの影響と対策
- フレーキー(flaky)=不安定に失敗するテスト
- 無視せずに他のテストと同じように調査する
- 再試行で「成功してしまう」ことがノイズを増幅させる危険あり
🚨 失敗の対応方針
- ラインを止めて修正完了までマージ停止
- 開発チーム全体で「グリーンな状態を維持する」文化を作る
- 問題のあるテストの修正・除去には長期的視点が必要
✅ まとめ
継続的デリバリーにおけるテスト戦略の原則:
- テストはコード品質のシグナルを出す重要な装置
- 全テストの失敗はバグとして扱い、必ず調査する
- フレーキーテストは無視せず、確実に安定化させる
- ノイズが増えるとシグナルを見逃す。精度と信頼性を維持することが大事
- テストを「グリーン」に保つことは、価値ある投資である
この姿勢を貫くことで、安全・迅速・確実なリリースサイクルが実現します。
inputメモ
- ポイント
- テストがCDにとって極めて重要である理由の説明
- ノイズの多いテストの失敗から有用なシブナルを得る計画の作成と実行
- 何がテストにノイズをもたらすかの理解
- テストの失敗をバグとして扱う
- フレーキーテストの定義と、それが有害である理由の理解
- 適切なテストの再試行
- 内容
- CDにおけるテストの位置付け
- 安全に変更を提供する、それには自分のコードが意図した通りに動作すると確信する必要がある
- テストを頻繁に実行するだけではなく、全ての変更に対して実行することが非常に重要
- プロジェクトが大きくなるにつれてテストスイートも大きくなり、時間の経過とともにテストが遅くなり信頼性が低下する
- テストスイート:テストのグループ分け、ソフトウェアの特定部分をテストするテストのセット
- テストを長期にわたって維持する方法が必要
- シグナルとノイズ
- ある望ましい情報(シグナル)とそれを妨げるもの(ノイズ)
- テストの成功も失敗も情報をもたらす
- 失敗も成功もシグナルでありノイズでもある
- 成功は、情報を隠蔽しない限りはシグナル、ただし本当は成功してはいけないテストが成功してしまった場合はノイズ
- 失敗は、新しい情報を提供すればシグナル、そうでない場合はノイズ
- テストの失敗を無視することで、ノイズに変わる
- アラートシステムは人がアラートに注意を払っている場合にのみ有効
- あまりにうるさいとシグナルを見逃すことに繋がる
- グリーンな状態を実現して保つ
- テストの失敗をシグナルとする
- テストの価値はシグナルの提供
- テストを修正するとは
- 失敗するテストを成功するテストに変えることだけではない
- テストがノイズである状態からシグナルである状態にする
- テストが失敗する時
- テストが間違っている
- システムにバグがある
- 1つ目に飛びつくことが多々ある
- テストが失敗する時、テストが期待するシステムの動作と、実際のシステムの動作との間に不整合が存在する
- 修正がテストの更新かシステムの更新かに関わらず、不整合は調査する必要がある
- ノイズが混入するポイント
- テストの失敗がノイズになる原因
- テストの失敗は全てバグとして扱い、十分に調査する
- フレーキーテスト
- 一貫性なく失敗するテスト
- 無視せずに他のテストと同等に扱う
- 失敗への対応
- テストが失敗したらラインを止めてグリーンに戻す、テストが修正されるまでMainブランチへのマージはやめる
- コードの実際の動作との不整合を理解して、適切な場所に修正を加える
- フリーキーテストを再試行によって成功させることは「成功すべきではないのに成功してしまうテスト」というノイズをもたらす
- グリーンな状態を保つ
- テストスイートを修正するために開発を凍結することは投資に見合う価値がある
- 問題のあるテストを無効にしたり再思考したりすることは、長い目で見ればあまりお勧めできない
- バグのコストは幾らかが重要、バランスが大事
- CDにおけるテストの位置付け
6章 遅いテストスイートを速くする
概要
継続的デリバリーにおいて、テストスイートの速度はリリースサイクル全体の俊敏性と信頼性を左右する重要な要素です。特に遅いテストは開発者へのフィードバックを遅らせ、開発効率を損ないます。このセクションでは、遅いテストスイートを高速化するための戦略を解説します。
ポイント
🧪 テストピラミッドの活用
- 単体テスト > 結合テスト > E2Eテスト の順でコストと信頼性を最適化
- E2Eは最小限、単体テストで最大のカバレッジを狙う
🚦 高速テスト優先戦略
- 小さく速いテストから先に実行し、即時フィードバックを得る
- フルパイプライン(E2E含む)は夜間実行などで分離
📊 テストカバレッジの活用
- ステートメント・条件カバレッジを測定し、品質を維持
- カバレッジ低下をブロックする閾値設定(CIで自動化)
🧹 テスト構成の最適化
- 結合テストの中で単体テストと重複するものを整理・削除
- 高速な単体テストに置き換えることで実行コストを削減
⚙️ 並列実行・シャーディング
- 並列実行:依存や順序関係のないテストを複数スレッドで同時実行
- シャーディング:複数マシンにテスト群を分割して実行時間を短縮
まとめ
テストスイートの高速化は、テストの量を減らすことではなく、戦略的に構成し直すことです。ピラミッド構造を意識したテスト構成、高速テストの優先実行、並列化・分散化によって、より早く正確なフィードバックループを実現しましょう。
inputメモ
- ポイント
- 高速なテストを最初に実行することで、遅いテストスイートを速くすること
- 単体テストと結合テストとシステムテストの最も効果的な比率を決定するためにテストピラミッドを使用すること
- 適切な比率を実現し、維持するために、テストカバレッジ測定を使うこと
- 並列実行とシャード実行を使用することで、遅いテストからより高速にシグナルを得ること
- 並列実行とシャード実行が実行可能なタイミングと、その使い方を理解すること
- 内容
- テストと継続的デリバリー
- 継続的テスト:CDパイプラインの一部としてテストを実行すること、テストを継続的に実行する必要がある
- テストピラミッド
- ソフトウェア開発プロジェクトで必要とされるテストの種類と、それぞれのテストがどの程度の割合で行われるのが適切かを示す一般的な図解
- 単体テスト>結合テスト>E2Eテスト
- ピラミッドの一番下にあるテストが最も結合度が低く、一番上にあるテストが最も結合どの高い(テストされるコンポーネント間の相互依存性が高まる、より複雑で実行に時間がかかるテスト)
- 速いテストから先にやる
- 自信の変更についてすぐにフィードバックを得ることができる
- 単体テストの実行のみを含むパイプラインを全ての変更に対してマージする前に実行する
- 長くて遅いパイプライン(単体テスト+結合テスト+ブラウザテスト+イメージビルド+イメージプッシュ)は毎晩実行
- バランス
- ほとんどのテストは単体テストであるべき
- 単体テストでカバーできないものは結合テストが次善の策
- E2Eテストはごく少数
- テストの安全な調整
- 単体テストのカバレッジを測定
- テストカバレッジ:テスト対象のコードをどれだけ効果的に実行しているかを評価する
- テスト対象のどのコードがテストに使われていて、どのコードが使われていないかを教えてくれる
- ステートメントカバレッジとコンディションカバレッジ
- テストカバレッジの低下を防ぐための閾値の強制
- カバレッジを測定して、カバレッジを低下させるPRをブロックする自動化を追加
- 単体テストでカバーされていないところの単体テストを追加
- 単体テストと同じロジックの結合テストで遅いものを見つけて更新削除する
- 高速なテストを増やして、低速なテストを減らす
- 結合テストの目的は全ての単体が正しく繋がっていることを確認すること
- 単体テストと同じ子バー範囲の結合テストを実行するコストに見合うだけの価値があるか
- 見落としたコーナーケースを発見できる可能性はあるか
- 単体テストのカバレッジを測定
- テストとは
- 恐れを抱くことなく思い通りに変化を起こせると確信させるもの
- システムがどのように動作するかを考えたことをコード化したもの
- テストの並列実行
- 互いに依存したり、干渉したり、順序関係なく実行可能なこと
- →どういうことか詳しく?
- 互いに依存したり、干渉したり、順序関係なく実行可能なこと
- テストのしゃーディング
- 複数のマシンにまたがってテストを実行
- テストと継続的デリバリー
7章 適切なタイミングで適切なシグナルを送る
概要
CI(継続的インテグレーション)は、変更のライフサイクル全体でバグの混入を防ぐための重要な要素です。特に、マージ前後や定期的なCI実行によって、変更が他と競合した際や依存関係の変化によるバグを早期に検知できます。これにより、信頼できるソフトウェアリリースを維持します。
ポイント
🔍 変更のどこにバグが入り込むかを見極める
- 変更のライフサイクル全体でバグが混入する可能性を特定
- 特に競合する変更との結合タイミングや依存関係の変化に注意が必要
🧪 CIの種類と役割
| タイミング | 特徴 | メリット | 限界 |
|---|---|---|---|
| マージ前のCI | PRに対して実行 | Mainを壊さずに済む | 分岐による新しい変更を考慮できない |
| マージ後のCI | Mainに対して実行 | 最新状態での問題検知 | Mainが壊れるリスクあり |
| 定期的なCI | 毎晩などスケジュール実行 | フレーキーテストの検出に有効 | 責任の所在が曖昧になりがち |
| 自動マージキュー | 最新Mainで変更を統合してCI | Mainの安定性を担保 | 実装コストと複雑性がある |
🛡 競合の緩和戦略とそのトレードオフ
- PRに対してMainの最新を取り込ませてからマージ:衝突回避だが他PRにブロッキング
- マージキューの導入:信頼性高いが待ち時間と実装の複雑さあり
- 定期CIでMainの品質を監視:一時的に壊れても許容する運用が必要
🐛 バグの原因と対策
- フレーキーテスト:
- 一貫性のない失敗を定期テストで可視化
- 無視せず、調査と修正対象とする
- ビルドの非決定性:
- 依存関係のバージョン変動やOSの差異などが原因
- 対策:依存のバージョン固定、本番同様の環境でテスト実行
まとめ
今後実践すべきことは、「CIの多層的な実行と、バグ混入リスクの見える化」です。
特に、自動化されたマージ前後のCIと定期的なCIによって、Mainブランチを常にグリーンに保ちつつ、競合やフレーキーテストによる問題を事前に検出する体制を整えるべきです。また、依存関係を固定し、本番と同じビルド手順をCIに組み込むことで、環境差によるトラブルも未然に防ぐことができます。これらの工夫によって、安定したリリースサイクルを築きましょう。
inputメモ
- ポイント
- 変更のライフサイクルにおいて、バグが混入する可能性のあるポイントの特定
- 競合する変更によってバグが混入されないことの保証
- 競合を緩和するテクニックの長所と短所の比較
- マージ前、マージ後、および定期的にCIを実行することで、変更のライフサイクルの全ての時点でバグを検出する
- 内容
- マージ前のCI
- 問題がMainブランチに追加されるのを阻止
- 全員のブロックを避けれる
- これだけではバグを見逃す
- Mainブランチとの分岐により、新しい変更を考慮できていない
- 依存関係のあるパッケージやライブラリのバージョン違い
- 発見されないフレーキーテストやアーティファクトの鼻づ路からの次のアーティファクトのビルドの微妙な違い
- マージ前とマージ後のCI
- 変更を最新のmainブランチと結合して、CIが成功してからマージすることを要求する
- 3つの選択肢
- Mainブランチ上でCIを定期的に実行する
- CIを定期的に実行する(毎晩とか)
- Mainブランチが一時的に壊れた状態になることを許容する
- 実行結果に対してどう対応するのかが大きな問題
- 責任が分散される
- 誰かに通知する必要がある
- Mainブランチにマージする前に、ブランチが最新であることを要求する
- 競合の変更が紛れ込むことを防げる
- PRがマージされるたびに他の全てのオープンなPRをブロックしてしまう
- 自動化を使って、マージする前に最新のMainブランチで変更のCIを再実行してからマージする
- マージ前に最後にもう一度CIを実行する自動化
- 自分のブランチと最新のMainの変更を結合する
- マージキュー
- CIが通るまでマージをブロックする
- マージ前のCIが実行されている間にMainブランチが変更されないようにする
- Mainブランチ上でCIを定期的に実行する
- あとはどこでバグが起きるか
- フレーキーテスト
- 定期的なテストはフレークを発見するのに効果的
- 無関係な誰かの作業を妨げることなく、非決定的な動作を特定して、きちんと処理・徹底的に調査されることに役立つ
- バグとビルド
- 原因
- 依存関係の変更
- ビルドにおける非決定性
- 最善の解決策は依存関係を常に固定すること
- システムテストで統合テスト環境をセットアップして実行する
- ビルドがいつ行われるかによって違いが生まれる
- ビルド環境によるOSなどのバージョンの異なる環境でのビルド
- 本番環境のビルドとデプロイに使用されるものと同じタスクをシステムテストで使用する
- 原因
- フレーキーテスト
- マージ前のCI
8章 簡単なデリバリーはバージョン管理から始まる
ポイント
- DORAメトリクス:DevOpsResearch and Assesment;ソフトウェア開発チームのパフォーマンスを評価する4つのキーメトリクス
- デプロイの頻度
- 変更のリードタイム
- サービス復旧時間
- 変更に伴う障害発生率
- 変更を速く取り込むことで早期かつ継続的に統合を進めることができる
- 存続期間の長いfeatureブランチを回避し、mainに頻繁にマージして戻すインクリメンタルアプローチを採用すると、CD全体が改善されるだけでなく、より優れたCIも提供される
inputメモ
9章 安全かつ信頼性のあるビルド
概要
本章では、継続的デリバリーにおける安全かつ信頼性の高いビルドの確立方法について解説しています。ビルドをコードとして管理し、明確なバージョニングと依存関係管理を通じて、再現性と一貫性のあるリリースプロセスを実現するための実践的な方法が示されています。
ポイント
✅ ビルドプロセスをコードとして定義し、自動化する
- ビルド手順は手動ではなくコードで明示的に記述し、CIパイプラインによって自動実行されるようにする。
- これにより、誰がどこでビルドしても同じアーティファクトが生成されることを保証できる。
- 専用のCDサービスやビルドツール(例:GitHub Actions, GitLab CI, ArgoCD)を活用する。
🧪 セマンティックバージョニング + ハッシュで一意に識別
| 種類 | 意味 |
|---|---|
| MAJOR | 互換性のない変更 |
| MINOR | 互換性のある新機能 |
| PATCH | 互換性のあるバグ修正 |
- 各リリースには一貫性のあるバージョン番号を割り当てることで、変更の性質を明確化。
- バージョン番号の付け忘れをCIで検知してビルド失敗にする工夫も必要。
- Gitハッシュやイメージダイジェストなどでアーティファクトを一意に識別できるようにする。
🔒 依存関係はバージョンを固定
-
latestや可変な依存関係は予期せぬバグの温床になる。 -
go.mod,package-lock.json,requirements.txtなどで、正確なバージョン・ハッシュを固定する。 - 外部のライブラリ更新によるビルド失敗や不整合を防ぐ。
🐳 一時的なビルド環境の利用(Ephemeral Builds)
- 毎回まっさらな環境でビルドすることで、ローカル状態やキャッシュに依存せずにビルドが再現可能に。
- Dockerなどのコンテナ技術を活用して軽量かつ高速に実現。
📄 リリースノートで変更の伝達
- リリースに含まれる変更点はリリースノートとして文書化し、ユーザや運用者に明確に伝える。
- バージョン番号とリリースノートはセットで管理する。
まとめ(今後実践すべきこと)
- すべてのビルド手順をスクリプトに落とし込み、自動化を徹底する。
- セマンティックバージョンとGitハッシュを用いた識別で、誰がどこで再ビルドしても同じ成果物を得られる仕組みを構築する。
- 依存関係を固定し、再現性の高いビルドを保証する。
- CDパイプライン上で、バージョン忘れやビルド手順の逸脱を自動で検知できるようにする。
これらを実践することで、安全性・再現性・可観測性の高い継続的デリバリーが実現されます。
inputメモ
- ポイント
- ビルドプロセスをコードとして定義し、ビルド専用サービスを利用して自動化することで、ビルドの安全性を高める方法
- セマンティックバージョニングとハッシュを使用して、アーティファクトを明確かつ一意に識別する方法
- 依存関係を特定の一位のバージョンに固定することで、依存関係から予期せぬバグを排除する方法
- 内容
- 安全で信頼性の高いビルドの特徴
- 常にリリース可能
- CIパイプラインを駆使して、コードベースをリリース可能な状態に保つ
- 自動ビルド
- アーティファクトの構築に必要な全ての手順をスクリプトで定義する
- スクリプトの実行は手動ではなく自動的にトリガーされる
- コードとしてビルドする
- ソフトウェアを定義するプレーンテキストデータの一部として、ビルドの構成を定義する
- ソースコードからどのようにしてアーティファクトが生成されるかをコードとして定義
- CDサービスを利用する
- ビルドのトリガーと実行方法の一貫性を確保する
- 一時的なビルド環境
- エフェメラル(一時的な環境)でビルド処理の間のみ存在して再利用されrないビルド環境を使う
- コンテナは、軌道とは気を非常に高速に行えるため適している
- セマンティックバージョニング
- 課題:新しいバージョンを作成しつつも以前のバージョンも引き続き使用可能にする必要がある
- バージョン間で何が変更されたかをハイレベルな情報として伝達できるように、ソフトウェアにバージョンを割り当てる方法を定義
- Major:工法互換性のない変更が行われると上がる
- Minor:新しい工法互換性のある機能が追加されると上がる
- Patch:工法互換性のある修正が追加されると上がる
- →サービスのリリースにおける影響度の違いを区別する
- リリースノート
- 利用者が知っておくべき全ての詳細な変更をリスト化したもの
- バージョン番号を変更することを忘れるリスクもあるため、その場合はパイプラインが失敗するようにする
- ビルド時の依存関係のバグ
- 依存関係への変更による被害を確実に防ぐ最善の方法は、特定のバージョンとして明示的に指定すること
- ハッシュ値を使った明確な識別子でもバージョン管理ができる
- 常にリリース可能
- 安全で信頼性の高いビルドの特徴
X章 Template
hoge