SlideShare a Scribd company logo
1 of 56
『継続的デリバリー』 読書会
     第13章
コンポーネントや依存関係を管理す
       る
    大崎的デリバリー
       @favril
13.1 導入(1/2)
• 本章で説明する内容
 – コンテキストが切り替わるときにもアプリ
   ケーションを常にリリース可能に保つための
   方法
 – 巨大なアプリケーションのコンポーネント化
  • コンポーネント分割の方法
  • 複数コンポーネントからなる巨大プロジェクトの
    ビルド方法
  • その管理方法
13.1 導入(2/2)
• 言葉の定義
 – コンポーネント
  •   それなりに大規模なコード
  •   よく作られたAPIを提供
  •   別の実装にも切り替えられる
  •   モジュールとも呼ぶ
  •   Windows: DLL, UNIX: SOファイル, Java: JARファイル..
 – コンポーネントベースのシステム
  • いくつかの部品に分解可能
  • それぞれのふるまいが定義されている
  • 他のコンポーネントと最小限のやりとり
13.2 アプリケーションをリリース
      可能な状態に保つ(1/3)
• 通常、下記の手法で開発を行うとリリー
  ス間隔が長くなりがち
                      リリー
trunk                 ス
        開発   bugfix               開発

                      release 1

• 「常にリリース可能な状態」を保ててい
  ない
13.2 アプリケーションをリリース
      可能な状態に保つ(2/3)
• バージョン管理システムのブランチを使うこと
  で、メインラインを常にリリース可能な状態に保
  つことが可能
               リリー
 trunk         ス
                     マー
                     ジ
 feature 1                 feature 2
             開発 / bugfix               開発

• しかし、これはあくまで次善の策
 –  ブランチ上での作業が継続的に統合されていない
13.2 アプリケーションをリリース
      可能な状態に保つ(3/3)
• 全員がメインライン上で作業する方式を
  推奨
• ただし、常にリリース可能状態は保つ
 – そのための4つの作戦
  • 新機能は完成するまで隠す
  • すべての変更を細かくインクリメンタルに行い、
    個々の変更をすべてリリース可能な状態にする
  • 抽象化によるブランチを使って、大規模な変更を
    コードベースに加える
  • 変更の頻度が異なる部分をコンポーネント化し
    て、アプリケーションから切り離す
13.2.1 新機能は完成するまで隠せ
           (1/2)
• 開発中の機能を本番に反映しつつ、それ
  を利用できないようにする
 – 開発中の機能に個別のURIを与え、機能のリ
   リースまではWebサーバの設定でアクセス拒
   否
 – 古い機能と、開発中の新しい機能を設定で切
   り替えれるように作る
13.2.1 新機能は完成するまで隠せ
           (2/2)
• 未完成の機能もメインラインで開発するメ
  リット
 – システム全体の統合やテストをありのままの状態
   でいつでも実行できる
 – 依存関係の整理や統合のフェーズをプロジェクト
   の計画に含める必要がなくなる

• この方法での開発は
 – 準備や検討などそれなりに大変
 – 新機能を開発途中でもリリースできるという利点
   を考慮すると、その価値はある
 – ブランチ開発より優れている
13.2.2 すべての変更はインクリメン
          タルに(1/2)
• 大規模な変更を加えるとき、以下をやりがち
 – ブランチを作り
 – アプリが動かなくなるくらいがっつり変更を加え
 – その後、正しく動くように細かい部分を含めて修
   正する(メインラインにマージする)

 – 上記手法は、確かに開発を高速化するかもしれな
   い
 – が、すべて正しく修正するのは大変で難しい
 – したがって、変更量が大規模であればあるほど、
   実際はブランチを作るべきではない
13.2.2 すべての変更はインクリメン
          タルに(2/2)
• 大規模な変更を細かく分割して、小さな
  変更をインクリメンタルに進める
 – 要件を小さなタスクに分解していく過程と類
   似
 – 分析が重要
 – 間違いが尐なくなる
 – 作業をどう進めるか(本当に進めるべきか)
   を判断できる
 – いつでもやめれる(?)
13.2.3 抽象化によるブランチ
           (1/3)
• 大規模な変更を加えたいが、小さくてインク
  リメンタルな段階に分解できない場合
 – 1. 既存システムにおいて、変更したい部分を抽象
   化
 – 2. 既存システムをリファクタリングし、その抽象
   化レイヤを使うようにする
 – 3. 新しい実装をする(ただし、完成までは実行パ
   スに含まれないように)
 – 4. 抽象化レイヤを書き換え、新しい実装に処理を
   委譲
 – 5. 古い実装を削除
 – 6. 不要なら抽象化レイヤも削除
13.2.3 抽象化によるブランチ
           (2/3)
• この方法で困難な2点
 – 対象のコードベースから、エントリポイント
   を分離すること
 – 開発中の機能に対して施すべき変更を管理す
   ること
13.2.3 抽象化によるブランチ
           (3/3)
• アプリに大規模な変更を加えるとき、包
  括的な自動受け入れテストスイートの存
  在が重要
 – ユニットテストやコンポーネントテストは、
   この目的で使うには粒度が細か過ぎる
 – 業務的な機能が壊れないようにするための助
   けにならない
13.3 依存関係(1/2)
• ソフトウェアのある部分をビルドあるい
  は実行するために別の何かが必要
 – 大半のアプリは何らかの依存関係がある
 – 例えば、動作環境
  •   Java  JVM
  •   .NET  CLR
  •   Rails  Ruby, Rails
  •   C  C言語標準ライブラリ
13.3 依存関係(2/2)
• 言葉の定義
 – コンポーネントとライブラリ
   • ライブラリ
     – ソフトウェアパッケージの中で、自分たちで制御しようのないも
       の(どれを使うかの選択しかできない)
   • コンポーネント
     – ソフトウェアの部品としてアプリが依存しているもの
     – 自分達が開発する

 – ビルド時の依存関係と実行時の依存関係
   • ビルド時の依存関係
     – アプリをコンパイルしたときにあらわれるもの
   • 実行時の依存関係
     – アプリを実行して機能を使うときにあらわれる
13.3.1 依存地獄(1/3)
• 別名:DLL地獄
 – 実行時に発生するライブラリの依存関係
 – あるアプリケーションが、特定のバージョン
   の何かに依存しているのに、別のバージョン
   をデプロイしてしまった場合、あるいはそも
   そもデプロイしなかった場合に起こる
   • 例: 初期windowsは異なるバージョンのDLLを使うア
     プリの共存が不可能  .NET, GACで改善
   • 例: Linuxは命名規約で回避
13.3.1 依存地獄(2/3)
• OS全体の依存関係
 – 静的にコンパイルしたまともなアプリを使う
 – コンパイル時に依存関係を1つのアセンブリ
   にまとめれば実行時の依存関係はほぼなくな
   る
 – ただし、バイナリが肥大化するし、特定のOS
   バージョンに密結合するので、おすすめしな
   い
13.3.1 依存地獄(3/3)
• 動的言語の場合
 – 依存するフレームワークやライブラリも、ア
   プリと一緒に出荷することで依存関係を解決
   する
   • 例: Rails
• Javaの場合
 – あるクラスの複数のバージョンを同じJVM内
   で使えないという深刻な問題がある
 – OSGiフレームワーク形式を使って解決する
           JAR1 ver1
      アプリ                     JAR3

                JAR2   ver2
13.3.2 ライブラリを管理する
           (1/3)
• ビルドが再現性のあるものであることが
  重要
• 適切な方法が2つ
 – ライブラリもバージョン管理にチェックイン
   する
  • 最もシンプル
  • 小規模なプロジェクトならこれで十分
 – 使うライブラリを宣言した上でMaven, Ivyを使
   い、組織内のリポジトリからライブラリをダ
   ウンロードして使う
13.3.2 ライブラリを管理する
           (2/3)
• ライブラリチェックインの問題点
 – リポジトリの肥大化
 – 同一プラットフォーム上で、別のプロジェク
   トを共存させないといけなくなった場合

 – プロジェクト間の依存関係を手動で管理する
   のは厳しい
13.3.2 ライブラリを管理する
           (3/3)
• 依存関係の管理を自動化する仕組みを提供す
  るツール(Maven, Ivy)を使う
 – 必要なライブラリとそのバージョンを、プロジェ
   クトに設定できる
 – 他プロジェクトとの依存関係をよろしく解決して
   くれる

• 自前の成果物リポジトリを持つ
 – Artifactory, Nexusなど
 – 自社内のプロジェクトで、どのライブラリのどの
   バージョンが使えるか制御できる
13.4 コンポーネント
• なぜコードベースを複数のコンポーネン
  トに分割しないといけないのか?

• コンポーネント間の関係はどうやって管
  理すべきか?
13.4.1 コードベースをコンポーネン
       トに分割する方法(1/6)
• コンポーネントに分割することが、開発
  プロセスを効率化する理由
 – 1. 大きな問題を、より小さくわかりやすい問
   題に分割できる
 – 2. コンポーネントが、システム中の更新頻度
   が違う部分、ライフサイクルが違う部分をあ
   らわす
 – 3. ソフトウェアの設計や保守の段階で、その
   責務を明確化することにつながる
 – 4. ビルドプロセスやデプロイメントプロセス
   を最適化する際に、自由をくれる
13.4.1 コードベースをコンポーネン
       トに分割する方法(2/6)
• 大半のコンポーネントの特徴
 – 何らかの形式でAPIを公開していること
  • APIは、外部の協調オブジェクトとの情報交換を表
    している
  • また、結合度合いも表している


 – コンポーネント間の依存は考慮しないといけ
   ない
  • 結合が強いと、別々に分割して、個別にビルドや
    デプロイメントをするのが難しくなる
13.4.1 コードベースをコンポーネン
       トに分割する方法(3/6)
• コンポーネント化すべき場面
 – 1. コードベースの一部を個別にデプロイする必要がある
 – 2. コードベースをコアとプラグイン群に分割し、一部を別
   の実装に切り替えたり、ユーザ側での拡張性を高めたりし
   たい
 – 3. そのコンポーネントが別のシステムへのインタフェース
   を提供する
 – 4. コードのコンパイルとリンクに時間がかかる
 – 5. 開発ツールでプロジェクトを開くのに時間がかかる
 – 6. コードベースが大きくなりすぎて、1つのチームで手に
   負えない

 – 後半3点は著者の主観だが、すべて理由としては妥当だし、
   最後の項目は最も重要
13.4.1 コードベースをコンポーネン
       トに分割する方法(4/6)
• チームの力を最大限に発揮できるのは
 – 10人前後のメンバーで構成
 – 各自がコードベースの特定の部分を隅々まで
   知り尽くしている
  • 特定の部分:機能的な区切りでも、それ以外の何
    かの基準による区切でもよい
13.4.1 コードベースをコンポーネン
       トに分割する方法(5/6)
• 10人以上必要な場合
 – システムを疎結合なコンポーネントに分割し、
   チームも分割する
 – ただし、コンポーネント毎のチーム分けは勧めな
   い
  • 要件の分割はコンポーネントの境界と沿わない
  • コミュニケーションコストの浪費
  • プロジェクト全体で何がベストか見えなくなりがち
 – 各チームが1つのストーリーの流れを扱うのがよ
   い
  • 必要なコンポーネントはすべて手をいれられる権限を
    与える
  • 統合チームに責任を押し付けることがなくなる
13.4.1 コードベースをコンポーネン
       トに分割する方法(6/6)
• コンポーネント分割するにあたっての、強力
  でお手軽なツールは無い
 – 説明してきたより良い設計を考えるだけ
 – その際の罠
  • 何もかもコンポーネント化してしまうこと
  • 1つのコンポーネントにすべてを任せること

• コンウェイの法則
 – システムを設計する組織は、その組織のコミュニ
   ケーション構造をそっくりまねた設計を生み出す
  • チーム編成には注意
コンポーネントを使うからといって必
ずしもN層アーキテクチャになるわけ
       ではない
• N層アーキテクチャとは
 – アプリケーションを表示、業務処理、データ等、複数の階層で
   分割する分散アプリケーション設計手法
• メリット
 – 経験の浅い開発者が集まった巨大なチームでも密結合な泥団子
   を作らずにすむ
 – キャパシティやスケーラビリティの面で有利
• デメリット
 – 階層が物理的に離れている場合、リクエストを処理する待ち時
   間が増える
   • 複雑なキャッシュの仕組みの導入につながる
   • 保守やデバッグがしづらい
   • コードは理解しにくく、各層間の依存関係のせいで変更もしにくい
• N層化はコンポーネントベースの開発と同義ではなく、直交
  する概念
13.4.2 コンポーネントをパイプライ
         ン化する(1/4)
• 基本的には、何か変更がコミットされる
  たびに、すべてをビルドし、テストする
  のが良い
 – 時間がかかりすぎるようになったら、そのと
   き対応する
 – 巨大で複雑なシステムでも対応可能
13.4.2 コンポーネントをパイプライ
         ン化する(2/4)
• パイプラインに分割したほうがやりやすい場面
 – アプリケーションの一部が、他の部分とは異なるラ
   イフサイクルをたどる
 – アプリケーション内で機能的に分かれた部分をそれ
   ぞれ別チームが担当しており、個々のチームで専用
   のコンポーネントを使っている
 – あるコンポーネントが他とは異なる技術やビルドプ
   ロセスを使っている
 – 共有コンポーネントが他のプロジェクトでも使われ
   ている
 – あるコンポーネントが比較的安定しいて、変更頻度
   が低い
 – ビルドに時間がかかり、コンポーネントごとに分け
   た方が速い
13.4.2 コンポーネントをパイプライ
         ン化する(3/4)
• 各コンポーネントあるいはコンポーネン
  ト群のビルドには独自のパイプラインが
  必要
• パイプラインの動き
 – 必要に応じてコードをコンパイルする
 – ひとつあるいは複数のバイナリを、あらゆる
   環境へのデプロイメントに対応できるよう組
   み立てる
 – ユニットテストを実行する
 – 受け入れテストを実行する
 – 手動テストをする場面ではそれに対応する
13.4.2 コンポーネントをパイプライ
         ン化する(4/4)
• 各バイナリが自身のリリースプロセスを
  通過すれば、次のインテグレーションビ
  ルドに進む準備ができたことになる
• DLLやJARの単位でパイプラインを作るべき、
  と主張しているわけではない
• 運用するビルド数はできるだけ尐ない方
  がよい
13.4.3 インテグレーションパイプラ
          イン(1/3)
• 適切なバイナリを組み合わせてデプロイ
  用のパッケージを作成
• できあがったアプリケーションを疑似本
  番環境にデプロイしてスモークテストを
  実行
• 受け入れテストを実行

• 例、図13-1 (p.427)
13.4.3 インテグレーションパイプラ
          イン(2/3)
• デプロイメントパイプラインに関する一
  般原則2つ
 – 素早いフィードバック
 – ビルドの状況を関係者全員が見れる
  • 失敗した場合、なぜ失敗したかが正確にわかる必
    要
   – インテグレーションビルド側から、元になった各コンポ
     ーネントのバージョンをたどれる必要
   – コンポーネント開発側からも、どのバージョンのコンポ
     ーネントがインテグレーションパイプラインで成功した
     か見れる必要
13.4.3 インテグレーションパイプラ
          イン(3/3)
• インテグレーションパイプラインの実行間隔
  が離れていて、その間に複数のコンポーネン
  トに多くの変更があるのは好ましくない状況
 – どの変更がアプリを壊したのかわかりにくい

• 最もシンプルな解決策
 – 各コンポーネントのうまく動いているバージョン
   について、考えうるすべての組み合わせをビルド
   する
  • 人手が必要ない&賢いアルゴリズムを考える必要もな
    い
• 次善の策
 – スケジューリングを使って、定期的にビルドする
13.5 依存グラフを管理する
• 依存関係は、ライブラリやコンポーネン
  トも含めてバージョン管理しておくこと
  が重要
 – コンポーネント間の依存関係を図示した際は、
   無閉路有向グラフでなければならない
 – そうならない場合、特に閉路グラフになる場
   合は、依存関係に病的な問題がある
13.5.1 依存グラフを作成する
            (1/4)
• 例、図13-2 (p429)
 上流                レポート
                               下流
                   エンジン


  フレームワー                    資産管理アプ
               決済エンジン
    ク                       リケーション


    CDS        プライシング
  ライブラリ         エンジン
 他社
                    それぞれパイプラインを持っていて、
                    自身あるいは上流に変更があったら、
                    パイプラインが起動
13.5.1 依存グラフを作成する
           (2/4)
• この例のビルド時に起こりうるシナリオ
 – 1. 資産管理アプリケーションを変更
  • 資産管理アプリケーションだけ再ビルド
 – 2. レポートエンジンを変更
  • レポートエンジンを再ビルドし、すべてのテストを通す
  • その後、資産管理アプリケーションを再ビルド
 – 3. CDSプライシングライブラリに変更
  • プライシングエンジンの再ビルド
  • その後、資産管理アプリケーションの再ビルド
 – 4. フレームワークに変更
  • フレームワークを再ビルド
  • 直近の下流にあるすべての依存コンポーネントを再ビルド
  • 上記がすべてできたら、資産管理アプリケーションを再ビル
    ド
    – 1つでも失敗していたら、資産管理アプリケーションは再ビルド
      しない
13.5.1 依存グラフを作成する
           (3/4)
• 続き
 – 5. フレームワークとプライシングエンジンに
   変更
   • グラフ全体の再ビルドが必要
   • 理想は、すべてのビルドが成功すること
   • もし、決済エンジンのビルドが失敗したら?
       – 資産管理アプリケーションを新しいフレームワークでは
         ビルドできない
       – しかし、CDSプライシングライブラリは動作検証済みな
         ので、これだけ新しいバージョンで、資産管理アプリ
         ケーションをビルドしたい
          » が、そんなバージョンのプライシングエンジンは存
            在しない
13.5.1 依存グラフを作成する
           (4/4)
• この例の最も重要な制約は、
 – 資産管理アプリケーションをビルドする際に
   使えるフレームワークのバージョンが1つだ
   けということ
  • これは典型的な「菱形依存」
13.5.2 依存グラフをパイプライン化
          する(1/2)
• 図13-3 (p432)
  – フィードバックを早くするために、各プロジェク
    トのパイプライン内でコミットステージが完了し
    た時点で、依存プロジェクトのパイプラインを立
    ち上げる(受け入れテストの完了を待たない)
  – すべてのトリガーは自動(手動テスト、本番デプ
    ロイを除く)
  – アプリケーションのあるバージョンをビルドする
    ときに使った各コンポーネントをたどれることが
    重要
  – どのバージョンのコンポーネントの組み合わせが
    統合に成功したかを知れる
• 図13-4, 図13-5 (p433)
13.5.2 依存グラフをパイプライン化
          する(2/2)
• 大幅な変更をコンポーネントに加える必要がある場合
  は新しいリリースを作る
 – 図13-6 (p434)
 – APIの後方互換性がない新バージョンを開発する際、開発
   をはじめる前に1.0系のリリース用ブランチを作ってから
   開発する
 – 下流の資産管理アプリケーションは、1.0ブランチから
   作ったバイナリを使える
 – Bugfixは1.0で行い、trunkにマージする
 – 資産管理アプリケーションが新バージョンに対応した時点
   で、trunkに切り替える

 – 継続的インテグレーションの観点では次善の策
 – だが、コンポーネントが疎結合であることが、統合を先延
   ばしにしたときのリスクを抑えている
13.5.3 いつビルドすべきか?
           (1/2)
• 上流の依存を最新版に保ち、最新の機能
  とバグフィックスを使いたいが、すべて
  の依存を最新にする統合にはコストがか
  かる
 – 動かなくなった部分を修正しないといけない
   ので
13.5.3 いつビルドすべきか?
           (2/2)
• 依存関係更新の頻度を決める際の検討事項
 – 依存コンポーネントの最新版をどの程度信頼できるか?
   • 数が尐なく、自分たちで開発しているなら、修正も素早く行え
     るので、頻繁に統合すべき
   • 社内の別のチームの場合、個別のパイプラインにすべき。追従
     するか、しないかを都度判断できる
   • サードパーティのライブラリは、明らかな必要性があるときの
     みにすべき
 – コンポーネントの変更にどの程度関与でき、どの程度知れ
   るかがポイント
   • 程度が低いほど、信頼性は下がる
 – 基本的には、依存コンポーネントの新バージョンの統合を
   継続的に行えるのがベスト
   • コストがかかる
   • 素早いフィードバックを得るには、統合を頻繁に行う必要があ
     る
   • が、頻繁に行うと自分たちの関与しないところで問題が発生し
     うる
   • 両者のバランスをとるための解決策の1つとして「慎重な楽天
13.5.4 慎重な楽天主義
• 依存グラフに、3つの状態を導入
 – static, gruarded, fluid
 – staticな上流の依存を変更しても新しいビルドは
   引き起こさない
 – fluidな上流の依存が変更されたら常にビルドを実
   行する
   • ビルドが失敗すると、依存コンポーネントは
     「guarded」になり、動作確認済みの既知のバージョン
     に固定される
      – guardedな依存はstaticと同じふるまいをする
      – 開発チームには通知が飛ぶ
 – 例、図13-7 (p437)
13.5.5 循環依存
• 最もやっかいな問題
 – 依存グラフに閉路が含まれる場合に起こる
 – 一番シンプルな例
  • コンポーネントAはコンポーネントBに依存してい
    るが、
  • コンポーネントBもコンポーネントAに依存してい
    る
  • 最初の起動時に致命的な問題

  • プロジェクトの開始時点では循環していない
  • おすすめしないが解決策は図13-8 (p438)
13.6 バイナリを管理する
• 成果物リポジトリを使うときの一般的な
  法則
• ファイルシステムだけを使ってバイナリ
  管理する方法
• Mavenを使って依存関係を管理する方法
13.6.1 成果物リポジトリの活用法
           (1/3)
• 成果物リポジトリに再生成できないもの
  を含めてはいけない
 – 気兼ねなく削除でき、それによって取り戻せ
   ない何かがあってはいけない
 – あらゆるバイナリを再生成するために必要な
   すべてをバージョン管理する
13.6.1 成果物リポジトリの活用法
           (2/3)
• バイナリをどの程度保持し続けるにし
  ろ、ハッシュ(バイナリのMD5)も保持して
  おく必要がある
 – それによりバージョン管理システム内のどの
   リビジョンを使って作成したバイナリかわか
   る
 – 保存は、ビルドシステムでもよいし、バー
   ジョン管理システムでもよい
  • ハッシュ管理は構成管理の一貫として重要な位置
    を占める
13.6.1 成果物リポジトリの活用法
           (3/3)
• 最もシンプルな成果物リポジトリ
 – ディスク上のディレクトリ構造として構成し
   たもの
  • バイナリと、それを作るソースのバージョンを関
    連づけられる必要がある
  • パイプラインごとにディレクトリを作り、その中
    でビルド番号ごとのディレクトリを作る
  • ビルドの成果物はすべてこのディレクトリに保管
    する
13.6.2 デプロイメントパイプライン
  と成果物リポジトリのやりとり
           (1/2)
• デプロイメントパイプラインで以下を実装
 – ビルドの成果物を成果物リポジトリに保存
 – 後で使うときに、それを取り出す
• コンパイル、ユニットテスト、受け入れテスト、
  手動受け入れテスト、本番 というパイプライン
  を例とする
 – コンパイルでバイナリができるので、それを成果物
   リポジトリに保存
 – ユニットテスト/受け入れテストでは、このバイナ
   リを取得してテストを行う。レポートは成果物リポ
   ジトリに保存
 – 手動受け入れテストでは、このバイナリを取得し、
   テスト環境にデプロイして手動テストする
 – リリースでは、このバイナリを本番環境にデプロイ
   する
13.6.2 デプロイメントパイプライン
  と成果物リポジトリのやりとり
           (2/2)
• 成果物リポジトリは、
 – 共有ファイルシステム上に保存する方法
 – Nexus, Artifactoryといったリポジトリ管理ツー
   ルも使える
13.7 Mavenを使って依存関係を管理
            する
• Maven
  – Javaプロジェクト用のビルド管理システム
  – 依存関係の管理が得意
  – 外部のライブラリとの依存関係/アプリケー
    ション内のコンポーネント間の依存関係 を
    抽象化してどちらもほぼ同様に扱えるように
    する

  –略
13.8 まとめ
• チームでの開発をできる限り効率的に進めつ
  つ、アプリケーションを常にリリース可能な
  状態に保つ方法を議論
 – すべての変更を小さくインクリメンタルなものに
   分割し、尐しずつメインラインにチェックインす
   る方法
 – アプリケーション自体をコンポーネントに分割す
   る方法
  • 基本的には、コンポーネントを個別にビルドする必要
    はない
  • ある一定ラインを超えたら、コンポーネントや依存関
    係にもとづいたパイプライン、成果物管理を用いない
    と、効率的なデリバリーや素早いフィードバックが実
    現できなくなる
感想
• ブランチはあくまで次善の策

More Related Content

Similar to Continuous delivery chapter13

クラウド開発に役立つ OSS あれこれ
クラウド開発に役立つ OSS あれこれクラウド開発に役立つ OSS あれこれ
クラウド開発に役立つ OSS あれこれ
Masataka MIZUNO
 
xDB Replication ブローシャー
xDB Replication ブローシャーxDB Replication ブローシャー
xDB Replication ブローシャー
Yuji Fujita
 
Java fx勉強会lt 第8回
Java fx勉強会lt 第8回Java fx勉強会lt 第8回
Java fx勉強会lt 第8回
Taiji Miyabe
 
Active directory の移行 (2011年6月の資料)
Active directory の移行 (2011年6月の資料)Active directory の移行 (2011年6月の資料)
Active directory の移行 (2011年6月の資料)
wintechq
 
意外と知らない?Yumパッケージ管理
意外と知らない?Yumパッケージ管理意外と知らない?Yumパッケージ管理
意外と知らない?Yumパッケージ管理
denet1999
 

Similar to Continuous delivery chapter13 (20)

Microservices and Servcie Mesh on Azure
Microservices and Servcie Mesh on AzureMicroservices and Servcie Mesh on Azure
Microservices and Servcie Mesh on Azure
 
QCon北京2015 sina jpool-微博平台自动化运维实践
QCon北京2015 sina jpool-微博平台自动化运维实践QCon北京2015 sina jpool-微博平台自动化运维实践
QCon北京2015 sina jpool-微博平台自动化运维实践
 
クラウド開発に役立つ OSS あれこれ
クラウド開発に役立つ OSS あれこれクラウド開発に役立つ OSS あれこれ
クラウド開発に役立つ OSS あれこれ
 
iOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPracticeiOSやAndroidアプリ開発のGoodPractice
iOSやAndroidアプリ開発のGoodPractice
 
Oracleが提供するマイクロサービス開発環境
Oracleが提供するマイクロサービス開発環境Oracleが提供するマイクロサービス開発環境
Oracleが提供するマイクロサービス開発環境
 
第2回 分散システム本読書会
第2回 分散システム本読書会第2回 分散システム本読書会
第2回 分散システム本読書会
 
xDB Replication ブローシャー
xDB Replication ブローシャーxDB Replication ブローシャー
xDB Replication ブローシャー
 
20181120 HowtoFlow
20181120 HowtoFlow20181120 HowtoFlow
20181120 HowtoFlow
 
Java fx勉強会lt 第8回
Java fx勉強会lt 第8回Java fx勉強会lt 第8回
Java fx勉強会lt 第8回
 
オープンソースを利用したモデル駆動トライアル
オープンソースを利用したモデル駆動トライアルオープンソースを利用したモデル駆動トライアル
オープンソースを利用したモデル駆動トライアル
 
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
密着! nibohsiデプロイ 13:00-13:05 - railsアプリのデプロイ事例 -
 
PostgreSQLの連携!クラウド移行!負荷分散!バックアップ!DBMotoで一挙解決!
PostgreSQLの連携!クラウド移行!負荷分散!バックアップ!DBMotoで一挙解決!PostgreSQLの連携!クラウド移行!負荷分散!バックアップ!DBMotoで一挙解決!
PostgreSQLの連携!クラウド移行!負荷分散!バックアップ!DBMotoで一挙解決!
 
Gaej Explorer
Gaej ExplorerGaej Explorer
Gaej Explorer
 
「今そこにある危機」を捉える ~ pg_stat_statements revisited
「今そこにある危機」を捉える ~ pg_stat_statements revisited「今そこにある危機」を捉える ~ pg_stat_statements revisited
「今そこにある危機」を捉える ~ pg_stat_statements revisited
 
Voicepic@FacebookNight
Voicepic@FacebookNightVoicepic@FacebookNight
Voicepic@FacebookNight
 
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶjQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
 
Azure Service Fabric 概要
Azure Service Fabric 概要Azure Service Fabric 概要
Azure Service Fabric 概要
 
Active directory の移行 (2011年6月の資料)
Active directory の移行 (2011年6月の資料)Active directory の移行 (2011年6月の資料)
Active directory の移行 (2011年6月の資料)
 
Citrix eco new
Citrix eco newCitrix eco new
Citrix eco new
 
意外と知らない?Yumパッケージ管理
意外と知らない?Yumパッケージ管理意外と知らない?Yumパッケージ管理
意外と知らない?Yumパッケージ管理
 

Continuous delivery chapter13

  • 1. 『継続的デリバリー』 読書会 第13章 コンポーネントや依存関係を管理す る 大崎的デリバリー @favril
  • 2. 13.1 導入(1/2) • 本章で説明する内容 – コンテキストが切り替わるときにもアプリ ケーションを常にリリース可能に保つための 方法 – 巨大なアプリケーションのコンポーネント化 • コンポーネント分割の方法 • 複数コンポーネントからなる巨大プロジェクトの ビルド方法 • その管理方法
  • 3. 13.1 導入(2/2) • 言葉の定義 – コンポーネント • それなりに大規模なコード • よく作られたAPIを提供 • 別の実装にも切り替えられる • モジュールとも呼ぶ • Windows: DLL, UNIX: SOファイル, Java: JARファイル.. – コンポーネントベースのシステム • いくつかの部品に分解可能 • それぞれのふるまいが定義されている • 他のコンポーネントと最小限のやりとり
  • 4. 13.2 アプリケーションをリリース 可能な状態に保つ(1/3) • 通常、下記の手法で開発を行うとリリー ス間隔が長くなりがち リリー trunk ス 開発 bugfix 開発 release 1 • 「常にリリース可能な状態」を保ててい ない
  • 5. 13.2 アプリケーションをリリース 可能な状態に保つ(2/3) • バージョン管理システムのブランチを使うこと で、メインラインを常にリリース可能な状態に保 つことが可能 リリー trunk ス マー ジ feature 1 feature 2 開発 / bugfix 開発 • しかし、これはあくまで次善の策 –  ブランチ上での作業が継続的に統合されていない
  • 6. 13.2 アプリケーションをリリース 可能な状態に保つ(3/3) • 全員がメインライン上で作業する方式を 推奨 • ただし、常にリリース可能状態は保つ – そのための4つの作戦 • 新機能は完成するまで隠す • すべての変更を細かくインクリメンタルに行い、 個々の変更をすべてリリース可能な状態にする • 抽象化によるブランチを使って、大規模な変更を コードベースに加える • 変更の頻度が異なる部分をコンポーネント化し て、アプリケーションから切り離す
  • 7. 13.2.1 新機能は完成するまで隠せ (1/2) • 開発中の機能を本番に反映しつつ、それ を利用できないようにする – 開発中の機能に個別のURIを与え、機能のリ リースまではWebサーバの設定でアクセス拒 否 – 古い機能と、開発中の新しい機能を設定で切 り替えれるように作る
  • 8. 13.2.1 新機能は完成するまで隠せ (2/2) • 未完成の機能もメインラインで開発するメ リット – システム全体の統合やテストをありのままの状態 でいつでも実行できる – 依存関係の整理や統合のフェーズをプロジェクト の計画に含める必要がなくなる • この方法での開発は – 準備や検討などそれなりに大変 – 新機能を開発途中でもリリースできるという利点 を考慮すると、その価値はある – ブランチ開発より優れている
  • 9. 13.2.2 すべての変更はインクリメン タルに(1/2) • 大規模な変更を加えるとき、以下をやりがち – ブランチを作り – アプリが動かなくなるくらいがっつり変更を加え – その後、正しく動くように細かい部分を含めて修 正する(メインラインにマージする) – 上記手法は、確かに開発を高速化するかもしれな い – が、すべて正しく修正するのは大変で難しい – したがって、変更量が大規模であればあるほど、 実際はブランチを作るべきではない
  • 10. 13.2.2 すべての変更はインクリメン タルに(2/2) • 大規模な変更を細かく分割して、小さな 変更をインクリメンタルに進める – 要件を小さなタスクに分解していく過程と類 似 – 分析が重要 – 間違いが尐なくなる – 作業をどう進めるか(本当に進めるべきか) を判断できる – いつでもやめれる(?)
  • 11. 13.2.3 抽象化によるブランチ (1/3) • 大規模な変更を加えたいが、小さくてインク リメンタルな段階に分解できない場合 – 1. 既存システムにおいて、変更したい部分を抽象 化 – 2. 既存システムをリファクタリングし、その抽象 化レイヤを使うようにする – 3. 新しい実装をする(ただし、完成までは実行パ スに含まれないように) – 4. 抽象化レイヤを書き換え、新しい実装に処理を 委譲 – 5. 古い実装を削除 – 6. 不要なら抽象化レイヤも削除
  • 12. 13.2.3 抽象化によるブランチ (2/3) • この方法で困難な2点 – 対象のコードベースから、エントリポイント を分離すること – 開発中の機能に対して施すべき変更を管理す ること
  • 13. 13.2.3 抽象化によるブランチ (3/3) • アプリに大規模な変更を加えるとき、包 括的な自動受け入れテストスイートの存 在が重要 – ユニットテストやコンポーネントテストは、 この目的で使うには粒度が細か過ぎる – 業務的な機能が壊れないようにするための助 けにならない
  • 14. 13.3 依存関係(1/2) • ソフトウェアのある部分をビルドあるい は実行するために別の何かが必要 – 大半のアプリは何らかの依存関係がある – 例えば、動作環境 • Java  JVM • .NET  CLR • Rails  Ruby, Rails • C  C言語標準ライブラリ
  • 15. 13.3 依存関係(2/2) • 言葉の定義 – コンポーネントとライブラリ • ライブラリ – ソフトウェアパッケージの中で、自分たちで制御しようのないも の(どれを使うかの選択しかできない) • コンポーネント – ソフトウェアの部品としてアプリが依存しているもの – 自分達が開発する – ビルド時の依存関係と実行時の依存関係 • ビルド時の依存関係 – アプリをコンパイルしたときにあらわれるもの • 実行時の依存関係 – アプリを実行して機能を使うときにあらわれる
  • 16. 13.3.1 依存地獄(1/3) • 別名:DLL地獄 – 実行時に発生するライブラリの依存関係 – あるアプリケーションが、特定のバージョン の何かに依存しているのに、別のバージョン をデプロイしてしまった場合、あるいはそも そもデプロイしなかった場合に起こる • 例: 初期windowsは異なるバージョンのDLLを使うア プリの共存が不可能  .NET, GACで改善 • 例: Linuxは命名規約で回避
  • 17. 13.3.1 依存地獄(2/3) • OS全体の依存関係 – 静的にコンパイルしたまともなアプリを使う – コンパイル時に依存関係を1つのアセンブリ にまとめれば実行時の依存関係はほぼなくな る – ただし、バイナリが肥大化するし、特定のOS バージョンに密結合するので、おすすめしな い
  • 18. 13.3.1 依存地獄(3/3) • 動的言語の場合 – 依存するフレームワークやライブラリも、ア プリと一緒に出荷することで依存関係を解決 する • 例: Rails • Javaの場合 – あるクラスの複数のバージョンを同じJVM内 で使えないという深刻な問題がある – OSGiフレームワーク形式を使って解決する JAR1 ver1 アプリ JAR3 JAR2 ver2
  • 19. 13.3.2 ライブラリを管理する (1/3) • ビルドが再現性のあるものであることが 重要 • 適切な方法が2つ – ライブラリもバージョン管理にチェックイン する • 最もシンプル • 小規模なプロジェクトならこれで十分 – 使うライブラリを宣言した上でMaven, Ivyを使 い、組織内のリポジトリからライブラリをダ ウンロードして使う
  • 20. 13.3.2 ライブラリを管理する (2/3) • ライブラリチェックインの問題点 – リポジトリの肥大化 – 同一プラットフォーム上で、別のプロジェク トを共存させないといけなくなった場合 – プロジェクト間の依存関係を手動で管理する のは厳しい
  • 21. 13.3.2 ライブラリを管理する (3/3) • 依存関係の管理を自動化する仕組みを提供す るツール(Maven, Ivy)を使う – 必要なライブラリとそのバージョンを、プロジェ クトに設定できる – 他プロジェクトとの依存関係をよろしく解決して くれる • 自前の成果物リポジトリを持つ – Artifactory, Nexusなど – 自社内のプロジェクトで、どのライブラリのどの バージョンが使えるか制御できる
  • 22. 13.4 コンポーネント • なぜコードベースを複数のコンポーネン トに分割しないといけないのか? • コンポーネント間の関係はどうやって管 理すべきか?
  • 23. 13.4.1 コードベースをコンポーネン トに分割する方法(1/6) • コンポーネントに分割することが、開発 プロセスを効率化する理由 – 1. 大きな問題を、より小さくわかりやすい問 題に分割できる – 2. コンポーネントが、システム中の更新頻度 が違う部分、ライフサイクルが違う部分をあ らわす – 3. ソフトウェアの設計や保守の段階で、その 責務を明確化することにつながる – 4. ビルドプロセスやデプロイメントプロセス を最適化する際に、自由をくれる
  • 24. 13.4.1 コードベースをコンポーネン トに分割する方法(2/6) • 大半のコンポーネントの特徴 – 何らかの形式でAPIを公開していること • APIは、外部の協調オブジェクトとの情報交換を表 している • また、結合度合いも表している – コンポーネント間の依存は考慮しないといけ ない • 結合が強いと、別々に分割して、個別にビルドや デプロイメントをするのが難しくなる
  • 25. 13.4.1 コードベースをコンポーネン トに分割する方法(3/6) • コンポーネント化すべき場面 – 1. コードベースの一部を個別にデプロイする必要がある – 2. コードベースをコアとプラグイン群に分割し、一部を別 の実装に切り替えたり、ユーザ側での拡張性を高めたりし たい – 3. そのコンポーネントが別のシステムへのインタフェース を提供する – 4. コードのコンパイルとリンクに時間がかかる – 5. 開発ツールでプロジェクトを開くのに時間がかかる – 6. コードベースが大きくなりすぎて、1つのチームで手に 負えない – 後半3点は著者の主観だが、すべて理由としては妥当だし、 最後の項目は最も重要
  • 26. 13.4.1 コードベースをコンポーネン トに分割する方法(4/6) • チームの力を最大限に発揮できるのは – 10人前後のメンバーで構成 – 各自がコードベースの特定の部分を隅々まで 知り尽くしている • 特定の部分:機能的な区切りでも、それ以外の何 かの基準による区切でもよい
  • 27. 13.4.1 コードベースをコンポーネン トに分割する方法(5/6) • 10人以上必要な場合 – システムを疎結合なコンポーネントに分割し、 チームも分割する – ただし、コンポーネント毎のチーム分けは勧めな い • 要件の分割はコンポーネントの境界と沿わない • コミュニケーションコストの浪費 • プロジェクト全体で何がベストか見えなくなりがち – 各チームが1つのストーリーの流れを扱うのがよ い • 必要なコンポーネントはすべて手をいれられる権限を 与える • 統合チームに責任を押し付けることがなくなる
  • 28. 13.4.1 コードベースをコンポーネン トに分割する方法(6/6) • コンポーネント分割するにあたっての、強力 でお手軽なツールは無い – 説明してきたより良い設計を考えるだけ – その際の罠 • 何もかもコンポーネント化してしまうこと • 1つのコンポーネントにすべてを任せること • コンウェイの法則 – システムを設計する組織は、その組織のコミュニ ケーション構造をそっくりまねた設計を生み出す • チーム編成には注意
  • 29. コンポーネントを使うからといって必 ずしもN層アーキテクチャになるわけ ではない • N層アーキテクチャとは – アプリケーションを表示、業務処理、データ等、複数の階層で 分割する分散アプリケーション設計手法 • メリット – 経験の浅い開発者が集まった巨大なチームでも密結合な泥団子 を作らずにすむ – キャパシティやスケーラビリティの面で有利 • デメリット – 階層が物理的に離れている場合、リクエストを処理する待ち時 間が増える • 複雑なキャッシュの仕組みの導入につながる • 保守やデバッグがしづらい • コードは理解しにくく、各層間の依存関係のせいで変更もしにくい • N層化はコンポーネントベースの開発と同義ではなく、直交 する概念
  • 30. 13.4.2 コンポーネントをパイプライ ン化する(1/4) • 基本的には、何か変更がコミットされる たびに、すべてをビルドし、テストする のが良い – 時間がかかりすぎるようになったら、そのと き対応する – 巨大で複雑なシステムでも対応可能
  • 31. 13.4.2 コンポーネントをパイプライ ン化する(2/4) • パイプラインに分割したほうがやりやすい場面 – アプリケーションの一部が、他の部分とは異なるラ イフサイクルをたどる – アプリケーション内で機能的に分かれた部分をそれ ぞれ別チームが担当しており、個々のチームで専用 のコンポーネントを使っている – あるコンポーネントが他とは異なる技術やビルドプ ロセスを使っている – 共有コンポーネントが他のプロジェクトでも使われ ている – あるコンポーネントが比較的安定しいて、変更頻度 が低い – ビルドに時間がかかり、コンポーネントごとに分け た方が速い
  • 32. 13.4.2 コンポーネントをパイプライ ン化する(3/4) • 各コンポーネントあるいはコンポーネン ト群のビルドには独自のパイプラインが 必要 • パイプラインの動き – 必要に応じてコードをコンパイルする – ひとつあるいは複数のバイナリを、あらゆる 環境へのデプロイメントに対応できるよう組 み立てる – ユニットテストを実行する – 受け入れテストを実行する – 手動テストをする場面ではそれに対応する
  • 33. 13.4.2 コンポーネントをパイプライ ン化する(4/4) • 各バイナリが自身のリリースプロセスを 通過すれば、次のインテグレーションビ ルドに進む準備ができたことになる • DLLやJARの単位でパイプラインを作るべき、 と主張しているわけではない • 運用するビルド数はできるだけ尐ない方 がよい
  • 34. 13.4.3 インテグレーションパイプラ イン(1/3) • 適切なバイナリを組み合わせてデプロイ 用のパッケージを作成 • できあがったアプリケーションを疑似本 番環境にデプロイしてスモークテストを 実行 • 受け入れテストを実行 • 例、図13-1 (p.427)
  • 35. 13.4.3 インテグレーションパイプラ イン(2/3) • デプロイメントパイプラインに関する一 般原則2つ – 素早いフィードバック – ビルドの状況を関係者全員が見れる • 失敗した場合、なぜ失敗したかが正確にわかる必 要 – インテグレーションビルド側から、元になった各コンポ ーネントのバージョンをたどれる必要 – コンポーネント開発側からも、どのバージョンのコンポ ーネントがインテグレーションパイプラインで成功した か見れる必要
  • 36. 13.4.3 インテグレーションパイプラ イン(3/3) • インテグレーションパイプラインの実行間隔 が離れていて、その間に複数のコンポーネン トに多くの変更があるのは好ましくない状況 – どの変更がアプリを壊したのかわかりにくい • 最もシンプルな解決策 – 各コンポーネントのうまく動いているバージョン について、考えうるすべての組み合わせをビルド する • 人手が必要ない&賢いアルゴリズムを考える必要もな い • 次善の策 – スケジューリングを使って、定期的にビルドする
  • 37. 13.5 依存グラフを管理する • 依存関係は、ライブラリやコンポーネン トも含めてバージョン管理しておくこと が重要 – コンポーネント間の依存関係を図示した際は、 無閉路有向グラフでなければならない – そうならない場合、特に閉路グラフになる場 合は、依存関係に病的な問題がある
  • 38. 13.5.1 依存グラフを作成する (1/4) • 例、図13-2 (p429) 上流 レポート 下流 エンジン フレームワー 資産管理アプ 決済エンジン ク リケーション CDS プライシング ライブラリ エンジン 他社 それぞれパイプラインを持っていて、 自身あるいは上流に変更があったら、 パイプラインが起動
  • 39. 13.5.1 依存グラフを作成する (2/4) • この例のビルド時に起こりうるシナリオ – 1. 資産管理アプリケーションを変更 • 資産管理アプリケーションだけ再ビルド – 2. レポートエンジンを変更 • レポートエンジンを再ビルドし、すべてのテストを通す • その後、資産管理アプリケーションを再ビルド – 3. CDSプライシングライブラリに変更 • プライシングエンジンの再ビルド • その後、資産管理アプリケーションの再ビルド – 4. フレームワークに変更 • フレームワークを再ビルド • 直近の下流にあるすべての依存コンポーネントを再ビルド • 上記がすべてできたら、資産管理アプリケーションを再ビル ド – 1つでも失敗していたら、資産管理アプリケーションは再ビルド しない
  • 40. 13.5.1 依存グラフを作成する (3/4) • 続き – 5. フレームワークとプライシングエンジンに 変更 • グラフ全体の再ビルドが必要 • 理想は、すべてのビルドが成功すること • もし、決済エンジンのビルドが失敗したら? – 資産管理アプリケーションを新しいフレームワークでは ビルドできない – しかし、CDSプライシングライブラリは動作検証済みな ので、これだけ新しいバージョンで、資産管理アプリ ケーションをビルドしたい » が、そんなバージョンのプライシングエンジンは存 在しない
  • 41. 13.5.1 依存グラフを作成する (4/4) • この例の最も重要な制約は、 – 資産管理アプリケーションをビルドする際に 使えるフレームワークのバージョンが1つだ けということ • これは典型的な「菱形依存」
  • 42. 13.5.2 依存グラフをパイプライン化 する(1/2) • 図13-3 (p432) – フィードバックを早くするために、各プロジェク トのパイプライン内でコミットステージが完了し た時点で、依存プロジェクトのパイプラインを立 ち上げる(受け入れテストの完了を待たない) – すべてのトリガーは自動(手動テスト、本番デプ ロイを除く) – アプリケーションのあるバージョンをビルドする ときに使った各コンポーネントをたどれることが 重要 – どのバージョンのコンポーネントの組み合わせが 統合に成功したかを知れる • 図13-4, 図13-5 (p433)
  • 43. 13.5.2 依存グラフをパイプライン化 する(2/2) • 大幅な変更をコンポーネントに加える必要がある場合 は新しいリリースを作る – 図13-6 (p434) – APIの後方互換性がない新バージョンを開発する際、開発 をはじめる前に1.0系のリリース用ブランチを作ってから 開発する – 下流の資産管理アプリケーションは、1.0ブランチから 作ったバイナリを使える – Bugfixは1.0で行い、trunkにマージする – 資産管理アプリケーションが新バージョンに対応した時点 で、trunkに切り替える – 継続的インテグレーションの観点では次善の策 – だが、コンポーネントが疎結合であることが、統合を先延 ばしにしたときのリスクを抑えている
  • 44. 13.5.3 いつビルドすべきか? (1/2) • 上流の依存を最新版に保ち、最新の機能 とバグフィックスを使いたいが、すべて の依存を最新にする統合にはコストがか かる – 動かなくなった部分を修正しないといけない ので
  • 45. 13.5.3 いつビルドすべきか? (2/2) • 依存関係更新の頻度を決める際の検討事項 – 依存コンポーネントの最新版をどの程度信頼できるか? • 数が尐なく、自分たちで開発しているなら、修正も素早く行え るので、頻繁に統合すべき • 社内の別のチームの場合、個別のパイプラインにすべき。追従 するか、しないかを都度判断できる • サードパーティのライブラリは、明らかな必要性があるときの みにすべき – コンポーネントの変更にどの程度関与でき、どの程度知れ るかがポイント • 程度が低いほど、信頼性は下がる – 基本的には、依存コンポーネントの新バージョンの統合を 継続的に行えるのがベスト • コストがかかる • 素早いフィードバックを得るには、統合を頻繁に行う必要があ る • が、頻繁に行うと自分たちの関与しないところで問題が発生し うる • 両者のバランスをとるための解決策の1つとして「慎重な楽天
  • 46. 13.5.4 慎重な楽天主義 • 依存グラフに、3つの状態を導入 – static, gruarded, fluid – staticな上流の依存を変更しても新しいビルドは 引き起こさない – fluidな上流の依存が変更されたら常にビルドを実 行する • ビルドが失敗すると、依存コンポーネントは 「guarded」になり、動作確認済みの既知のバージョン に固定される – guardedな依存はstaticと同じふるまいをする – 開発チームには通知が飛ぶ – 例、図13-7 (p437)
  • 47. 13.5.5 循環依存 • 最もやっかいな問題 – 依存グラフに閉路が含まれる場合に起こる – 一番シンプルな例 • コンポーネントAはコンポーネントBに依存してい るが、 • コンポーネントBもコンポーネントAに依存してい る • 最初の起動時に致命的な問題 • プロジェクトの開始時点では循環していない • おすすめしないが解決策は図13-8 (p438)
  • 48. 13.6 バイナリを管理する • 成果物リポジトリを使うときの一般的な 法則 • ファイルシステムだけを使ってバイナリ 管理する方法 • Mavenを使って依存関係を管理する方法
  • 49. 13.6.1 成果物リポジトリの活用法 (1/3) • 成果物リポジトリに再生成できないもの を含めてはいけない – 気兼ねなく削除でき、それによって取り戻せ ない何かがあってはいけない – あらゆるバイナリを再生成するために必要な すべてをバージョン管理する
  • 50. 13.6.1 成果物リポジトリの活用法 (2/3) • バイナリをどの程度保持し続けるにし ろ、ハッシュ(バイナリのMD5)も保持して おく必要がある – それによりバージョン管理システム内のどの リビジョンを使って作成したバイナリかわか る – 保存は、ビルドシステムでもよいし、バー ジョン管理システムでもよい • ハッシュ管理は構成管理の一貫として重要な位置 を占める
  • 51. 13.6.1 成果物リポジトリの活用法 (3/3) • 最もシンプルな成果物リポジトリ – ディスク上のディレクトリ構造として構成し たもの • バイナリと、それを作るソースのバージョンを関 連づけられる必要がある • パイプラインごとにディレクトリを作り、その中 でビルド番号ごとのディレクトリを作る • ビルドの成果物はすべてこのディレクトリに保管 する
  • 52. 13.6.2 デプロイメントパイプライン と成果物リポジトリのやりとり (1/2) • デプロイメントパイプラインで以下を実装 – ビルドの成果物を成果物リポジトリに保存 – 後で使うときに、それを取り出す • コンパイル、ユニットテスト、受け入れテスト、 手動受け入れテスト、本番 というパイプライン を例とする – コンパイルでバイナリができるので、それを成果物 リポジトリに保存 – ユニットテスト/受け入れテストでは、このバイナ リを取得してテストを行う。レポートは成果物リポ ジトリに保存 – 手動受け入れテストでは、このバイナリを取得し、 テスト環境にデプロイして手動テストする – リリースでは、このバイナリを本番環境にデプロイ する
  • 53. 13.6.2 デプロイメントパイプライン と成果物リポジトリのやりとり (2/2) • 成果物リポジトリは、 – 共有ファイルシステム上に保存する方法 – Nexus, Artifactoryといったリポジトリ管理ツー ルも使える
  • 54. 13.7 Mavenを使って依存関係を管理 する • Maven – Javaプロジェクト用のビルド管理システム – 依存関係の管理が得意 – 外部のライブラリとの依存関係/アプリケー ション内のコンポーネント間の依存関係 を 抽象化してどちらもほぼ同様に扱えるように する –略
  • 55. 13.8 まとめ • チームでの開発をできる限り効率的に進めつ つ、アプリケーションを常にリリース可能な 状態に保つ方法を議論 – すべての変更を小さくインクリメンタルなものに 分割し、尐しずつメインラインにチェックインす る方法 – アプリケーション自体をコンポーネントに分割す る方法 • 基本的には、コンポーネントを個別にビルドする必要 はない • ある一定ラインを超えたら、コンポーネントや依存関 係にもとづいたパイプライン、成果物管理を用いない と、効率的なデリバリーや素早いフィードバックが実 現できなくなる