達人プログラマになるために習得しておくべきソフトウェア開発の技術として、
バージョン管理
ユニットテスト
自動化
を使いこなすことを推奨していいる本。
コードの書き方やロジックなどの本ではない。

もともと、この3つについて3部作で別々に出版したものを日本語版では1冊にまとめたもの。

第1部 バージョン管理
第1章 はじめに
メリット
・チームプロジェクト全体に及ぶUndo
・複数の開発者が管理された方法で同じコードを基に作業できる。
・時間とともに行われた変更を保持、変更を加えた人と時間、運が良ければ理由もわかる
・メインの開発を続けながら複数のリリースを同時にサポートすることができる。

CVSを例にどんなことができるか、具体的な導入方法、競合がおきたときなどを解説している。


第2章用語
最初に用語がいろんな使われ方をしているので定義するといっていた。

ワークスペース・・・プロジェクトの一部に取り組むために必要なリポジトリ内にあるすべてのファイルのローカルコピーする場所

チェックアウト ・・・リポジトリからファイルを取得すること

リポジトリ・・・プロジェクトファイルのすべてのバージョンに対してマスターコピーを置くための中心的な場所 。格納するもの=それが無ければアプリケーションの構築と提供が行えなくなるならすべて、でも生成可能なものはいれない 。プログラムのソースファイル 。Antツール(スクリプト)が作るスクリプトなど。 メタデータ ドキュメント、重要な電子メール、会議の議事録、Web情報 。

コミット・・・行った変更を再度リポジトリに保存すること

更新 ・・・誰かが行った変更を手に入れるため、リポジトリから最新のファイルを入手すること(最新の更新をチェックアウトしているので、更新のことをチェックアウトという人もいる)

バージョン・・・リポリトジは現在のコピーだけでなく、チェックインされたすべてのバージョンを格納している。そのメリットはファイルの特定のリビジョン(システムが付けるファイルの番号)を取り出す。システムのすべてのコードを2か月前に戻す。バージョン間での変更を表示する。

タグ・・・ある時点でのファイルの集合(または、モジュールやプロジェクト全体)に名前を割り当てる

ブランチ・・・本流の作業から離れて、特定のリリースを作成するときなどにブランチをつくり、そこでリリースチームが作業。メリットは本流の作業を止めずにリリースを作成できる

マージ・・・ブランチ内での修正を本流に反映させる。 メリットはブランチ内で発見したバグの修正を本流にコピーペーストする必要がないこと。

ロックオプション・・・二人が同時に同じファイルをチェックアウトして変更し、チェックインしようとした場合競合が起きる 。kのときの処理方法は二つ
厳格なロック・・・誰かが編集中のファイルは編集できない。メリットはファイルの整合性が保たれる。デメリットは特に見返りのない多くの面倒な作業が追加される
楽観的ロック・・・何人でも編集可能だが、チェックインしようとすると競合の警告がでるので、それを手動で解決する。 著者はこちらを推奨していた。実際にやってみれば競合はほとんどおきないとも。


第3章 バージョン管理システムCVSについて
インストール
 手順
   ・インストールされているか確認。コマンド「cvs -v」を入力、CVSのバージョンが表示されなければ、ダウンロードしてインストール
   ・リポジトリの作成。HDの置き場(階層の先頭のみ)「cvs -d ディレクトリ名 init」
   ・GUIフロントエンド、WinCvs TortoiseCVS(Visual Studioにプラグインできる)などを使う。IDEではEclipseがCVSをサポートしている。 注意 それでもCVSのコマンドを知ることは大切。

シンプルなプロジェクトを作成しCVSを使う
 ・ファイルをつくりインポートする例、引数importにメッセージをつけて格納
 ・ローカルマシンのどこにファイルの作業コピーを置くか決定し、チェックアウト 「cvs -d ディレクトリ名 co プロジェクト名]
 ・チェックアウトしたファイルに変更を加えて戻す。
   手順
    ・プロジェクトの状態を確認「cvs status ファイル名」
    ・リポジトリとローカルコピーの変更点を出す「cvs diff ファイル名]
    ・リポジトリの更新(ユニットテストも行ってOKならね!)「cvs commit -m "メッセージ"]
      一つのファイルが2人のユーザーに変更された場合
        ・変更されたコードに競合がなければ、リポジトリの変更に現在のファイルを合わせる。もちろんdeffで確認してから。「CVS update」でリポジトリに合わせて(もちろんローカルの変更はなくさない、マージされるのだ)から、自分のコードをチェックインする。
        ・変更されたコードが競合する場合「cvs update」はエラーを返すが、ローカルの変更は失われず、CVSが競合している部分を教えてくれる。は、「cvs log -rバージョン ファイル名」で誰がコードを変更したか調べ、確認する必要がある。cvsが勘違いを防いでくれたともいえる。ただし、こんな事態はめったに起きない。


第4章 バージョン管理に関する問題
バージョン管理の利点があるににも関わらず採用されないのは、理論と実践は違う、バージョン管理はとても面倒だとみなされるから。

基本的な哲学としてバージョン管理は軽量で、シンプルで明白でなければならない。変更したコードをチェックインするために複雑な手順や、作業の中断があってはならない。また実行していることやバージョンが明確にならなければならない。

CVSリポジトリにソースを整理するための基本的な規則
・開始する前にリポジトリにアクセスするための効率的かつ安全な方法を確立する。
・アクセス可能な状態になった後は、シンプルなCVSコマンド軍を常に使用します。
・個々の企業で開発する各プロジェクトは、異なるCVSモジュールとして利用できなければいけまない。プロジェクトの完全なソースを一か所からチェックアウトできるようにすべき。
・切り離して取り組むことができる下位のコンポーネントがプロジェクトに含まれる場合や、プロジェクト間でコンポーネントを共有しようとする場合は、これらのコンポーネントは名前を付けたモジュールに格納する必要がある。
・プロジェクトがサードパーティ(ベンダーやオープンソースのプロジェクト)のコードを組み込んでいる場合は、リソースとしてこのようなコードを管理する必要がある。
・開発者は、リリース、バグの修正、主なコードの実験の開始など、適切なタイミングにおける特異点を識別するのにタグを使用する。


第5章 リポジトリへのアクセス
通常ネットワーク経由でアクセスするセントラルリポジトリをもつのが普通。重要なのは間違った方法で初めても問題ないこと。接続方法にはリポジトリに影響しない。

接続技術にはpserverとexternalがある。
pserverは独自のネットワークポートを使用するので、企業のファイアウォールの多くはこのトラフィックの通貨を許可しない。パスワードの暗号化が脆弱でファイルの内容が平文で送られる。などの問題があり、匿名のリモートアクセスを行う場合以外は推奨しない。

externalでは既存のOSコマンドを使用してクライアントとサーバのデータパイプをつくる。外部のDVSのデフォルト設定ではrshを使うが、これは安全性が低いのでsshを使う方がいい。

CVSはリポジトリにアクセスして変更を行う人をユーザとして扱う。方法によらずユーザIDが必要。
そして一つのユーザIDでリポジトリにアクセスするという怠慢は避けるべき、だれが変更を加えたかわからなくなってしまうので。
環境変数CVSROOTにデフォルトのリポジトリの場所を設定して使う。
sshをインストールしてCVS_RSHにsshを指定する。Unixの場合は。Profileに設定を追加してsshでログインして使う。

pserverを使用してリポジトリにアクセスする場合、管理者はサーバにCVSパスワードを設定する。ユーザは[「cvs login」ではじめる。セキュリティが懸念する場合は使わないこと。


第6章 共通のCVSコマンド

毎日のタスクを行うために使用するCVSコマンド例
チェックアウト先のディレクトリに移動してからコマンドを実行
チェックアウト cvs co .... ファイル名日付タグなどを指定して取り出す。
最新の状態に保つ cvs update... ディフォルトでは最後にチェックアウトした後にリポジトリに新たに追加されたディレクトリは作業ディレクトリには反映されないので、-dオプションをつけると反映される。またファイル名を指定して特定のファイルだけを更新することもできる。
ファイルおよびディレクトリの追加 cvs add ... バイナリファイルは-kbで追加する。忘れた場合の対処方法の記述あり。
cvswrappersを使用してファイル名に基づいてデフォルトのファイルの種類を指定する方法解説。
特定のファイルを無視する .cvsignoreの内容を読み取ってそれを無視する。総てのひとが同じ環境で作業している場合は .cvsignoreもチェックインすることを推奨していた。
ファイル名の変更 かなり面倒くさそうな手順がのっていた。mv とかremoveをつかう。
ディレクトリ名の変更 ファイル名よりさらに長い手順が載っていた。
変更された内容の確認 cvs diff... ディフォルトではチェックアウトされた時点のファイルとローカルのファイルの差異を調べる。リポジトリの最新バージョンと比較するには cvs diff -r HEAD ファイル名
差異をパッチとして出力する。オープンソースコミュニティなどでよく使われる。 cvs diff -u >出力ファイル名。こうして作られたパッチをソースに適用するには patch -p0 <パッチファイル名
マージ競合の方法。同じファイルの異なる部分を変更した場合はcvsはマージする。同じファイルの同じ部分を変更した場合はcvsはそれを宣言して人間に解決をゆだねる。いずれにせよ変更がなくなってしまうことはない。かえって、解決すべき問題がわかってよい。
変更のコミット 変更して(何も壊れてないことをテストしたら)、そのファイルをリポジトリに格納する。 cvs commit ...しかし、これを行う前にローカルを最新のリポジトリと一致させて(cvs update)競合の解決とテストの実行を行うことを推奨していた。
変更履歴の調査 cvs log...ログメッセージはどんな変更をしたかでなく、なぜそう変更したかを書くように推奨していた。cvs annotate はファイルの各行がいつ、だれにどのリビジョンで変更されたか示す。
変更の削除 まず最新のリポジトリに合わせて(update)、ログを出力し(log)、詳細な差分を調べ(diff)担当者と話し合い、削除しろ(cvs update -jリビジョン番号 -jリビジョン番号 ファイル名)といっていた。そしてコミット。大きな変更の時にはタグで同じことができる。-jオプションをつけるとcvsは現在の作業コピーに変更をマージする。-jオプションを二つ指定するとcvsは2つのリビジョン間で行われた変更をマージする。逆に指定すれば戻すことになる。

CVSキーワードは情報の重複になるので使わないといっていた。


第7章 タグとブランチの使用
タグとブランチは正しく使用しないとリポジトリの構造は複雑に絡み合ったスパゲッティのように見える。
またマージを先送りしていると、最終的に悪夢のような競合がおきたりする。

用語定義
タグ・・・識別名 必ず英字ではじまり、英字数字ハイフンアンダーバーを含めることができる。
通常のタグ・・・ある特定の時点におけるモジュール内のファイル群につける名前。
ブランチタグ・・・ブランチはリポジトリの履歴における分岐点。同じファイルに対して2つ以上の個別の変更がなされ、それぞれ別のブランチに格納されていることが考えられる。ブランチを作成するときにはブランチタグをつくる。

タグとブランチには何通りもの使い方があるので、過度に使用すると混乱する。
シンプルな状態を維持するために推奨される4つの目的
1 リリースブランチ・・・リリースは別のブランチにいれる
2 リリース・・・リリースされた時点を特定する
3 バグ修正・・・適切に修正されたら本流にマージ
4 実験
上記について、具体的に作成するコマンドや注意点を解説。


第8章 プロジェクトの作成

プロジェクトをバージョン管理するためのディレクトリ構造の例
work/
wibble/README BUIDING GLOSSARY
util/ src/ doc/ vendor/ vendorsrc
さらにsrcの下をclieant/ serverという風


第9章 モジュールの使用
モジュールはリポジトリ内の様々な部分をまとめてプロジェクトに論理構造を作成する際に使用する。
モジュールを使って特定のプロジェクトまたはサブプロジェクトが何を意味するかの正確な定義を一か所で行うと、開発者の誤りが減少し、すべてのプロジェクトに対して一貫性のある外部構造を維持できる。

ある程度のプロジェクトの規模になったら水平またはクライアントサーバーなどのサブプロジェクトに分割したほうがよい。
通常独自のサブツリーにサブプロジェクトを割り当てる。
ビルド構造という観点から
1 動作するディレクトリ構造を選択する
2 選択した構造をリポジトリ内で使用する
3 この構造を使用してチェックアウトするように、すべての開発者に要求する。

CVSモジュールは基本的にはリポジトリ内の1つまたは複数のサブディレクトリに名前をつけるための方法のひとつ。
モジュールはリポジトリ内のソースを使用しやすい塊に整理する際に生じるすべての問題に対処するのに役立つ。
CVSROOT/modulesファイル内にはモジュールが定義されている。

cvsのサポートする3種類のモジュール
別名モジュール・・・CVSROOT/modulesファイルに 別名 -a 実際のディレクトリ名で定義されたもの。その別名でリポジトリから呼び出せる。例では、3つのディレクトリをそれぞれ別名をつけ、それらの別名3つをさらに別名にして一括で扱っていた。

一般モジュール・・・チェックアウトする際にツリーの特定の部分の名前を変更できる。本来ディレクトリ構造が違ってしまうのはビルドをまとめるのが困難になるので悪いことだが、サブプロジェクトが相互に依存していない時にはとても有用。例として、社外で必要なファイルだけをチェックアウトすることが頻繁にあるときモジュールファイルに一般モジュールを設定して使う方法がのっていた。 モジュールファイル内に「チェックアウトするディレクトリ名リポジトリ内のディレクトリ名」として定義。

アンドモジュール・・・モジュールは他のモジュール名の前にアンド記号を付けることで他のモジュールの一覧として定義できる。例として一般モジュールを定義した後 モジュールファイル内で「モジュール名 &先に定義したモジュール名・・・・」として、一つのモジュール名で複数のモジュールをチェックアウトしていた。


第10章 サードパーティのコード
プロジェクトが依存する外部ライブラリ(Cならヘッダファイルなど)は、CVSのリポジトリに含めることを推奨していた。バージョンの変更があってもプログラムが動作するようにするためである。リポジトリの位置としてはプロジェクトの最上位レベルの下にvendorというディレクトリをつくり、その下にlib includeというディレクトリを切っていた。

ビルド環境と統合するために、プロジェクトツリーの最上位のプロジェクトディレクトリをします何らかの外部変数を設定し、関連するすべてのビルドでこの変数を参照するようにするのを推奨していた。

ソースコードを含んだライブラリを管理する方法として、ベンダーからリリースが来るたびにリポジトリにインポートする方法を解説していた。

サードパーティの提供するコードを使用していて、それを修正した場合。理想的なのはサードパーティにそれを通知して変更をリリースに反映してもらうこと。でも、それができなければ、リリースがあるたびに、自分たちの行った修正をマージする必要がある。cvsでそれを実施する方法を解説。


付録Aとして cvsコマンドの要約とレシピがのっていた。
cvsは 「cvs <全体にかかるオプション> コマンド <オプションと引数>...」という構造になっている。
全体にかかるオプション一覧
フラグ文字
環境
cvsコマンド一覧
その解説など

レシピとしてはsshによる接続例が何ページにのっているかなどがならんでいる。


付録B  リソースとして
オンラインのCVSリソース
他のCVS書籍
他のバージョン管理システム
参考文献



第2部 JUnitによるユニットテスト

第1章 はじめに
テストが重要なことは誰もが認めているが、実際にはプロジェクトの終盤で行われるだけであることが多い。
しかし、これではバグの発生源を探すのは困難である。
ユニットテストは開発者の作成する部分的なコードであり、とても小さな特定のコードの機能が動作するかテストするもの。開発者が意図したようにコードが動作するかを検証するために行われる。
コードが予想通りに動作するかを確認しなければ、その他の形式のテストを行うのは時間の浪費である。

ユニットテストの目的
・意図したとおりに動作するか確認する
・常に意図したとおりに動作するか確認する・・・開発者は唯一の正しい経路のみをテストしがち
・信頼できるか確認する・・・完全なコードを作成できる人はいない。なにが来ても動くようにコードをかけば、コードは膨れ上がってしまう。どこに問題があるかわかっていれば十分、例として数字の一覧を入れ替えるルーチンを作成していると、空の一覧の場合はどうするかという問題があるが、メソッドの仕様として空の一覧で呼び出されたら例外を返してもいいわけで、どんなときでも動くようにするというわけではない。
・意図を記録しているか確認する・・・さまざまな条件下でコードがどのようにふるまうか示す実行可能なドキュメントとして機能する。書面と違って内容がコードから離れていくことはない。

ユニットテストの実行方法
コードを作成する前に対象となるメソッドのテスト方法を決定し、実装コードと同時にテストコードを作成する。
そして、新しいテストだけでなく、以前のテストにもパスすることが大事。
すべてのテストにパスしたかは自動で判定される必要がある。

テストしないことに対する言い訳
・テストの作成に時間がかかりすぎる・・・終盤の一括テストの方が時間がかかる
・テストの実行に時間がかかりすぎる・・・そのようなテストはいけない。ユニットテストは迅速にほんの数秒でテストできるようにすべき。長いテストは切り離して、1日または数日ごとに実行する。
・自分のコードをテストするのは別の人の仕事だ・・・自分の仕事は動作するコードをつくることです
・コードがどのようにふるまうべきがよくわからないのでてすとできない・・・ではどうやってコードを作成する?
・コードはコンパイルすることができる・・・コンパイルやインタープリタは構文が正しいと保証してくれるだけ
・テストの作成ではなくコードの作成で報酬を得ている・・・同さするコードで報酬を得ているのだ
・テスト担当者と品質保証スタッフを失業させてしまうことに罪悪感がある・・・ユニットテストと機能テスト受け入れテスト、パフォーマンステスト、環境テストなどとは違う
・社内規則のため本番システムでユニットテストを行うことができない・・・本番システムで行うのはユニットテストではない


第2章 ユニットテストの開始
ユニットテストは、別の部分のコードを実行し、他の部分のコードが意図したとおりに動作するかを判断するコード。
具体的にはアサートを使用する。
実装の例
Public void asserTrue(boolean condition)
if (!condition){
abort();
}
}

テストの例として数字のリストから最大値をみつけるための1つの静的メソッドをあげていた。
シンプルな数列 [7, 8, 9]なら9をみつける。
このメソッドの考えられる限りのテストを見つけるという例題
並べ替え [7, 8, 9] [8, 9, 7] [9, 7, 8]
最大値が重複 [7, 9, 8, 9]
一つの数字しかない場合[1]
負の数の場合[-9, -8, -7]
これで実際に問題がおきるのを確認。こうして問題を解決しておけばよい。
本では、テストするメソッドとテストコードがのっていた。
バグは端にもっとも多く現れる。(渡す配列の最初または最後に最大値があるときに生じる。
例では7,8,9の配列を入れ替えて試していた。そしてforループの終了が早いエラーを発見する例をやっていた、
元からバグのあるメソッドのコードをつくって、このようにバグを発見していく手順で説明していた。
また、空の配列をどうするかという問題にあたって、これは仕様で決まっていないことに気が付いて、設計上の問題をはっけんできることを示していた。


第3章 JUnitによるテストの作成
テストコードの命名規則 createAccountというメソッドをテストしたいなら最初のテストメソッドはtestCreateAccountにするとよい。

テストコードの行うべきこと
・テストに必要なすべの条件の設定(必要なオブジェクトの作成や必要なリソースの割り当てなど)
・テスト対象のメソッドの呼び出し
・テスト対象のメソッドが予想通りに機能するかの確認
・テスト実行後の整理
コードを実行するときには、本番コードを実行する代わりに、テストコードを実行し、慎重に管理されたっ条件下で本番コードを順番に試す。テストフレームワークに関する一般概念はどのような言語や環境であっても同じ。

JUnitの提供するassertメソッドの解説
assertEquals・・・期待値と実際の値を比較、配列の内容は比較しない。浮動小数点の場合は許容誤差(有効桁数)も指定
assertNull・・・特定のオブジェクトがNullである、またはNullでないことを調べる
assertSame・・・期待値と実際の値が同じオブジェクトを参照することを調べる
assertTrue・・・特定のboolean型の条件式が清であることを調べる。ただし、一番最後にassertTrueが一つだけあるテストは、最後までコードが実行されたのだから動作するはずという考えがみえて、テストではなく希望的観測といっていた。
fail・・・任意のメッセージを表示して、テストを即座に失敗させる。
テストではメソッドの様々な面と関係をテストするので、通常はテストメソッドには複数のassertメソッドがある。どこかのassertで失敗すればテストはそこで終わりになる。その修正が終わるまで先に進んではいけない。常にすべてのテストをパスするようにすべき。

JUnitフレームワーク
assertを動作させるフレームワーク
実際にテストコードで解説
import junit.framework.*;

pubulic class TestSimple extends TestCase {
pubulic TestSimple(String name){
super(name)
}
public void testAdd(){
assertEquals(2, 1+i);
}
}

TestCaseという基底クラスはassertメソッドなどユニットテストに必要な機能の大部分を提供する。
テストすら素にはtestではじまる個別のテストメソッドがある。
またSuiteメソッドを定義すれば特定のメソッドを指定して実行することもできる。

Junitテストの複合
テストスイーツを作成すると、希望するテストのコレクションを返すことができる。
各テストがすべてのテストから切り離されて実行されうためには環境の一部を初期化するか、テスト実行後に後片付けを行う必要がある。設定を初期化するためのメソッドprotected void setUp(); テスト環境を整理するためのメソッドprotected void tearDown(); が提供されている。これの使い方解説。
テストスイートごとの前処理と後ろ処理・・・必要なテストの集合を取得してTestSetupオブジェクトにラッピングする必要がある。同じクラスでテストごとのsetUpメソッドとテストスイートごとのsetUpメソッドの両方を使える。

assertメソッドをカスタマイズして、独自のassertメソッドを作る場合
TestCaseクラスをサブクラス化し、すべてのテストがそのサブクラスを継承するのを推奨していた。

JUnitと例外
テストするメソッドに例外を起こさせる例・・・nullのリストを渡したら例外を起こす
public void testForException(){
try{
sortMyList(null);
fail("Shoud have trown an exception");
}catch (RuntimeException e){
assertTrue(true);
}
}
最後のassertTrueは制御フローはここを通過すべきと予想するのを明記している。後で生じる可能性のある誤解を解くためのドキュメントの役割をする。
一般的には宣言された例外ごとにメソッドをテストする必要がある。
予想外の例外はJUnitに任せることを推奨していた。
public void testDatal() throws FileNotFoundException{
FileInputStream in = new FileInputStream("data.txt");
.....

}
これで、JUnitフレームワークは発生した例外を受け取り、エラーとして報告する。さらにバグに至るまでのすべてのスタックトレースが報告されるので失敗の理由を見つけるのに役立つ。

通常JUinitはtestではじまるメソッド名を実行するので、取り組む準備ができるまでpendingTestMyThingなどの名前をつけておくことを推奨していた。このpendingは実行まちのテストの命名規則として統一して使う。

絶体にしてはいけないのはテスト結果の失敗を無視するという習慣。

JUnitを使用してテストを作成するのに本当に必要なのは
1 junit.Framework.*を取り込むimport文
2 クラスをTestCaseから継承させるextends文
3 super(string)を呼び出しているコンストラクタ
多くのIDEでは少なくともこれらは提供されている。
こうして作成されたクラスはJUnitのTestRunnerを使用して実行し、そのクラス内のtestではじまるメソッドは自動的に実行される。
TestRunnerを使用しないでテストクラスを直接実行するためのスケルトンの作成を付録Cで解説。


第4章 テストする内容:Right-BICEP
「失敗しそう」な状況は経験で感じ取れるが、初心者用にテストすべき6つの特定の部分を解説

・Right(適切)・・・その結果は適切か
 「コードが正しく実行されたと、どうすればわかるか」に満足に答えられないとコードやテストを作成できない。もし、はっきりしなければ、自分で考えた動作を予測してつくることはできるはず。そしてフィードバックで予測を微調整すればよい。大量のテストデータを使うときにはデータファイルから読み込ませるとよい。例が載っていた。ただし、エラーがでたら用意したデータの妥当性はチェックすべきともいっていた。

・Boundary(境界)・・・すべての境界条件はCORRECTに従っているか
 端になるのに考慮すべき条件
 ・完全に偽の入力値や矛盾した入力値
 ・不適切な形式のデータ
 ・空の値や欠落した値
 ・合理的な予想をはるかに超える値(人の年齢が10000歳など)
 ・リスト内で発生してはいけない値の重複
 ・順序付けされていない順序月リスト。あるいは順序付けされている順序なしリスト(ソートアルゴリズムとして、ソート済みリストや逆順のリストを処理するなど)
 ・一貫性のない順序で発生したり、予想される順序に反して発生するもの(ログインするまえにドキュメントをプリントするなど)

 CORRECTの内容は5章で解説

・Inverse(逆の関係)・・・逆の関係を確かめられるか
 計算結果を2乗して、その結果が元の数字にある程度近いことをテストすることで平方根を計算するメソッド。
 データを検索することによって、そのデータがデータベースに適切に挿入されたことを確認するなど。
 注意すべきは両方のルーチンにある共通のエラーでバグが隠される場合があること、狩野なら別のソースを利用して逆のテストを行うこと。

・Cross-check(クロスチェック)・・・他の手段を用いて結果をクロスチェックできるか
 図書貸し出しシステムなら、貸出部数と書庫の部数の合計はつねにすべての部数と一致するなど

・Error conditions(エラー条件)・・・エラー条件を強制的に発生できるか
 著者らが考え付いた環境的問題
 メモリ不足、ディスクの空き容量不足、実時間に関する問題、ネットワークへのアクセス可否、システム負荷、カラーパレットの制限、高すぎる低すぎるビデオ解像度。

・Performance(パフォーマンス)・・・パフォーマンス特製は妥当な範囲か
 パフォーマンス特製の簡単な回帰テストを行うことを推奨していた。例として特定のWebサイトを遮断するフィルタをあげ、1万とか10万のサンプルサイトで動作確認をして、パフォーマンス目標を満たしていることを確かめる。ただし実行には時間がかかるので、毎晩とか2・3日おきに実行していると、どんな変更を加えた時にパフォーマンスがおちたか、迅速にはっけんできる。
JUnitPerfなどにタイミングや重い付加条件のシュミレーションをサポートしている。


第5章 境界条件:CORRECT
 根本的な疑問「他に失敗する可能性があるのは何ですか」
 しっぱいしそうなことを思いついたらそのためのテストを作成し、パスしたら再度同じことを問いかける。

・COnformance(適合性)・・その値は予想される書式に適合していますか。
 電子メールからユーザー名を抽出するメソッドなら、@の前の文字を抽出すればいいが、もし、@がなかったらどうする?
 あるいはデータレコードに、最終的にはトレーラレコードにリンクされているヘッダーレコードを含む何らかの報告データをよんでいたとしたら、ヘッダーがなく、データとトレーラだけの場合は?データがなくヘッダーとトレーラだけの場合は?トレーラがなく、ヘッダーとデータだけの場合は?トレーラしかない場合は?ヘッダーしかない場合は?データしかない場合は?

・Ordering(順序)・・・一連の値は必要に応じて順序付けされる、もしくは順序付けされないという状態になっているか
 検索対象がリストの最初または最後に存在する場合のテストはバグが多いのでテストする必要がある。
 他の順序の例としてレストランの注文を処理するメソッドで、前菜からデザートになっているはずのリストで逆になっているならどうなるか?普通はそうだが、甥っ子のアイスクリームは前菜のサラダといっしょということもある。そういったときどうなるのか?
 またソートルーチンで一連のデータがすでに順序付けられていたら?あるいは逆順でソートされていたらどうなるのか?問題を引き起こすことがあるのか?
 自問して、必要なテストを作成する必要がある。

・Range(範囲)・・・その他意は合理的な最小値と最大値内になっているか
 型を指定しただけでは必要以上の広い範囲の値を変数にだいにゅうできてしまうという状況を意味する、便利で包括的な言葉。人間の年齢や角度、円周など。
 優れたオブジェクト指向設計では、境界のある整数を格納するのにそのままでは使用しない。
 例として角度0-359の整数で生成される変数をあげていた。これでシステム全体に対してその変数の範囲は保障される。
 例として配列を使用して文字列のスタックを実装するクラスをつくり、空スタックやスタックオーバーフローがチェックされていないのでバグが潜んでいるとしてチェックを追加するのをあげていた。

・Referrence(参照)・・・コードはそのコード自体の直接制御下にはない外部の要因を参照していますか
 クラスの状態と他のオブジェクトや全体的なアプリケーションの状態について前提をもたなければならない場合は、そのような条件がみたされない場合はコードが正しく動作するか確認が必要。例口座利用履歴を表示するなら、顧客がログインしていなければならない。
 一部の言語(Eiffel)には事前条件、事後条件のサポートがある

・Existence(存在)・・・その値は存在していますか(たとえば、null意外、0以外、1つの集合に含まれるなど)
 潜在的バグの多くは「ある特定のモノは存在するか」という重要な疑問を尋ねることでみつけられる。
 渡す値や保持する値は、その値が存在しなかった場合、null 空白 0だったらメソッドに何がおこるか自問するべき。
 ほとんどのjavaライブラリメソッドは存在しないデータに直面すると何らかの例外を返すが、一般的な実行例外をデバッグするのは困難。それよりは「年齢が設定されていません」がかえってくれたほうがよっぽど親切。
 ネットワーク、ファイルのURL、ライセンスキー、ユーザ、プリンタこれらがなかった場合どうなるかメソッドの動作を確認すべき。

・Cardinality(カーディナリティ)・・・十分な数の値が存在しているか
 360㎝の芝生を90㎝幅のフェンスで区切りたい場合ポストは4本ではなく5本必要。これは一つ違いのエラーの例。
 値の集合の数は3つ、0、1、2以上。
 例パンケーキ店の注文ベスト10をリアルタイムで更新してマネージャのPDAに報告するプログラムをつくる。テストするのは?
  ・一覧のケーキが10に満たなくても報告書をつくれるか。
  ・一覧にケーキがまったくなくても報告書を作れるか
  ・一覧のケーキが一つだけでも報告書をつくることができるか。
  ・一覧のケーキが10に満たなくてもケーキを追加することはできるか。
  ・一覧にケーキがまったくなくてもケーキを追加することはできるか。
  ・一覧のケーキが1つだけでもケーキを追加することはできるか。
  ・メニューのケーキが10に見た以内場合はどうなるか
  ・メニューにケーキがまったくない場合はどうなるか
 すべてを検討した後に、マネージャはトップ10でなくトップ20を見たいというかも、あるいはトップ5を
 変更するのは一行
  private final static int NUMBER_TO_RETAIN = 20;
 テスト用アクセッサー
public int getMaxEntries(){
return NUMBER_TO_RETAIN;
}

・Time(時間 絶対的および相対的)・・・すべてが順次、適切なタイミングで時間内におこっているか。
考慮すべき時間の側面
 ・相対的な時間(時間内の順序)
 ・絶対的な時間(経過時間と実時間)
 ・並列処理の問題
 
 一部のインターフェースは基本的にステートフル loginメソッドはlogaputメソッドの前に呼び出される。これらのメソッドが不適切な順序で呼び出されたらどうなるか?
 一時リソースが使用可能になるのをメソッドがどのくらい待つかという問題もある。永遠に待つのはもっともいけない。
 一日の長さは24時間ですか?これが問題となることもあります。夏時間と冬時間の境目もある。基本ライブラリがこれらの問題を処理してくれると考えてはいけない。
 複数のスレッドが同じオブジェクトを同時に使用した場合はどうなるか?
 同期をとらなければいけないグローバルまたはインスタンスレベルのデータやメソッドはあるか?
 ファイルやハードウェアに対する外部アクセスはどうか?
 同期をとる必要のあるデータ要素やメソッドにはsynchronizedキーワードを加えてテストの一部として複数のスレッドを同時に実行するようにする。

演習問題として
1シンプルなスタッククラス
2ショッピングカート
3ファックススケジューラ
4刺しゅう機能付きの自動ミシン 座標
5オーディオ/ビデオ編集


第6章 モックオブジェクトの使用
 テスト対象のメソッドが、ネットワーク、データベース、サーブレットエンジンなど他の扱い難いものに依存する場合は、注意しないとテストを実行できるだけの状況を与える為に、最終的ににはほとんどすべてのシステムコンポーネントを初期化するようなテストを作成することになってしまう。このようなときは照明チェックの代役のように目的に安易に取り組むことができる安価な代役をたてる。
 モックオブジェクトは現実世界のオブジェクトをデバッグ用に置き換えたもの。

モックオブジェクトが役立つ状況
 ・実際のオブジェクトには、費決定性のふるまいがある(株式相場の情報提供のように予期しない結果を生む)
 ・実際のオブジェクトは設定を行うのが大変である
 ・実際のオブジェクトはトリガを引き起こすのが困難な振る舞いがある(ネットワークエラーなど)
 ・実際のオブジェクトは遅い
 ・実際のオブジェクトはユーザインターフェースを保持している、またはユーザインターフェースである。
 ・テストでは、どのようにしようされたのかを実際のオブジェクトに尋ねる必要がある
 ・実際のオブジェクトはまだ存在していない。

モックオブジェクトを使用するための3つのステップ
 ・インターフェースを使用してオブジェクトを記述する
 ・そのインターフェースを本番コード用に実装する
 ・そのインターフェースをテスト用のモックオブジェクトとして実装する。

例として代謝時刻になったら音楽を鳴らすプログラムで、時刻のオブジェクトのモックオブジェクトを作成していた。
現在時刻など、現実世界のさまざまな環境の物事にに対応するインターフェースから始め、実装し、時刻をずらしながら音楽がなったかたしかめる(確かめるのはassertで自分で耳をかたむけている必要はない)

サーブレット・・・Webサーバが管理するコードの塊。特定のURLへのリクエストはサーブレットコンテナ(またはマネージャー)に転送されて、コンテナ化がサーブレットのコードを呼び出す。

javaプログラマのためのMok Objectsというフレームワークがあるので、サーブレット環境でのテスト用クラスもある。

EasyMockはモックオブジェクトを動的に作成するためのJavaAPI。対応するモックオブジェクトに対して記録モードと再生モードを指定して使用する。オブジェクトが記録モードのとき、注目すべきメソッドを呼び出し、希望する返り値を指定する。そして再生モードにして、メソッドを呼び出すと指定した返り値が受け取れる。残りのメソッドは呼びだれると実行時例外を起こすが定義は必要ない。他にもメソッドが特定の値を何かい返すか指定したり、voidを返すメソッドが実際によぼれたことを検証するオプションもある。

サーブレット環境ではモックオブジェクトに代わる方法としてCactusという重いフレームワークを使う手がある。

演習
指定されたメソッドをもつMP3プレーヤーのコントロールパネル用のシンプルなモックオブジェクト(手動)を考える


第7章 良質なテストの特性
 ユニットテストは強力な魔法であるが、不適切に作成、実装されるとテスト時代の保守とデバッグにとても多くの時間を費やすことになり、プロジェクト全体が損害をうける。
 良質なユニットテストが問題を起こしにくくすることを証明するために、ユニットテストが実行された(assertのある)モジュールとないモジュールで問題の発生数の統計をとると、テストされているモジュールほど問題がないとわかった。

良質なテストの特性A-TRIP
・Automatic(自動)
 テストの実行とテストの確認が自動でないといけない。特に確認はテストがすべき。
 テストの実行はIDEのボタン一つで実行できる簡単なものでないといけない。モックオブジェクトなどを使ってテストに必要なものも自動で用意されるようにする。コードがチェックインされたら自動でテストするような無人のチェックシステムが必要。人間はテストしないことがあるので。

・Thorough(徹底)
 失敗しそうなことすべてをテストする。網羅性を高めるにはコードカバレッジツールを使用するとよい。バグはソースコード全体に均等に分散されるわけではなく、ある領域にままって集まる傾向がある。バグの塊であるコードは破棄して、ゼロから書き直す方が安価で苦痛はすくない。

・Repeatable(繰り返し可能)
 すべてのテストが任意の順序で繰り返し実行できて、同じ結果をださなければならない。データベースやWebサーバのような環境はモックオブジェクトでつくりだし、開発者用の分離された実験用の「砂場」が必要。そうでないと本物のバグでないテストの問題による錯覚で時間を浪費する。

・Independent(独立)
 テストを作成するときには必ず一つのことだけをテストする。
 テストが失敗したらコードのどこに隠れたバグがあるか明らかになるべき。
 個々のテストを任意の順序で実行できるようにすべき(setupとreardownメソッドを使う)

・Professonal(専門的)
 テストコードは実際のコードと同じように同じようにかく。同じようなコードを何行も繰り返し、何の関数もオブジェクトもない地道なことを行うコードを作成すべきではない。テストを作成する目的だけでテストを作成すべきではない。テストコードはバグが含まれる可能性のあるメソッドに関して興味深いことすべてをテストする必要がある。
 また、テストコードは本番コードと同じくらい作成する必要があると考えて間違いない。本番コードと同じくらい専門的にきちんと整理し、適切な設計と分解をおこなわなければいけない。

テストコードが正しいことを確認する方法
・バグの修正時にテストを向上させる
・バグの導入することでテストを検証する

バグの修正方法
1 バグを識別します
2 失敗するテストを作成し、バグが存在することを検証する
3 今度はテストがパスするようにコードを修正する
4 すべてのテストが依然としてパスすることを検証する
「これと同じような問題が他にもどこかで起こる可能性はあるか」と自問する。
プロジェクト全体に学習したことを適用する。新たにみつけた知識を適切なすべてのユニットテストに反映する。そうすることで類似のバグすべてをとらえたことになる。

テストが正しく作成された確信がないときは、検出しようとしているバグを本番コードに恋に含ませて予想通りにテストが失敗することを確認する。
例としてデータベースに口座を追加してその口座をみつけようとしているテストメソッドをあげていた。口座を追加するとき単に値を返すだけにして検索が失敗するようにする。


第8章 プロジェクトのテスト
 プロジェクトの全員がユニットテストを行うことで生じる問題

テストコードの格納場所
 小規模なプロジェクトなら本番コードと同じディレクトリにテストコードを置くので十分。しかし、これでは本番コードのディレクトリ内にテストコードが散在してしまうデメリットがある。
 邪魔にならないサブディレクトリtestにテストコードを入れる場合は、テスト用に本番コードのサブクラスを作成しない限りprotectedなどのメンバにアクセスできないデメリットがある。例をあげて説明していた。
 並列ツリーは本番コードと同じパッケージにTestクラスを格納するが、ソースコードは別にすること、両方のツリーのルートディレクトリをCLASSPATHに置くのが必須。ディレクトリ構造は同じにする。
 いずれにしてもチームで一貫した方法で行うことが大切。

テスト作法
 チームメンバと一緒に作業しているときは何らかのバージョン管理を使っているのが普通。チェックインする前に完全なユニットテストを行いテストをパスすることが必要。また誰かか自分のコードにアクセスしたらすぐに、あらゆる場所にあるすべてのテストがパスする必要がある。「すべてのテストは常にパスする」が大切。
 コードに関する違反
 ・不完全なコード(1つのクラスファイルだけをチェックインし、そのファイルが依存する他のファイルをチェックインするのを忘れるなど)
 ・コンパイルできないコード
 ・コンパイルできるが、既存コードをコンパイルできなくするような、既存コードを破壊するコード
 ・対応するユニットテストのないコード
 ・ユニットテストが失敗するコード
 ・対応するテストはパスするが、システム内の別の場所にある他のテストを失敗させるコード
コードに対して矛盾する変更を行う必要がある場合やシステムの別の場所で他のテストを失敗させる要因となる変更を行う場合は、プロジェクトで使用している方法やプロセスに依存するが、すくなくともチーム全員がビルドが壊れていることを把握している必要はある。


テストの頻度
 一般的な指針として
 ・新しいメソッドの作成・・・ローカルのユニットテストをコンパイルして実行
 ・バグの修正・・・テストを実行してバグを明らかにする。コード修正を行いユニットテストを再度実行する。
 ・コンパイルの実行・・・ローカルのユニットテストを実行
 ・バージョン管理への個々のチェックイン・・・すべてのモジュールまたはシステムのユニットテストを実行
 ・常時・・・専用マシンは1日中何もない状態から完全なビルドとテストを自動的に実行している必要がある。
なるべく常時ビルドをおこなうのを推奨していた。

テストとレガシーコード
 プロジェクトがユニットテストのない大量のコードをすでに保持している場合どうするかは、コードがどのような状態かによる。必要とする個々の部分に容易に到達できるような適切に分解されたモジュールであれば、ユニットテストを容易に追加できる。コードの状態が複雑に絡み合った「大きな泥団子」なら大幅な書き直しなしにテストすることは不可能に近い。
 既存のコードのテストできるすべてのコードに対してユニットテストを追加するのはあまり達人的ではない。労力に見合う見返りをうけるためには、ほぼ壊れているコードから最初にテストを行うほうがいい。
 もっとも重要なのは「逆行」を防ぐこと。保守の修正と強化を行うことで既存の特性にバグが発生するというデススパイラルを回避すること。新しいコードが既存のコードを何もこわしていないことを確認するために回帰テストとしsてJUnitテストを行う。レガシーコードに対応するときには全体を網羅する必要はないが、痛みのひどい部分だけ摘要する。
 例として、オブジェクトデータベースアクセスに使用される下位レベルのライブラリにバグがある場合のアプリケーションレベルでの修正がのっていた。名前にスペースが入っているとアプリケーションが壊れるのだが、これを修正したところ、こんどはディレクトリにスペースが入っていると壊れるという別のバグが発生。この時点で下位レベルAPI呼び出しをテストするJUnitテストを作成。コードがリポジトリにコミットされるたびにユニットテストが自動実行されるようにしたところ、テストが2日連続で失敗。バグは固まっているのだ。そして、テストがなければ毎晩ビルドのたびに不正なコードが会社全体に伝播されていしまう。2度現れた問題にはその週のうちにJUnitを作成するという規則を作ったそうだ。

テストとレビュー
 著者はコードのレビューを推奨していた。その順番
1 テストケースやテストコードを作成する
2 テストケースやテストコードをレビューする
3 レビューを受けてテストケースやテストコードを修正する
4 テストをパスする本番コードを作成
5 テストコードと本番コードをレビューする
6 レビューをうけてテストコードと本番コードを修正する

レビューはチームの意思疎通を向上させるという意味で有効で効率的。
何度も発生するよくある問題を記録することで、よりシステムを安定させることができる。


第9章 設計上の問題

テスト容易性を保持した設計
 テストできるようにコードを明示的に設計することで、コードを適切に分解し(内気にする)コードの保守を容易に行える。例として何かを計算して、その秒数sleepするコードをテストする。失敗する可能性があるのはシステムのSleep呼び出しではない可能性が高い。必要なのは秒数が正しく計算されるかテストすること。常に「このコードをどのようにテストするか」考えることで、設計上の誤りを見つけることができるはず。

テストのリファクタリング
 例としてレシピ管理システムのコードをあげ、初心者が書いたコードではテストが困難であることを示す。GUI操作で必要な部分にたどりつかないといけないから。そして、レシピデータのテストを容易に構築し、レシピが画面、ディスク、ネットワーク、その他どこでも行き来できるようにするために、レシピを保持するためのオブジェクト作成から始め、コードを作成。そしてGUIコードを使用しないでディスクへの読み書きをテストする本物のテストケースを作成。テストを行い問題を発生させ「この問題がコードの他の場所でも起こる可能性はあるか」自問自答する。そして問題を修正するという手順をとっていた。結果といして設計がとてもきれいになることを示していた。

クラスの不変条件
 クラスの設計を改善する方法はクラスの不変条件の定義と検証を行うこと。
 クラスの不変条件が適用される可能性がある領域
 ・構造的領域。データの構造的な特性、怜として受注システムでは各明細は何らかの注文に属さなければならないなど。不変条件をチェックすると、運がよかったとうだけでテストをパスしていないか確認できる。
 ・数学的な領域。データ構造の論理的なモデルを考察。例として銀行口座の貸借は、残高に対応づけられなればいけない。境界条件ともいえる。
 ・データの一貫性 オブジェクトは同じデータを異なる方法で示す。例、ショッピングカートの商品一覧、売上総額、カート内の商品の総数は密接に関連する。詳細な商品一覧から他の2つの値を得られる。これらの値は不変条件として一貫していなければバグがある。

テスト駆動設計
 テスト提唱のメソッドを作成する前にテストする技術。
 テストを先に作成することで、コードの実装者としてでなく、コードの利用者になれる。するとインターフェースを実際にどのように使用するかについて、はるかによく理解でき、その設計を改善する機会を見いだせる。例として印刷ページに特殊な書式設定を行うルーチンを作成する。テストコードを先に作成すると用紙のサイズ指定を別のオブジェクトに抽出することが必要とわかり、テストは整理され読みやすくなり、使用するアプリもきれいになる。

演習として、2つの日付の間にある営業日数に基づいて利息を計算する利息計算器をテストファースト設計を使用して1度に少しずつ作成する。

無効なパラメータのテスト
 入力データの妥当性を確認するのは誰かについては場当たり的な解答しかないが、特に自分と関係がある入力データの側面は自分で確認すべき。しかしこれでは多くの部分で確認が行われ時間と労力が無駄になる。すぐれた設計では妥当性を確認する部分をあらかじめ構築して、システムの小さな既知の部分に局所化する。
 一般的に最も容易に採用できる規則は「入り口で野蛮人を遮断する」方法。自分が入力データに責任を負っているなら、それを確認するのに時間を費やすべき。

付録A 落とし穴 不注意から繰り返し浮上する問題や誤解
1 コードが動作する限り問題ない・・・テストのないコードやユニットテストが失敗したコードは壊れている。
2 スモークテスト・・メソッドが最後まで失敗せず実行されればそれでパスと考えること、しかしデータやその他の古い米の妥当性を確認しないのは錯覚のテスト。
3 自分んおマシン上での動作
4 浮動小数点の問題
5 時間のかかりすぎるテスト・・・平均よりも時間がかかるテストは抜き出してどこかにまとめる。そして1日1度などの実行にして、他のテストの邪魔にならないようにする
6 失敗したままのテスト
7 一部のマシン上でのテストの失敗
8 実行されていないmain・・・JUnitのTestRunnerではmainは実行されない、設定コードは置かないこと。

付録B JUnitのインストール

付録C JUnitスケルトン・・・テストを実行する決まり文句が記述されているテンプレート

付録D リソース
 Web上のリソース・・・Ant、CactusなどのリソースURLがのっていた。
 参考文献

付録E ユニットテストまとめ
 一般原則、テストする内容、問うべきこと、適切なテスト、境界条件

付録F 演習問題の解答



第3部 プロジェクトの自動化

第1章 はじめに
 プロジェクトの作業の一部をコンピュータにやらせ、人間は人間が得意とすることだけを行う方法を解説。

 自動化の種類
 ・コマンドによる自動化・・・すべてのマシンで同じ状態になるようにビルドを生成するステップを実行したり、アプリケーションを一貫して配置するために決まりきった指示を出すスクリプト
 ・定期的な自動化・・・コマンドの自動化を手動で実行する必要がないように、スケジュールにそのコマンドを入力する。
 ・トリガによる自動化・・・サイトにエラーイベントがあるか定期的に見張りポケベルに知らせるモニタなど、何らかの重要なイベントが発生したときに自動的に実行する。

自動化を開始するために必要なこと
・バージョン管理
・自動テスト(結果を自分で確認するテスト)
・スクリプト化
・通信デバイス

なぜ自動化する必要があるのか
 ビルドを組み合わせ、リリースコマンドでいっぱいのチェックリストを尊守し、サーバに存在するコードをコピーし、実行しているプログラムを監視すろいった作業よりも、プログラマには行わなければいけないことが他にある。また、自動化された手続きは正確で一貫性があり、繰り返し可能なので、自動化することで自信が持てる。またドキュメント化の必要性も軽減する。ビルドやリリースの生成方法を説明する代わりスクリプトの実行方法を示せばよい。作業を軽減し、重要な手続きを必要な回数だけ実行できる

いつ自動化するのか
 手動での作業に飽きた時はいつでも。経験上は2回より多く実行される手動のタスクは自動化すべき。
 エラーは退屈から自然に発生する。繰り返される主導のタスクに一貫性と正確性を持たせる必要があるときは自動化を導入する。ただし、自動化の時間が、自動化によって節約される時間より長くてはいけない。

いつ自動化を実行するか
 自動化のロードマップがのっていた。
 1ステップのビルド(コマンド指定)→定期ビルド(毎時)チェックアウト+コンパイルとテスト→プッシュボタンリリース(毎週)ブランチテスト、パッケージ化リリース→インストールと配置(毎月)自動更新・インストール・テスト・納品→最初に戻る。
このサイクルの真ん中に監視(常時)があり携帯電話や視覚デバイスRSSを使う。


第2章 ステップビルド
 コードのビルドとテストを自動化する
 ビルドプロセスはソフトウェアを大量生産するレシピ。

CRISPなビルドの作成
 ・Complere(完全)
  ビルドプロセスの実行前や実行後にファイルを追加するようなことはない。自立している。

 ・Repeatable(繰り返し可能)
  CVSなどのバージョン管理システムにビルドファイルとビルドのすべての入力を格納すること。そうして前のソフトのリリースが容易に作成できる。

 ・Informative(詳細な情報)
   ソフトウェアの状態を常に把握できるように有益な情報を発信する。成功すれば動作するという自信になり、失敗すれば問題をデバッグする時間を節約できる。

 ・Schedulable(定期実行可能)
  ビルドを完全かつ繰り返し可能にすることで、ビルドをスケジュール通りに効率的に実行できる

 ・Portable(移植可能)
  ビルドの実行が特定のIDE、マシンのIPアドレス、実行元のディレクトリに依存しない。Windows上でUnixのアプリをビルドするという意味ではない。

プロジェクトのディレクトリ構造をつくる
ルートの下にsrc, test, vendorというディレクトリをつくりこれはバージョン管理内。ビルドの出力するbuildディレクトリなどを解説。

最初のビルドの作成はコマンドラインによって行いそれをスクリプト化していた。

Antによるビルド
Ant・・・Javaプロジェクトに特化したオープンソースのビルドツール
 メリット Antのビルドファイルは移植可能、Antはファイウrの依存性を追跡する、Javaソースファイルのコンパイル方法を理解している。またJUnitテストを実行するタスクも含まれている。他にもタスクを拡張できる
 デメリット ビルドのレシピをXMLファイルで表現しなければならない。

Antのビルドファイルの作成方法を解説
JavaプロジェクトのビルドにはmakeよりAntが適しているといっていた。Antは専用ツールでmakeは一般ツールだからと。


テストのコンパイルと実行、テスト結果を表示する、テストスイート作成をAntで解説。

出力が再現できるならビルドの出力をすべて削除するAntのターゲットを定義する方法を解説。

複雑なプロジェクトをビルドする際のビルドのスクリプト化の解説
Groovyというスクリプト言語を使っていた。

コードが蓄積するまでビルドの自動化をおくらせてはいけない。
ディレクトリが決まったらすぐに行おう。
しかし、コードが溜まってしまっているから遅すぎるということはない。


第3章 定期ビルド
 1ステップのビルドプロセスはコマンドによる自動化のメリット。
 次はコンピュータにボタンを押させるという定期テストの段階に進む。
 一定の間隔で実行されるビルドは問題を迅速に発見し、修正を容易にする。

 cronによる定期実行方法解説・・・バージョン管理あから最新のコードをチェックアウトしてビルドファイルを呼び出し、コードのビルドとテストを行う。ログファイルにビルドの結果を記録する。
 ただ、結果をWebに掲示したり電子メールにしておくるなどの場合独自のビルドのスケジューラを入手したほうが達人に近づける。

 CruiseControlによるビルド解説。
  ビルドマシン選択
  インストール
  ビルドワークスペース用意・・・ビルドディレクトリ作成、プロジェクトチェックアウト、ログディレクトリ作成
  デリゲート用ビルドファイルの作成
  ビルドプロセスの設定・・・プロジェクトの定義、ビルド起動、変更の確認、ビルド間隔定義、ログ保存。XML形式でテスト結果の生成、ビルド結果の公開

 CruiseControl実行解説

 CruiseControlにビルド状況の公開を行わせる方法・・・電子メールで知らせる、するとWebページからビルドの履歴が取得できる。

 CruiseControlを大規模プロジェクトで使用している例


第4章 プッシュボタンリリース
 ビルドやテストは重要だが、納品しなければ意味がない。リリースが最終目標。
 リリース手順を自動化する。

プロジェクトが複雑になる前にソフトウェアのリリース生成を開始すべき。

リリースの中身
 名前とバージョン番号で一位に識別される。通常名前は市場が手イグするソフトウェアプロダクト名に似ている。バージョン番号はメジャーとマイナーがある
 各リリースはリリース内に含まれる昨日軍によって定義される。エンドユーザに価値をもたらす機能が制作されたときリリースを生成する。
 リリースには必要な内容がすべて含まれている、ドキュメントも含む
 リリースのインストールに複数の手順が必要になる場合は、インストールスクリプトまたはユーティリティを1回実行するだけで必要な手順がすべて行われる。

架空のプロジェクトについてリリースの例をあげる
 最初はQAチーム向けリリースを行い、作業が増えないうちにリリース生成を行う。
 リリースに向けて作業の同期をとる
 プログラマでなくリリースマネージャになって開発ディレクトリでないきれいな場所でバージョン管理リポジトリから現在のファイルをチェックアウトしてビルドし成功を確認。
 リリースブランチを作成する。
 リリースブランチをチェックアウトしてテスト集成しコミット
 リリースを顧客が扱いやすい形にパッケージ化する・・・配布ファイルの作成。標準的な配布ファイルの中身がのっていた。ZIPかtarが一般的。これを行うスクリプトを作成する例。
 普通は無いが、テスト用追加配布ファイルのパッケージ化の例もあった。
 配布ファイルの生成
 配布内容のテスト・・・ファイル内容の比較(diffコマンドなど)、アプリの実行、テストの実行
 模擬的なインストールを行う
 配布ファイルの確認作業が終わったら、ブランチディレクトリ内の現在のコンテンツにタグをつける。これでいつでもこの時点までタイムマシンで戻ることができる。
 リリースの出荷
 
これまでの内容を自動化する。変化するのはバージョン番号だけなので、リリース手順を2つのスクリプトで自動化する。
1本流ディレクトリにある内容のテスト
2 リリースブランチの作成
3 リリースブランチのチェックアウト
4 リリースブランチのビルドとテスト
ここまでは新しいリリースブランチを作成するたびに実行すること。
5 リリース用配布ファイルの作成
6 配布ファウルの内容のテスト
7 リリースのタグ付
8 QAチームへの配布ファイウrの出荷
5-8はリリースブランチが作成されたら行う

スケジューラに登録してデイリー配布を生成する方法。毎日最新のコードが実行できる。


第5章 インストールと配置
 ソフトウェアをユーザの手に届ける皇帝の自動化

 エンドユーザの望みはただ一つ、配布ファイルの内容を使うこと。だからインストールはできるだけ容易であるべき、ZIPなら展開するだけ。

 理想的なのはうまくインストールできないユーザから連絡がこないこと。
 同じインストールの問題が何度も発生する場合は対策が必要。トラブルシューティング用チェックリストから一歩進んで診断テストでの自動化を行う。

 JUnitを使用してインストールにいつどのような理由で問題が生じたか診断する方法解説。
 この診断テストは必要に応じてユーザに配布する追加のZIPファイルにするとよい
 ユーザがすべての診断テストを1度に実行できるようにJUnitのテストスイートにすべてのテストケースを格納する。

インストールイメージの拡張
 ZIPは展開するだけなので、追加のインストールステップは実行できない。
 インストーラで手順を自動化する方法解説・・・NS.ISの例を解説

ホストされるアプリケーションの配置
 サーバへの配置が必要なJavaアプリケーションのインストール自動化
 配置モジュールの作成方法解説。サーバの動的配置をつかうとかAntのタスクを使って自作する方法など。

インストールされたアプリケーションの自動更新
 定期的に更新をチェックする自動更新プログラムがあるのが理想。

 自動更新プログラムの作成
 1 敵的またはイベントに基づいて、更新を開始する。
 2 プログラムから既知のWebサイトにアクセスして、現在のバージョン番号を取得する。
 3 現在のバージョンがインストールされているバージョンよりも新しい場合は、現在のバージョンを自動的にダウンロードする。
 4 新しいバージョンが利用でき、インストールすべきであることを知らせるダイアログボッスを表示する(オプション)
 5 最新のバージョンをインストールする

 Java Web Startを使った自動更新プログラムの作成例

第6章 監視
 トリガによる自動化を使って、ビルドの監視と実行中のプログラムの監視を行う。

定期ビルドの監視
 携帯電話へのビルドの結果の送信・・・CruiseControlへのemailパブリッシャーの追加方法
 RSSシグナルのブロードキャスト・・・CruiseControlへのXSLTパブリッシャーの追加方法

視覚デバイスからのフィードバッグ
 ビルドモニタやビルドの成功を示す泡の例を表示。一目でビルドの成功と失敗がわかる

Javaプロセスの監視
 配置したソフトウェアの監視を自動化する方法。Unixのシェルスクリプトでjavaプロセスが実行されているか監視して異常があったらemailに知らせる例。もちろん再起動もついている。

Webアプリケーションのチェック
 curlやwgetという強力なHTMLスクレイパーがあるのでそれを使った定期的チェック方法を解説。

ログファイルの監視
 javaアプリが出力するログファイルを監視するRubyプログラムの例。FATALを含むメッセージを監視。

log4jでの監視
 アプリケーションがlog4jの」ような設定可能なログ出力プログラムを使用すると、外部の設定ファイルを変更するだけで、アプリケーション内部で発生するイベントログを捉えることができる。
 log4j動作方法と監視用アベンダの組み込み法帆う

RSSによる監視メカニズムの構築
 重要なイベントであるが、発生しても即座に通知を受ける必要がない場合など、log4jでRSS経由で通知が送信される方法を解説

デバッグコマンドによる健全性監視
 リモートアプリケーションが不具合の兆候を示しているとき、その原因をしらべるデバッグコマンドを作る。
 出力に
 ・JVMの統計
 ・ログに最後に記録されたエラーメッセージ
 ・システムの同時利用ユーザ数
 ・開いているデータベース接続数とコネクションプールの大きさ
 ・主なWebページの平均応答時間
 これをWebインターフェースで実現する方法解説。

クラッシュレポートの作成
 スクリプトまたはバッチファイルで以下のような情報を収集
 ・ログファイル内の最後からX行のメッセージ
 ・アプリケーションのバージョン
 ・OSとJVMのバージョン
 ・主な環境変数とシステムプロパティ
 ・動作中の他プロセスの名称

繰り返し可能なビルドをまとめて、自動的に実行されるように整理
インストーラを作成し、アプリケーションの配置が行える
クライアントの環境にインストールされたソフトのテストを可能にする
世界中のどこにいても問題が発生したときには通知されるような仕組みを用意する。
そうして人間は興味深いコードの開発に遷延する。


付録A リソース・・・Antなどの場所 参考文献

付録B プロジェクトの自動化のまとめ