Googleのソフトウェアエンジニアリング

―持続可能なプログラミングを支える技術、文化、プロセス

[cover photo]
TOPICS
System/Network
発行年月日
PRINT LENGTH
684
ISBN
978-4-87311-965-6
原書
Software Engineering at Google
FORMAT
Print PDF EPUB
Ebook
4,840円
Ebookを購入する
Print
4,840円

Googleの現役ソフトウェアエンジニアたちが、超大規模ソフトウェアの開発と保守を長期的に支えてきたGoogle社内の多様なベストプラクティスを、文化、プロセス、ツールの側面からこの一冊に凝縮。時間と変化、規模と成長、トレードオフとコストという3つの基本原理に沿って、コードを持続可能にする方法論を紐解きます。「謙虚、尊敬、信頼」、心理的安全性、ダイバーシティとインクルージョンなど公正を重んじる文化から、コードレビューやテスト構成法など人間の行動を規定するプロセス、継続的インテグレーションや大規模変更システムなど変化への対応を支援する自動化ツールの基盤技術まで、Googleが試行錯誤を経て獲得した教訓を余すところなく紹介しています。経済学、心理学、マネジメント論などを背景にした人間への深い洞察をふまえ、データ駆動かつトレードオフから導かれる、定量的かつ定性的な決定プロセスも解説。Googleの成長力の源泉を理解でき、得られる知見は、学生から組織の意思決定者、小規模スタートアップからデジタルトランスフォーメーション(DX)を目指す大企業まで、幅広く活用できます。

正誤表

ここで紹介する正誤表には、書籍発行後に気づいた誤植や更新された情報を掲載しています。以下のリストに記載の年月は、正誤表を作成し、増刷書籍を印刷した月です。お手持ちの書籍では、すでに修正が施されている場合がありますので、書籍最終ページの奥付でお手持ちの書籍の刷版、刷り年月日をご確認の上、ご利用ください。

第3刷までの修正

2023年3月更新

■P.511 訳注11
【誤】多項式時間O(nk)
【正】多項式時間O(n^k)
※「k」を上付き文字に

■P.511 訳注11
【誤】解の検証はできても解を得ることはできない問題
【正】解の検証はできても解を得ることはできないと予想されている問題

目次

監訳者まえがき
序文
はじめに

第1部 主題

1章 ソフトウェアエンジニアリングとは何か
    1.1 時間と変化
        1.1.1 Hyrumの法則
        1.1.2 例:ハッシュの順序付け
        1.1.3 「何も変化しない」状態をとにかく目指すのはどうか
    1.2 スケールと効率
        1.2.1 スケールしないポリシー
        1.2.2 よくスケールするポリシー
        1.2.3 例:コンパイラーのアップグレード
        1.2.4 左への移動
    1.3 トレードオフとコスト
        1.3.1 例:ホワイトボードマーカー
        1.3.2 意思決定への入力
        1.3.3 例:分散ビルド
        1.3.4 例:時間とスケールの間での決定
        1.3.5 決定を再考すること、間違うこと
    1.4 ソフトウェアエンジニアリング対プログラミング
    1.5 結論
    1.6 要約

第2部 文化

2章 チームでうまく仕事をするには
    2.1 自分のコードを隠すのを手伝ってはくれないか
    2.2 天才神話
    2.3 隠蔽は有害とみなされる
        2.3.1 早期発見
        2.3.2 バス係数
        2.3.3 進捗ペース
        2.3.4 要するに、隠れるな
    2.4 チームが全て
        2.4.1 社会交流の三本柱
        2.4.2 何故三本柱に意味があるのか
        2.4.3 謙虚、尊敬、信頼の実践
        2.4.4 非難なきポストモーテム文化
        2.4.5 Google的であること
    2.5 結論
    2.6 要約

3章 知識共有
    3.1 学びを阻む課題
    3.2 哲学
    3.3 舞台を整える:心理的安全性
        3.3.1 メンター制度
        3.3.2 大規模集団での心理的安全性
    3.4 自分の知識を発展させる
        3.4.1 質問を尋ねよ
        3.4.2 文脈を理解せよ
    3.5 質問をスケールさせる:コミュニティへの質問
        3.5.1 グループチャット
        3.5.2 メーリングリスト
        3.5.3 YAQS:Q&Aプラットフォーム
    3.6 自分の知識をスケールさせる:教えられるものは常にある
        3.6.1 オフィスアワー
        3.6.2 テックトークと講習
        3.6.3 ドキュメンテーション
        3.6.4 コード
    3.7 組織の知識をスケールさせる
        3.7.1 知識共有の文化を養う
        3.7.2 カノニカルな情報源の確立
        3.7.3 情報の輪に参加し続ける
    3.8 リーダビリティ:コードレビューを通じての標準化されたメンター制度
        3.8.1 リーダビリティプロセスとは何か
        3.8.2 何故このプロセスがあるのか
    3.9 結論
    3.10 要約

4章 公正のためのエンジニアリング
    4.1 バイアスこそがデフォルト状態である
    4.2 ダイバーシティの必要性を理解する
    4.3 多文化理解の能力を育む
    4.4 多様性を行動可能なものにする
    4.5 一本槍のアプローチは退けよ
    4.6 確立されたプロセスを疑え
    4.7 「価値観」対「結果」
    4.8 好奇心を持って突き進め
    4.9 結論
    4.10 要約

5章 チームリーダー入門
    5.1 マネージャーとテックリード(とその両方)
        5.1.1 エンジニアリングマネージャー
        5.1.2 テックリード(TL)
        5.1.3 テックリードマネージャー(TLM)
    5.2 IC役職からリーダーシップ役職への異動
        5.2.1 恐れるべき唯一のものは……えっと、全てだ
        5.2.2 サーバントリーダーシップ
    5.3 エンジニアリングマネージャー
        5.3.1 マネージャーとは四文字単語である
        5.3.2 今日のエンジニアリングマネージャー
    5.4 アンチパターン
        5.4.1 アンチパターン:押しに弱い者を採用する
        5.4.2 アンチパターン:成績の悪い者を無視する
        5.4.3 アンチパターン:人間的問題を無視する
        5.4.4 アンチパターン:全員の友人になる
        5.4.5 アンチパターン:採用基準で妥協する
        5.4.6 アンチパターン:自分のチームを子供のように扱う
    5.5 建設的パターン
        5.5.1 エゴを捨てよ
        5.5.2 禅の老師となれ
        5.5.3 触媒となれ
        5.5.4 障害を取り除け
        5.5.5 先生かつメンターになれ
        5.5.6 明確なゴールを設定せよ
        5.5.7 正直であれ
        5.5.8 満足度を追跡調査せよ
    5.6 予期しない質問
    5.7 他のヒントや秘訣
    5.8 人は植物のようなものである
        5.8.1 「内発的動機付け」対「外発的動機付け」
    5.9 結論
    5.10 要約

6章 スケールするリーダー
    6.1 いつでも決定せよ
        6.1.1 飛行機の比喩
        6.1.2 目隠しを特定せよ
        6.1.3 鍵となるトレードオフを特定せよ
        6.1.4 決定し、それから反復せよ
    6.2 いつでも立ち去れ
        6.2.1 あなたのミッション:「自動運転」チームを構築せよ
        6.2.2 問題空間の分割
    6.3 いつでもスケールせよ
        6.3.1 成功の周期
        6.3.2 「重要」対「緊急」
        6.3.3 ボールを落とすことを学べ
        6.3.4 自分のエネルギーを保護する
    6.4 結論
    6.5 要約

7章 エンジニアリング生産性の計測
    7.1 何故エンジニアリング生産性を計測すべきなのか
    7.2 トリアージ:そもそも計測するほどの価値があるか
    7.3 ゴールとシグナルを伴う、意味のあるメトリクスを選ぶ
    7.4 ゴール
    7.5 シグナル
    7.6 メトリクス
    7.7 メトリクスの検証にデータを用いる
    7.8 行動に出ることと結果の追跡
    7.9 結論
    7.10 要約

第3部 プロセス

8章 スタイルガイドとルール
    8.1 何故ルールを設けるのか
    8.2 ルールを作る
        8.2.1 指導原則
        8.2.2 スタイルガイド
    8.3 ルールを変更する
        8.3.1 プロセス
        8.3.2 スタイル調停者
        8.3.3 例外
    8.4 ガイダンス
    8.5 ルールを適用する
        8.5.1 エラーチェッカー
        8.5.2 コードフォーマッター
    8.6 結論
    8.7 要約

9章 コードレビュー
    9.1 コードレビューのフロー
    9.2 Googleでのコードレビューはどのように機能しているか
    9.3 コードレビューの恩恵
        9.3.1 コードの正しさ
        9.3.2 コードの意味の把握
        9.3.3 コードの一貫性
        9.3.4 心理的ならびに文化的な恩恵
        9.3.5 知識共有
    9.4 コードレビューのベストプラクティス
        9.4.1 礼儀正しく、かつプロフェッショナルになれ
        9.4.2 小さな変更を書け
        9.4.3 良い変更説明を書け
        9.4.4 レビュアーの人数は最小限にとどめよ
        9.4.5 可能な場合は自動化せよ
    9.5 コードレビューの類型
        9.5.1 グリーンフィールドコードレビュー
        9.5.2 挙動の変更、改善、最適化
        9.5.3 バグ修正とロールバック
        9.5.4 リファクタリングと大規模変更
    9.6 結論
    9.7 要約

10章 ドキュメンテーション
    10.1 何がドキュメンテーションとして適格か
    10.2 何故ドキュメンテーションが必要なのか
    10.3 ドキュメンテーションはコードのようなものである
    10.4 対象読者を認識せよ
        10.4.1 対象読者の類型
    10.5 ドキュメンテーションの類型
        10.5.1 リファレンスドキュメンテーション
        10.5.2 デザインドック
        10.5.3 チュートリアル
        10.5.4 概念的ドキュメンテーション
        10.5.5 ランディングページ
    10.6 ドキュメンテーションのレビュー
    10.7 ドキュメンテーション哲学
        10.7.1 誰が、何を、いつ、どこで、何故
        10.7.2 始まり、中盤、終わり
        10.7.3 優れたドキュメンテーションの特徴的要素
        10.7.4 ドキュメントを廃止する
    10.8 テクニカルライターが必要なのはどんなときか
    10.9 結論
    10.10 要約

11章 テスト概観
    11.1 何故テストを書くのか
        11.1.1 Googleウェブサーバーの物語
        11.1.2 現代的開発速度でのテスト
        11.1.3 書き、実行し、反応する
        11.1.4 コードをテストする利点
    11.2 テストスイートを設計する
        11.2.1 テスト規模
        11.2.2 テスト範囲
        11.2.3 Beyoncéルール
        11.2.4 コードカバレッジについてのメモ
    11.3 Google規模でのテスト
        11.3.1 大規模テストスイートの落とし穴
    11.4 Googleでのテストの歴史
        11.4.1 オリエンテーション講習
        11.4.2 テスト認定プログラム
        11.4.3 トイレでのテスト
        11.4.4 今日のテスト文化
    11.5 自動テストの限界
    11.6 結論
    11.7 要約

12章 ユニットテスト
    12.1 保守性の重要さ
    12.2 脆いテストを防ぐ
        12.2.1 変化しないテストを目指す
        12.2.2 公開API経由のテスト
        12.2.3 相互作用ではなく、状態をテストせよ
    12.3 明確なテストを書く
        12.3.1 テストは完全かつ簡潔にせよ
        12.3.2 メソッドではなく、挙動をテストせよ
        12.3.3 テストにロジックを入れるな
        12.3.4 明確な失敗メッセージを書け
    12.4 テストとコード共有:DRYではなくDAMP
        12.4.1 共有値
        12.4.2 初期設定の共有
        12.4.3 ヘルパーメソッドと検証メソッドの共有
        12.4.4 テストインフラストラクチャーを定義する
    12.5 結論
    12.6 要約

13章 テストダブル
    13.1 テストダブルの、ソフトウェア開発への影響
    13.2 Googleでのテストダブル
    13.3 基本概念
        13.3.1 テストダブルの例
        13.3.2 シーム
        13.3.3 モッキングフレームワーク
    13.4 テストダブル利用のためのテクニック
        13.4.1 フェイキング
        13.4.2 スタビング
        13.4.3 インタラクションテスト
    13.5 本物の実装
        13.5.1 分離より現実に即することを優先せよ
        13.5.2 いつ本物の実装を使うべきか決める方法
    13.6 フェイキング
        13.6.1 何故フェイクが重要なのか
        13.6.2 どんな場合にフェイクが書かれるべきか
        13.6.3 フェイクの忠実性
        13.6.4 フェイクはテストされるべきである
        13.6.5 フェイクが利用できない場合はどうすべきか
    13.7 スタビング
        13.7.1 スタビングを使いすぎることによる危険
        13.7.2 スタビングが適切なのはどんな場合か
    13.8 インタラクションテスト
        13.8.1 インタラクションテストよりステートテストを優先せよ
        13.8.2 インタラクションテストが適切なのはどんな場合か
        13.8.3 インタラクションテストのベストプラクティス
    13.9 結論
    13.10 要約

14章 大規模テスト
    14.1 大規模テストとは何か
        14.1.1 忠実性
        14.1.2 ユニットテストでよくある不足部分
        14.1.3 何故大規模テストを備えないのか
    14.2 Googleの大規模テスト
        14.2.1 大規模テストと時間
        14.2.2 Googleスケールでの大規模テスト
    14.3 大テストの構造
        14.3.1 テスト対象システム
        14.3.2 テストデータ
        14.3.3 検証
    14.4 大規模テストの類型
        14.4.1 相互に作用し合う1つ以上のバイナリの機能テスト
        14.4.2 ブラウザーとデバイスのテスト
        14.4.3 パフォーマンス、負荷、ストレスのテスト
        14.4.4 デプロイ設定のテスト
        14.4.5 探索的テスト
        14.4.6 A/B差分リグレッションテスト
        14.4.7 ユーザー受け入れテスト(UAT)
        14.4.8 プローバーとカナリア分析
        14.4.9 障害復旧とカオスエンジニアリング
        14.4.10 ユーザー評価
    14.5 大テストと開発者ワークフロー
        14.5.1 大テストの作成
        14.5.2 大テストの実行
        14.5.3 大規模テストのオーナーとなる
    14.6 結論
    14.7 要約

15章 廃止
    15.1 何故廃止するのか
    15.2 何故廃止はこれほど難しいのか
        15.2.1 設計中の廃止
    15.3 廃止の類型
        15.3.1 勧告的廃止
        15.3.2 強制的廃止
        15.3.3 廃止の警告
    15.4 廃止プロセスを管理する
        15.4.1 プロセスのオーナー
        15.4.2 マイルストーン
        15.4.3 廃止ツール環境
    15.5 結論
    15.6 要約

第4部 ツール

16章 バージョンコントロールとブランチ管理
    16.1 バージョンコントロールとは何か
        16.1.1 何故バージョンコントロールが重要なのか
        16.1.2 「中央集権的VCS」対「分散VCS」
        16.1.3 信頼できる情報源
        16.1.4 「バージョンコントロール」対「依存関係管理」
    16.2 ブランチ管理
        16.2.1 進行中の作業はブランチに似ている
        16.2.2 開発ブランチ
        16.2.3 リリースブランチ
    16.3 Googleでのバージョンコントロール
        16.3.1 単一バージョン
        16.3.2 シナリオ:複数の利用可能バージョン
        16.3.3 「単一バージョン」ルール
        16.3.4 存続期間の長いブランチを(ほとんど)なくす
        16.3.5 リリースブランチについてはどうか
    16.4 モノリポ
    16.5 バージョンコントロールの未来
    16.6 結論
    16.7 要約

17章 Code Search
    17.1 Code SearchのUI
    17.2 グーグラーはどのようにCode Searchを使うか
        17.2.1 どこに
        17.2.2 何を
        17.2.3 どのように
        17.2.4 何故
        17.2.5 誰が、いつ
    17.3 何故独立したウェブツールなのか
        17.3.1 スケール
        17.3.2 設定作業不要のグローバルコードビュー
        17.3.3 専門化
        17.3.4 他の開発者ツールとの統合
        17.3.5 API公開
    17.4 設計上でのスケールの影響
        17.4.1 検索クエリーのレイテンシー
        17.4.2 インデックスのレイテンシー
    17.5 Googleの実装
        17.5.1 検索インデックス
        17.5.2 ランキング
    17.6 選択されたトレードオフ
        17.6.1 完全性:ヘッドにあるリポジトリー
        17.6.2 完全性:「全部」対「最も関連性の高い結果」
        17.6.3 完全性:「ヘッド」対「ブランチ」対「全履歴」対「ワークスペース」
        17.6.4 表現力:「トークン」対「部分文字列」対「正規表現」
    17.7 結論
    17.8 要約

18章 ビルドシステムとビルド哲学
    18.1 ビルドシステムの目的
    18.2 ビルドシステムがないと何が起こるか
        18.2.1 でも必要なのはコンパイラーだけ!
        18.2.2 シェルスクリプトは救援となるか
    18.3 現代的ビルドシステム
        18.3.1 依存関係こそ全て
        18.3.2 タスクベースのビルドシステム
        18.3.3 アーティファクトベースのビルドシステム
        18.3.4 分散ビルド
        18.3.5 時間、スケール、トレードオフ
    18.4 モジュールと依存関係を扱う
        18.4.1 粒度の細かいモジュールの利用と1:1:1ルール
        18.4.2 モジュールの可視性の最小化
        18.4.3 依存関係の管理
    18.5 結論
    18.6 要約

19章 GoogleのコードレビューツールCritique
    19.1 コードレビュー用ツール環境の原則
    19.2 コードレビューのフロー
        19.2.1 通知
    19.3 第1段階:コード変更を作成する
        19.3.1 差分作成
        19.3.2 解析結果
        19.3.3 緊密なツール統合
    19.4 第2段階:レビューをリクエストする
    19.5 第3段階と第4段階:コード変更の理解と、コード変更へのコメント付加
        19.5.1 コメント付加
        19.5.2 コード変更の状態を理解する
    19.6 第5段階:コード変更の承認(コード変更のスコア付け)
    19.7 第6段階:コード変更のコミット
        19.7.1 コミット後:履歴の追跡
    19.8 結論
    19.9 要約

20章 静的解析
    20.1 効果的な静的解析の特徴
        20.1.1 スケーラビリティ
        20.1.2 ユーザビリティ
    20.2 静的解析を機能させる際に鍵となる教訓
        20.2.1 開発者の幸福を重視せよ
        20.2.2 静的解析を中心的な開発者ワークフローの一部とせよ
        20.2.3 ユーザーにコントリビュートする権限を与えよ
    20.3 Tricorder:Googleの静的解析プラットフォーム
        20.3.1 統合されているツール
        20.3.2 統合されているフィードバック経路
        20.3.3 修正提案
        20.3.4 プロジェクトごとのカスタマイズ機能
        20.3.5 リポジトリー提出前処理
        20.3.6 コンパイラー統合
        20.3.7 コードの編集中と閲覧中の静的解析
    20.4 結論
    20.5 要約

21章 依存関係管理
    21.1 何故依存関係管理がそれほど難しいのか
        21.1.1 競合する要件群とダイアモンド依存関係
    21.2 依存関係のインポート
        21.2.1 互換性の約束
        21.2.2 インポートを行う際に考慮すべき事項
        21.2.3 Googleはどのように依存関係のインポートを扱っているか
    21.3 理論上の依存関係管理
        21.3.1 何も変化しない(別名:静的依存関係モデル)
        21.3.2 セマンティックバージョニング
        21.3.3 バンドルされたディストリビューションのモデル
        21.3.4 リブアットヘッド
    21.4 SemVerの制限
        21.4.1 SemVerは過大に制約を課す可能性がある
        21.4.2 SemVerは過大に約束をする可能性がある
        21.4.3 動機
        21.4.4 最小バージョン選択
        21.4.5 では、SemVerは機能するのか
    21.5 無限のリソースがある場合の依存関係管理
        21.5.1 依存関係のエクスポート
    21.6 結論
    21.7 要約

22章 大規模変更
    22.1 大規模変更とは何か
    22.2 誰がLSCを扱うのか
    22.3 アトミックなコード変更への障壁
        22.3.1 技術的制約
        22.3.2 マージ競合
        22.3.3 幽霊の出る墓場をなくす
        22.3.4 異種多様性
        22.3.5 テスト
        22.3.6 コードレビュー
    22.4 LSCインフラストラクチャー
        22.4.1 ポリシーと文化
        22.4.2 コードベースの内部的知識
        22.4.3 コード変更の管理
        22.4.4 テスト
        22.4.5 言語サポート
    22.5 LSCプロセス
        22.5.1 認可
        22.5.2 コード変更の作成
        22.5.3 シャード分割とリポジトリーへのコード提出
        22.5.4 クリーンアップ
    22.6 結論
    22.7 要約

23章 継続的インテグレーション
    23.1 CIの概念
        23.1.1 高速なフィードバックループ
        23.1.2 自動化
        23.1.3 継続的テスト
        23.1.4 CIの課題
        23.1.5 密閉されたテスト
    23.2 GoogleにおけるCI
        23.2.1 CIケーススタディ:Google Takeout
        23.2.2 だがCIを行う余裕がない
    23.3 結論
    23.4 要約

24章 継続的デリバリー
    24.1 Googleでの継続的デリバリーのイディオム
    24.2 速度はチームスポーツである:デプロイを管理可能な部分へ分割する方法
    24.3 変更を分離して評価する:フラグによる機能の保護
    24.4 アジャイル性を目指す:リリーストレインの構成
        24.4.1 完璧なバイナリなどない
        24.4.2 リリースの締め切りは守れ
    24.5 品質とユーザー重視:使われるものだけをリリースせよ
    24.6 左への移動:データ駆動の決定を早期に行う
    24.7 チームの文化を変える:デプロイに規律を組み込む
    24.8 結論
    24.9 要約

25章 サービスとしてのコンピュート
    25.1 コンピュート環境を手なずける
        25.1.1 トイルの自動化
        25.1.2 コンテナ化とマルチテナンシー
        25.1.3 まとめ
    25.2 マネージドコンピュート用ソフトウェアを書く
        25.2.1 障害に備えたアーキテクチャー設計
        25.2.2 「バッチ」対「提供」
        25.2.3 状態管理
        25.2.4 サービスへの接続
        25.2.5 単発コード
    25.3 長期的にスケールするCaaS
        25.3.1 抽象化としてのコンテナ
        25.3.2 1つのサービスは全てを統べる
        25.3.3 リポジトリーへ提出される設定
    25.4 コンピュートサービスを選択する
        25.4.1 「中央集権化」対「カスタマイズ」
        25.4.2 抽象化のレベル:サーバーレス
        25.4.3 パブリック対プライベート
    25.5 結論
    25.6 要約

第5部 結論
あとがき
訳者あとがき
索引