Skip to content.

Sections
Personal tools
You are here: Home » コミュニティ » XP-jp » XP関連記事 » わたしたちのプチXP体験談

Document Actions

わたしたちのプチXP体験談

初版 2002, Apr.8
初出 Java PRESS vol.24
(株)永和システムマネジメント
田中 真弓
飛山 祥子

   はじめに

みなさん,こんにちはー(音声は変えてあります)! 今日は,私たち二人で挑戦してみた「プチXP」の体験談をお話したいと思います. XP(エックスピー)は,eXtreme Programming(エクストリーム・プログラミング) の略で,Kent Beck らによって提唱されているまったく新しいソフトウェアの 開発方法論です.まだ読まれていないかたは, 『XP エクストリーム・プログラミング入門』, 『XP エクストリーム・プログラミング導入編』などの書籍を読むか, あるいは,この記事の最後に紹介する Web ページを参照してください. いま,XP関係の本や記事があちこちに出るようになってきていますが, 「ほんとうにうまくいくの?」とか「うちの会社じゃ無理だよね」なんて声も 聞こえます. 私たち二人も,XPに興味はあるのですが,なかなか実際には やってみることができませんでした.今回,マネジャの理解もあって 「とにかくやってみよう!」と気楽に始めたのが,この「プチXP」です.

XP のプラクティスの中には,すぐに始めるのが難しいものもあります. 例えば,顧客をプロジェクトに一人よんでくる「オンサイト顧客」 なんかは,日本ではなかなか難しいかもしれませんし,残業を しない,という「週40時間」というのも現実にはきびしいでしょう. そこで,今回は「できることを,できる範囲でやる」という心構え でこの体験にのぞんでいます.

3週間の実践を終えて,ようやく形あるものになりましたので,報告も兼ねて この記事を書くことになりました.今XPを猛勉強中の私たちですが, かざらない「なま」の声,「なま」の現場をレポートしたいと思います. どうぞよろしく!


   プロジェクトのかたち

少しこのプロジェクト概要について説明したいと思います. プロジェクト名前は,SSS (エス・エス・エス). 「Simple Schedule Service」(シンプル・スケジュール・サービス)の略です. 私たちの会社では,「Webサービス同好会」というサイト ( http://objectclub.esm.co.jp/webservice/ml.html )を立ち上げていて, そこで,今はやりの「Webサービス」の実験を行っています.そのサ イト向けに,簡単なサービスを実装しよう,というプロジェクトです.

開発期間は3週間でワンリリースです.実験的に行ったプロジェクト なので,一回リリースして終りということになりました.XP では プロジェクトを「リリース」に分解し,さらにリリースを「イテレーション」 に分解します.今回, イテレーションは1週間をベースに考えましたが,長さは変則的です. つまり,イテレーションに入力するストーリーの数や大きさで, 1イテレーションの長さを変えています.

第1リリース
第1イテレーション 第2イテレーション 第3イテレーション
3/7-3/14(= 5営業日) 3/14-3/15(= 2営業日) 3/18-3/29(= 9営業日)

スケジュール

SSS は,言って見れば簡単なリマインダー(備忘録)サービスで,自分の スケジュール(内容,日時,通知先)を登録しておくと,その予定をメールで 知らせてくれる,というものです. 今回は,Webサービスの勉強も兼ねてこのプロジェクトをスタートさせました. Web サービスも XP もはじめての体験です.さて,うまくいくでしょうか?


   使った技術など

基本的な環境として,以下のものを使いました.

データベース:PostgreSQL 7.1.3
OS:Linux 2.2.18 (Turbolinux)
言語:Java (一部 C#)
テスティングフレームワーク:JUnit 3.7
構成管理:CVS 1.10.6
Webサービスフレームワーク:GLUE 2.3

開発環境

見て頂ければわかるとおり,ほとんどがオープンソースのツール群で 構成されています.XP みたいにフットワークの軽い手法には,やっぱり オープンソースがぴったりくるみたいです.試してみる,っていうときに お金がかかるものは手が出しにくいですよね.それに,最近はオープンソース の方がWeb上の「お助けドキュメント」が充実しています.困ったときも検索サイトで キーワード検索すれば,たいていは解決します. また,今回はせっかくのWebサービスなので,メールの送信に関しては 外部の Web サービスを利用することにしました.

開発は,自分たちのパソコンからネット上の Linux マシンにログイン して行っています.Windows のデスクトップになれた私たちには 最初ちょっともどかしかったのですが,使うコマンドも限られていたので すぐになれちゃいました.コマンドラインからの操作は,GUI にはない サクサク感があって,慣れると快適でした.


   エックスピー!

XP には,「12のプラクティス」といわれる実践項目があります(コラム参照). 極端に言えば「この12個さえ守れば開発はうまく行く!」という ありがたい教義なのですが,実際の開発現場では,なかなかすべてを実践する 分けには行かないでしょう.もともと,XPに限らず開発プロセス, 開発方法論というものは,現場にフィットしなければ意味をなさない ものです.XP自身も,実際はもっと柔軟に考えられており,組織に応じて プロセスをカスタマイズすることがある程度前提となっています. 今回は,XPのプラクティスのうち, 厳選したものしか取り入れていません.できるものだけやる,という 気ままなスタンスでXPに取り組んでいます. 次のリストが,実際に採用したプラクティスです.

  • 計画ゲーム
  • スタンドアップミーティング
  • メタファ
  • ミッションステートメント
  • 受け入れテスト
  • スパイクアーキテクチャ
  • テストファースト
  • ペアプログラミング
  • コードの共同所有
  • リファクタリング
  • シンプルデザイン
  • コーディング標準
  • 用語辞書

この中には,Kent Beckの「12のプラクティス」に書かれてないものが あることに気付きましたか? これらは,

  • XPで実際によく行われているが,プラクティスに昇格していないもの
    • スタンドアップミーティング
    • スパイクアーキテクチャ
  • 今回,マネジャの提案で採り入れたオリジナルプラクティス
    • ミッションステートメント
    • 用語辞書

です.では,実際に上のプラクティスを簡単に説明し,私たちがどのように 実践したかを紹介していきましょう.

計画ゲーム

これは,全員で行う計画づくりのミーティングです. イテレーションの最初に,ゲーム形式のプランニングを行います. 本当は,顧客も入ってチーム全体で行うミーティングですが, 今回は顧客なし. マネジャが仕様の権限をもっているとみなして,顧客のかわり をしてもらいました.ストーリーカードにやりたいことを書いてもらい, それを私たちで見積もります.それを見て,マネジャが優先順位を決める という流れで進みました.

本来は,計画ゲームは「リリース計画」と「イテレーション計画」に 分かれます.リリース計画で,1回のリリース分の計画を立てます. リリースは,何回かのイテレーションに分割されます.そのイテレーション 毎にイテレーション計画があります. 今回は,1リリースだけの開発で期間も短いため,簡略した方法で行いました. まず,とにかく最終的にやりたいことを全部カードに書き,それを見積もる. そして,優先順位をつけて1イテレーション分だけの計画を立てる, という方法を取っています.あとで実況中継をしたいと思います.

スタンドアップミーティング

これは,毎朝の全員参加ミーティングです.私たちのチームは机を向かい合わせた 「島」で仕事をしていたので,朝,9:30 にみんなが立ち上がって簡単な 会議をしました.これは,XPの本にはプラクティスとして位置付けられて いません.でも,私たちにはとても重要なものに思えたので,あえて, プラクティスとして取り上げています.

スタンドアップミーティングでの会話は,

  • 昨日までの作業での問題点.
  • 昨日までの変更で,全体に影響がありそうなもの.
  • 今日やるつもりの作業
  • ペアリング

が主です.今回は,ペアは固定だったのでペアリングの時間は とりませんでした.通常は,タスクを持っている人が「誰さん, お願い」っていう風に声をかけます.もし特定の分野に強い人 が分かっていれば,その人をコーチが推薦することもあります.

スタンドアップミーティングは,15分以上の時間をかけないことが肝心です. チームによっては,キッチンタイマーをかけるところもあるそうです.細かい 話になりそうなら,司会者は「それについては誰と誰で後で話そう」などと話 を区切らないと行けません.それから,いちばん大事なのは,問題が起きた場 合に犯人探しをしないことです.原因を見つけることは重要ですが,その対処 に焦点をあてて話ましょう.

メタファ

これは,システムを一言で表す比喩です.ちょっと難しいプラクティス ですが,今回やってみました.XPをやるときによく問題になる, 「悪名高き」プラクティスです.日本でうまくやっているのを聞いた ことがありません.

よく例にだされるのが,SETI@HOME プロジェクトの「蜂の巣」 メタファーです.このプロジェクトは,宇宙線(?)のデータを 解析して地球外生物の存在を探る,というもの. インターネットに継ったコンピュータのCPUの空きを うまく使って,膨大な計算を分担して行い,結果を収集します. この様子は,ちょうど蜂が密を求めてさまよい,密が見つかると それを持って巣に帰って来るのに似ていますよね.ですので, 「蜂の巣」メタファーは直感的にぴったりきます.

メタファーによって, 顧客と機能の会話がスムーズに行ったり,将来の機能拡張を考えたりできます. もう1つの重要な点は,システムの中に出て来る名前(クラス名やメソッド名) に一貫性がでることです.開発者間のコミュニケーションがスムーズになり, コードの共同所有やペアプログラミングを支援します.

今回「ホテルのモーニングコール」というメタファーを作って見ました. ですが,イメージは共有できたものの,内部のオブジェクトに関する 命名やおおまかな動作についてはほとんど訳に立っていません.そこで, メタファーの第2の役割を補強する目的で,「用語辞書」というプラクティス を入れることにしました.あとで計画ゲームの実況中継に,メタファー が出てきます.

ミッションステートメント

これも,オリジナルのプラクティスです.目的は,プロジェクトの中で 実際のシステム構築以外に自分なりの目標をもつ,ということです. 例えば,「今回はWebサービスを自分のものにするぞ!」とか,そんな 意気込みです.このプラクティスは,マネジャが新しく提案したものです. どうも,XPで行うこのプロジェクトが「お遊び」にならないか,気に したようです.これによって,目標をもってこのプロジェクトに 参加することを期待していました.

受け入れテスト

顧客が受け入れのためのテストを書きます.これは,マネジャにお願いしましょう. このテストも JUnit で行いました.作るものが Webサービスですので, ツールで自動生成されるクライアント側のプロキシを使えば JUnit でも簡単にテストができます.Web サービスって便利!って思いました.

スパイクアーキテクチャ

これは,XPの本にはプラクティスとして位置付けられていません. 計画ゲームの中に含まれるのかもしれませんが, XPの開発では実際によく行われているようです.開発に 入る前に,簡単なアーキテクチャの「種」にあたるものを作って しまうのです.ガチガチの完成したアーキテクチャではなく, シンプルでおおまかな構造をある程度決めてしまいます. これによって,スタートが切りやすくなります.何もないところから, さあはじめよう,って言っても難しいですからね.

テストファースト

これは,開発者から見た,「XPの真髄」にあたる部分でしょう.

  1. まずテストを書く
  2. テストを通すコードを書く

という作業の繰り返しによってコードを書いて行くものです. JUnit によるテスティングが必須です. 今回は,これを徹底的に行いました.やってみると結構難しいのですが, グリーンバー(JUnit の成功)は快感です.もう「やみつき」って感じです.

ペアプログラミング

二人ペアでプログラミングするもので,略して「ペアプロ」です. でも,私たちは二人しかいないの で,同じペアでずっとプログラミングすることになりました.でも, ときどき,マネジャやコーチにも,臨時でペアになってもらうことも ありました.テストも コーディングも設計もリファクタリングも,ずっとペアでやっています.この プラクティスは,「書いているそばからレビューをしている」 と考えることもできます.でも,役割はその都度交代しています. キーボードを使って実際にコードを打ち込む人を「ドライバー」, 見ている人を「パートナー」と呼びます.「パートナー」は 名前やスペルのチェックをしたり,次のテストを考えたり, 全体との整合性を考えたりします.

ペアプログラミングをうまくやるには,ある程度の「心得」が必要です. この心得を10箇条として書きました.

ペアプログラミング十箇条

  1. ドライバー,パートナーは5~10分毎で適当に交代しよう.ドライバーは引き際が肝心.パートナーの助言が多くなったら交代.
  2. やることを紙に項目として書き出そう.終わった項目を横線で消そう.
  3. コードより先にテストを書こう.テストをパスさせるための最もシンプルな実装をしよう.
  4. パートナーは,ツッコミの要領で助言しよう.
    • もっとシンプルな方法はないか
    • コードは意図を表現しているか
    • クラスやメソッド,変数の名前は意図を表しているか.
    • タイプミスはないか.括弧の数は合っているか.
    • テストは先に書いたか.
    • 次のテストはどう書こうか.テストし忘れていることはないか.
    • 全体から俯瞰してバランスはとれているか.ヘンな方向に突き進んでいないか.
    • コーディング標準にあっているか.
  5. パートナーは,じれったくなったら「わたしにやらせて!」と言おう.
  6. パートナーは,理解できないコードを見たらドライバーに聞こう.「なんでそうなの?」
  7. ドライバーは,パートナーの助言にいつでも耳を貸そう.そしてその助言に返事をしよう.
  8. ドライバーは,行き詰まったら助けを求めよう.このメソッド,ちょっとお願いできないかな?
  9. 腹が減ってはプログラミングはできぬ.一緒にお菓子を食べよう.
  10. 楽しくやろう.Enjoy Pair Programming!

ペアプロの心得

コードの共同所有

チーム全員でコードを共有します.といっても二人なので,問題は ありません.だた今回,CVS(Concurrent Versions System)を積極的に 導入して使ってみることにしました.二人ともちょっとさわった ことはあるのですが,本格的に使うのははじめてです.CVS は, RCS(Revision Control System) の後継にあたります (実は内部でRCSを使いる).RCS に比べて CVSの良い点は,

  • ソースファイル1つ1つだけでなくソースツリーを管理できる.
  • あるペアがファイルを編集中でも,他のペアが編集できる.

というところです.編集が運悪くぶつかってしまったときは, マージすることになります.とはいっても,今回はペアが1つだけ なので,実際にぶつかることはありませんでしたけど. 今回は,リファクタリングなどを行う過程で,失敗したら一つ前の バージョンにすぐにもどれる,という点で CVS を活用しています. これはとても重要だ,と思いました.

「ペアプログラミング」と「コードの共同所有」, それに「スタンドアップミーティング」によって,チームの 仲間意識が大幅にアップします.この3つのプラクティス が,コミュニケーションという意味では XP の核になっている のでしょうね.

リファクタリング

これは,もうお馴染みですね.動いているコードをきれいにクリーニング するというものです.機能を変化させずに内部を整えるのがポイントです. それに,テストがちゃんと備わっていて,動いていることが必要になります. 勝手に触って壊してしまってはいけませんし,テストなしでは恐くて触れません. 今回,特にちゃんと「リファクタリングの時間」を取ったこともポイントです. ある程度できたと思ったら,ちゃんとリファクタリングして,シンプルで かっこいい(自分が納得できる)コードに直すのです.

主なリファクタリングは,「コードから重複を取る」ことです.3行以上の 連続したコードパターンが現れたら,メソッドとして抜きだす,というのが 黄金のパターンです.また, リファクタリングには,「名前の変更」も含まれます.ちょっと変な名前 だなぁ,と思ったら辞書を引いていい単語を探します.いい単語は, 「用語辞書」に加えます.同じ用語が一貫してコードに現れるようにします. 今回は,リファクタリングにコーチも入ってもらいました. コーチのアドバイスを受けながら,1ステップずつ変更しました. もちろん,その都度テストを全部通します.1ステップ通ったところで, ちゃんと CVS にコミットすることも大事.失敗しても,最悪前のコードに もどることができます.

シンプルデザイン

シンプルに設計する,って言われても・・・・とても難しいです. 今回は,「タスクを満たす,いちばんの近道をする」と解釈しました. どうせこの機能も後から必要になる,と思って今追加してはいけません. 今のイテレーション だけを視野に入れて設計をします.設計が近視眼的になって, 後からうまく変更が入らなくなってしまったら どうするのかって? それはそのときに直すんです.そのための, リファクタリングなんですから.それに,予定されていた機能が, 顧客の都合でやっぱりやめ,ってこともありますし.そのために, イテレーション毎に計画ゲームをやるんですから.

コーディング標準

コーディング標準は,チームに1つソースコードの標準的なフォーマット を決めるというものです.ペアプログラミングをしながら,ソースコード のインデントやカッコの付け方などで無用の議論をしたくはないですよね. 今回のプロジェクトでは,これはやったような, やらなかったようなプラクティスです. というのも,1年以上チームを組んでいると,コードフォーマット はある程度固まってくるものですよね.ですから,特にこれ, と決めはしませんでしたが,「いつものように」コーディングしました.

用語辞書

これは,オリジナルのプラクティスの中でもマネジャがいちばんお気に入り のものです.よく,「メタファ」は難しいと言われます.メタファには,

  1. 開発者と顧客のコミュニケーションを助ける
  2. 開発者間のコミュニケーションを助ける

という役割があります.特に,2 では,「名前の体系」(System of Names) を持つことが重要になります.メタファーはこの「名前の体系」を形成 することを助ける働きがあります.ですが,特に日本では,英語と日本語 の問題があります.普段の会話は日本語で行われますが,コーディング に現れる単語は,英語の方が多いようです.例えば,「予定を追加する」 というメソッドは,「addSchedule」という風になります.日々の会話の中で 「予定」と呼んでいたものが,Schudule なのか,Appointment なのか, 追加が add なのか insert なのか.システム全体で単語の 使い方がばらばらだったら,とても混乱するでしょう.ペアプロや リファクタリングの大きな障害になりそうです.

このプラクティスでは,「用語辞書」というものを最初のイテレーション で作り,一貫してそれを見ながら名前を付けるというものです. イテレーションが進むにつれて,この用語辞書は成長していきます.

用語辞書は,「用語」「英語訳」「意味」の3つを対にして書いて行きます. 例えばこんな感じです.

用語英語意味
予定schedule 予定.入力者が,予定日,内容,通知先 をつけてこのSSSサービスに登録する.
モデルmodel データの永続化を実現する機能.SSS ではデータベースに対して 予定の追加,変更,削除を行う.
...... ...

用語辞書の例
   登場人物紹介

では,実際の開発の様子を実況中継でお伝えしたいと思いますが,その前に,登場人物の紹介です.

MT - 田中 真弓

プログラミング歴4年. データベースを使った業務系のサーバーサイドJavaが得意. 最近,部署がえがありマネジャのチームに参加.

ST - 飛山 祥子

プログラミング歴2年.入社してすぐにリアルタイム系 の C++ をやってめまいを覚える.今はやっぱりサーバーサイド Java です.

KH - マネジャ

二人の上司にあたる.プログラミング歴15年. 今回は「マネジャ」,「コーチ」,「トラッカ」の役割として このプロジェクトに参加.プロジェクトを見守る役目.

YO - お助けマン

二人の先輩にあたる.プログラミング歴8年. Web 系の開発ならなんでもこい.最近 Web サービスにのめり込み, 「Webサービス同好会」なるサイトを立ち上げている. UNIX や Java にも精通している.今回は,「コーチ」でもあり 困ったときのたのみの綱として参加.

基本的には,MT と ST でプロジェクトを進めます.ミーティングには マネジャのKH も参加します.ときどき,YO も顔をだすことになると思います.

   計画ゲーム

計画ゲームの例として,一番最初のミーティングを実況中継しましょう.

はじまり -- ミッションステートメント

KH: じゃあ,はじめましょう.お菓子持って来たから食べながらやろうね (PRINGLES を配る). まず,このプロジェクト「Simple Schedule Service」 (シンプル・スケジュール・サービス)の概要は, この前話した通りです.スケジュールを入力しておくと,それを メールで知らせてくれる Web サービスです.今からは,SSS(エス・エス・エス) と呼ぶようにしましょう. 最終的に「Webサービス同好会」のコンテンツとして出したいので, はりきって行きましょう.

KH: で,ミッションステートメントは書いてきた?

ST: はい.こんな感じでいいですか?

  • Linux環境に慣れる.
  • DB(データベース)への苦手意識をなくす.

うん,グッドだね.今回の DB は Postgres だね.Linux も 初めてだっけ? 前に UNIX は少し触っているから大丈夫だと思うよ.

MT: 私はこんな感じです.

  • UMLとJavaのマッピングをスムーズに考えることができる
  • テストファーストの実践を通してテストファーストに慣れる
  • Webサービスの特徴(くせ?)を知る

KH: はい.いいですね.たぶん,UML はホワイトボードに書く ことになると思うけど,あまり UML の文法には拘らなくていいから. 構造と動きをおおまかに理解するのに使おう. 今回は XP も Web サービスも始めてだから分からないことはすぐ 相談してください.

MT, ST: はーい.

KH: それと,Linux や Web サービスで分からなくなったら,YO君 にヘルプしてもらおうね.

ストーリーを書く

KH: じゃあ,ストーリーを書こう.いちおうぼくが顧客を 兼務するから,まずは適当に書いて見るね.

  • 1. 予定を入力する
    日時と予定が入力できる. 通知日を指定することができる. 通知が不要とすることができる.

  • 2. 予定を閲覧する
    個人による予定一覧を閲覧することができる. 日付による予定一覧を閲覧することができる.

  • 3. 予定を通知する
    予定期日になったら期日を通知するメールを送信することができる.

  • 4. 予定を変更する
    予定を変更することができる.(入力項目のすべて)

  • 5. 予定を削除する
    予定を削除することができる.

KH: すごく簡単だけど,こんなんでどうかな.今回,折角 Web サービス なんだから,外部の使える Web サービスは利用しちゃおう.つまり, メールの送信自体は,別の Web サービスに依頼する形にしよう. XMETHODS(http://www.xmethods.com)というサイトに,現在公開されている SOAP, WSDL ベースの Web サービス一覧があるよ.そこで使えそうなのを 調べておいてね.

ユースケースを書くとこんな風になる.

ユースケース
ユースケース図

ストーリーを見積もる

KH: じゃあ,見積だ. 見積は,「自分が専念したら何日でできるか」という値を出すんだよ. これを「ポイント」という単位で呼んだりする.チームによっては, 適当な単位を付けているとこもあるんだ.ぼくが聞いたチーム では,「アフロ犬」なんて単位を使ってたな. でも,今回は単純に「理想日」で見積もろう.じゃあ, 見積もってみて.

MT: 最初は,環境とかの設定で時間がかかりそう・・. まず,「(1)予定を入力する」ですけど,4理想日くらいかな.

ST: そうですね.そのくらいは見ておいた方いいかな. Web サービスやったことのある人に聞いて見よう. (YO さんに聞きに行く...)

ST: 3日あればでできるそうですよ.ですけど,最初だし多めに みて4理想日にしよう.データベースの設定とかもあるしね.

KH: 分かった.でも,最初のイテレーションは一週間,つまり5日 しかないよね.最初のイテレーションでゴールデンパス,つまり いちばん重要な機能をひとまわり通したいと思っているんだ. 二人で5日なので,10日の持ち点があるんだけど, 負荷係数を2で見積もっても5理想日分しか最初のイテレーションで できないことになる.

第1イテレーションに入れる見積日数 = 人数 × 日数 ÷ 負荷係数
= 2人 × 5日 ÷ 0.5
= 5理想日分

だから,もし「予定を入力する」ストーリだけで4理想日とすると, これだけでほぼ持ち点を使いきってしまうね....

MT: じゃあ,ストーリーを分解しましょうか. ゴールデンパスは,たぶん予定を入れて,通知がくることだから, 予定入力のオプション的な機能は別のストーリーにしたらどうでしょう.

KH: そうだね.じゃあ,こう書き直そう.

  • 1. 予定を入力する
    日時と予定が入力できる.
  • 1-1. 予定を入力する(オプション)
    通知日を指定することができる. 通知が不要とすることができる.
うん.これで行こう.じゃあ,見積を続けよう.

  • 1. 予定を入力する -- 2 理想日
  • 1-1. 予定を入力する(オプション) -- 2 理想日
  • 2. 予定を閲覧する -- 1 理想日
  • 3. 予定を通知する -- 2 理想日
  • 4. 予定を変更する -- 2 理想日
  • 5. 予定を削除する -- 1 理想日

KH: 了解.じゃあ,ゴールデンパスとして,1, 2, 3 を入れよう. これで,5理想日になる.

ST: ちょうどうまく行きましたね.

KH: 拍手!

ST, MT: パチパチ.

スパイクアーキテクチャ

KH: じゃあ,ここから,最初のイテレーションに集中して,タスクを 出していくことになるんだけど,その前に,ソフトウェアの 全体の構造はどういう風になるのかな? 最初のイテレーションのストーリーは,3つだ.

  • 1. 予定を入力する
  • 2. 予定を閲覧する
  • 3. 予定を通知する

これを実現するための絵を描いて見ようよ.MT さん描いてみて.

スパイク1
スパイクアーキテクチャの絵(案1)

うん,だいたいそんな感じ.ちょっとDBが大きいね.DBを扱ったことの ある人は,「DBありき」で考えてしまう場合が多いんだ.もう少し役割を 分割して,クラスのレベルにまでブレークダウンしよう.UMLっぽく 書いて見ようか. (全員でホワイトボードで議論しながら,このような絵がかけた)

ホワイトボード
ホワイトボードを使って設計

スパイク2
スパイクアーキテクチャの絵(案2)

Webサービスの口は,「SSSコントローラ」と名付けよう. これが,内部のデータ管理である「モデル」に「スケジュール」 を登録する.この流れとは別に,「タイマー」を持った「監視」 がいて,定期的に「モデル」を参照して,通知が必要であれば 「通知」に依頼してメールを送ってもらう.モデルは,実際にはDB を用いて実装することになるだろうね.それも書いておこう. それぞれの日本語に対応する英語も 書いておこう.実際にコーディングするときは,この英語にそろえよう. ST さん,用語辞書に登録しておいてね.

KH: じゃあ,ついでにメタファーも決めよう.何かいいアイディアはない?

YO: あらかじめ指定しておいた時間に届けてくれるんですよね, だから,「宅配便の期日指定」っていうのは?

MT: うん,いい感じですね.全体の動きはうまくあらわされていると思う.

ST: 「モーニングコール」っていうのはどうですか? ホテルで翌朝,電話 で起こしてくれる.

KH: うん,きれい,きれい.たぶん,モーニングコールのシステムって こんな感じになってるんだろうね.キャンセルもできるしね.

YO: これは美しいメタファーだな.これで行こう.

KH: 良い気分だし,休憩しよう.

タスクの書き出し

KH: では,とりあえず,最初のイテレーションに集中して,タスクを 出して見よう.どんな作業があるだろう.

MT: データベースもあるし,CVS もいるし,Linux にユーザを作らないと.

KH: うん,最初はインフラの整備がいろいろあるね. じゃあ,タスクを書き出してみようか.何をやらないと行けない?

MT: データベースの設定とかもタスクに入れるんですか?

KH: うん.やることはすべて出してみよう.

ST: データベース,CVS .... (ホワイトボードに書き出す)

MT: で,実際に作るクラスは,Model, Schedule, Watcher,....(ホワイトボードに書き出す)

KH: Model(モデル)と Schedule(スケジュール), それから, Watcher(監視) と Notifier(通知) はそれぞれ 1まとめのタスクにした方が分かりやすいね.

第1イテレーションタスク
  • データベーススキーマ定義
    - schedule テーブルの作成
  • 開発環境設定
    - UNIX ユーザ登録
    - CVS
    - JUnit
  • Model, Schedule クラス
  • Watcher, Notifier クラス
  • SSSController クラス

KH: こんなもんかな.じゃあ,タスク毎に見積もろう. 自分がやりたいタスクにサインして,見積を書いて.

MT: サインって言っても,二人しかいなくてペアプロだったら, 結局全部やることになるのでは ?

KH: うん.そうなんだけど,タスクの完了に責任を持つ人を 決めたいんだ.それと,後で見積の精度をトラッキングしたいから, サインした人,つまり見積した人が誰かを記録したい意味もある.

ST: じゃあ,私,今回ミッションステートメントで「DB に強くなる」 って言っているので,データベース設定やります.MTさん,手伝ってくださいね.

(ここで,UNIXに強いYO君登場)

YO: お,XPやってるね.

KH: いいとこに来たね.Linux マシン使いたいんだけどさ, mild って名前のマシンつかってもいいかな?

YO: ええ,あれは開発用だから自由に使っていいですよ.ユーザ設定 とか,やりましょうか?

全員: おおー,是非,是非.

YO: じゃあ,環境の設定まわりはぼくがやります.0.5 日で終ります.

.... っとこんな感じでミーティングが進み,タスク表ができあがりました. 一週間は5日ですが,負荷係数を2として,一人2.5日を目安にタスクに コミットしています.YO 君は一時的なリリーフです.

第1イテレーションタスク
  • データベーススキーマ定義 (0.5) MT
    - schedule テーブルの作成
  • 開発環境設定 (0.5) YO
    - UNIX ユーザ登録
    - CVS
    - JUnit
  • Model, Schedule クラス (1.0) MT
  • Watcher, Notifier クラス (3.0) ST
  • SSSController クラス (1.0) MT
コミット量

  • MT ... 2.5
  • ST ... 3.0
  • YO ... 0.5

  • 合計 6.0

これだと,全員の合計が6日になります.本当は1日分オーバーなのですが,YO 君が入ってくれたのと,まあ,最初なのでとりあえずこれで始めて みよう,ということになりました.

ホワイトボードに書かれたタスクは,模造紙に書かれて壁に張り出されます. そして,終了したタスクから,横線を引いて消します.消したら,完了日と 実際にかかった日数を書き込むようにしました.これで,どのタスクが 見積より難しかったか,あるいは見積よりも簡単だったかが分かります.

例えば,第1イテレーションが終ったあとのタスクの模造紙は,こんな感じ になりました.

タスク模造紙
イテレーション終了時のタスク表

   テストファースト!

さて,実際にペアプログラミングでテストファースト, リファクタリングを行っている様子を紹介します.ペアプロの現場の写真 もお見せしましょう.二人の後ろには,そのイテレーションのタスク を書いた模造紙がはってあります.そして,ストーリーカードは 「終了」と「TODO」に分けてはりだされているのにも注目してください.

ペアプロ中
ペアプロ中の MT と ST

ユニットテストの実際

まずは,ユニットテストを使ったテストファースト開発です.

~ ストーリ ~
予定を入力する
  • 日時と予定が入力できる.

ST: このタスクのテストから書きましょうか.テストメソッド名は何にしましょう?

MT: 予定の追加を確認だからtestAddScheduleでどう?

ST: こんなかんじでいいですか? Schedule は 予定の入力者,予定日,内容, 予定の通知先を持ったクラスで,コンストラクタで全部設定できるように します.


    public void testAddSchedule() throws SSSException {
        Schedule sc = new Schedule("test@esm.co.jp", "2002/03/31 15:00",  "出張", "test@esm.co.jp");
        SSSController.addSchedule(sc);
    }

ST: あっ,これをどうやって確認しましょう..

MT: DB に登録して,それを確認することにして,今はとりあえずコンパイルしよう.

ST: あー,コンパイルエラーだ.メソッドないですもんね.あたりまえか.

MT: じゃあ,addSchedule を実装しよう! DB への接続は別のメソッドにしますね. getDB という private メソッドを作ってっと.SQL 文はこれで合ってます?

    public void addSchedule(Schedule sc) throws SSSException {
        Connection con = getDB();
        // beginTransaction

        String sql = "insert into schedule values (nextval('schedule_id')";
        sql += ",'" + sc.getOwner() + "','" + sc.getDate();
        sql += "','" + sc.getContent() + "','" + sc.getNotifyee();
        sql += "')";
        try {
            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);

            con.close();
            // endTransaction
        } catch(Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

    private Connection getDB() throws SSSException {
        try {
            Properties p = new Properties();
            p.setProperty("user",USER);
            p.setProperty("password",PASS);
            p.setProperty("charSet","EUCJIS");
            Class.forName("org.postgresql.Driver");
            return DriverManager.getConnection(URL,p);
        } catch (Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

MT: これでどうかな.コンパイル・・・.

ST: 通りましたね.それじゃ,テスト.

ST: すごーい,とおりましたね!!ちゃんと通ったテストにチェック が付くんですね.

MT: add しただけで,何も assert してないから当然だよね.

MT: DB にちゃんと追加されてるか,確認しよう.psql(PostgreSQLのシェル) で直接確認っと.

ST: あー,ちゃんと追加されてますね.でもこれってテストとしてどうなんでしょう..

MT: そうだねえ.テストメソッドの中でちゃんとテストしないとね. それじゃgetメソッドを作ろっか.とりあえず get を作るタスクはないんだけど, これがないとテストできないもんね.じゃあこっちのストーリーに移ろう!


~ ストーリ ~
予定を閲覧する
  • 個人による予定一覧を閲覧することができる.

ST: まず最初は,何も登録されてない場合のテストを書きましょう.

MT: それじゃ,こんな感じでどうかな?

    public void testGetEmpty(){
        Schedule[] scs = SSSController.getSchedules("");
        assertNull(scs);
    }

MT: じゃぁ,コンパイルっと.はい.約束通りコンパイルエラー.

ST: メソッド作りましょう.

    public Schedule[] getSchedules(String owner) {
        return null;
    }

MT: コンパイル通った.じゃあ,実行!


ST, MT: わーい.成功した~.testGetEmpty が,通ったテストに追加 されてますね.

ST: 今は null が返ってきて当たり前ですね.じゃあ Schedule が返ってくるテストを書きましょう.

MT: さっきの中途半端だった testAddSchedule に付け加えればいいんじゃない? 追加した Schedule を,問い合わせで取って来ればいいんだよね.

    public void testAddSchedule() throws SSSException {
        Schedule sc = new Schedule("test@esm.co.jp", "2002/03/31 15:00", "出張", "test@esm.co.jp");
        SSSController.addSchedule(sc);
        Schedule[] scs = SSSController.getSchedules("test@esm.co.jp");
        assertEquals(1, scs.length);
        assertTrue(scs[0].equals(sc));
        assertTrue(scs[0].getNeedNotify());

ST: コンパイルエラーになりましたね.じゃあ実装.DB からスケジュールを とってくる部分は,private メソッドにして括り出しますね.

    public Schedule[] getSchedules(String owner) throws SSSException {
        String sql = "select * from schedule where owner = '" + owner + "'";
        return getSchedulesFromDB(sql);
    }
    ※ getSchedulesFromDB(sql) は private method で SQL 文を実行して Schedule[] を返す.

MT: コンパイルとおったね.じゃあテスト実行. ST: 通りましたね♪

MT: 日付が不正だったらどうするんだろう.

ST: 顧客役に聞いて来よう.(ストーリーカードを持って聞きに行く)

KH: うーん,どうしようかな...例外出してもらおうかな.

ST: わかりました.SSSException でいいですか?

KH: うん.とりあえずそれでいいよ.

MT: じゃあ,不正ななデータを add する場合のテストもしよう.

ST: そうですね.そんじゃメソッド名は testAddBadDate でどうでしょう. 日付のフォーマットは,"yyyy/mm/dd hh:mm" でしたよね."1111" なんてヘンな 文字列入れますね. この場合,SSSException 例外が帰って来るのをテストするんですよね. 例外はどうやってテストするのかな...

MT: catch の方に assertTrue を入れて,そこを通っていることを確認しましょう. それと,念の為に addSchedule の後のコードが実行されていないことも, fail を入れておいて確認っと.さらに,Exception 全体も catch して おいて,他の例外でないことも見ておきましょうか.

    public void testAddBadDate() throws SSSException {
        Schedule sc = new Schedule("test@esm.co.jp",  "1111", "出張", "test@esm.co.jp");
        try {
            SSSController.addSchedule(sc);
            fail();
        } catch(SSSException e) {
            assertTrue(true);
        } catch(Exception e) {
            fail();
        }
    }

MT: コンパイルして実行っと.

ST: テスト失敗しちゃいましたね.あ,当たり前か.実際に不正日付の チェックしてないですもんね.

MT: だめだったテストメソッドには, ばってん(×)が付いて表示されるんですね.

ST: チェックするロジックを書きましょう. チェックはどうやってやるのかな....

MT: たしか,java.util.text パッケージに日付のフォーマットとパース のためのクラスがあったはず.API を調べてみよう.

ST: ありましたね.SimpleDateFormat ですね.ふむふむ,parse に失敗 すると,ParseException ですね.これを捕まえましょう.

MT: うん.DB の属性を not null にしてるけど, 不正日付のチェックを入れるなら null チェックも入れようか. null の場合も SSSException 投げるようにしましょう. できるだけ,細かいお助けメソッドを作って重複をさけましょう.

    public void addSchedule(Schedule sc) throws SSSException {
        Connection con = getDB();
        // beginTransaction

        String owner = sc.getOwner();
        String date = sc.getDate();
        String content = sc.getContent();
        String notifyee = sc.getNotifyee();

        if(stringIsNull(owner) || stringIsNull(date) ||
           stringIsNull(content) || stringIsNull(notifyee)) {
            throw new SSSException("NullPointerException addSchedule.owner = " + "'"+owner +"'");
        }

        try {
            java.util.Date d = parseDate(date);

            String sql = "insert into schedule values (nextval('schedule_id')";
            sql += ",'" + owner + "','" + DATE_FORMAT.format(d);
            sql += "','" + content + "','" + notifyee;
            sql += "')";

            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);

            con.close();
            // endTransaction
        } catch(Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm");

    private static java.util.Date parseDate(String dateString) throws java.text.ParseException {
        return DATE_FORMAT.parse(dateString);
    }

   private static boolean stringIsNull(String s) {
        return (s == null || s.trim().equals(""));                      
    }    

MT: コンパイルして実行! ST: オッケーですね.

リファクタリング

第2イテレーションに入って,modifySchedule,removeSchedule を 作成しようとしたときに,addScheduleと重複するロジックが存在すること に気が付きました.

    public void addSchedule(Schedule sc) throws SSSException {
        Connection con = getDB();
        // beginTransaction

        String owner = sc.getOwner();
        String date = sc.getDate();
        String content = sc.getContent();
        String notifyee = sc.getNotifyee();

        if(stringIsNull(owner) || stringIsNull(date) ||
           stringIsNull(content) || stringIsNull(notifyee)) {
            throw new SSSException("NullPointerException addSchedule.owner = " + "'"+owner +"'");
        }

        try {
            java.util.Date d = parseDate(date);

            String sql = "insert into schedule values (nextval('schedule_id')";
            sql += ",'" + owner + "','" + DATE_FORMAT.format(d);
            sql += "','" + content + "','" + notifyee;
            sql += "')";

            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);

            con.close();
            // endTransaction
        } catch(Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

MT: 赤字の部分が重複するところだよね.

ST: それじゃ,null チェックと dateチェックのところを括りだしましょう.私書きますね.

    private static void checkSchedule(Schedule sc) throws SSSException {
        if(stringIsNull(sc.getOwner()) || stringIsNull(sc.getDate()) || 
           stringIsNull(sc.getContent()) || stringIsNull(sc.getNotifyee()))
            throw new SSSException("Data is lacking.");
    }

    private static String checkDateFormat(String date) throws SSSException {
        try {
            java.util.Date d = parseDate(date);

            return DATE_FORMAT.format(d);
        } catch(ParseException pe) {
            throw new SSSException(pe.getMessage());
        }
    }

    public void addSchedule(Schedule sc) throws SSSException {
        checkSchedule(sc);

        String date = checkDateFormat(sc.getDate());

        try {
            String sql = "insert into schedule values (nextval('schedule_id')";
            sql += ",'" + sc.getOwner() + "','" + date;
            sql += "','" + sc.getContent() + "','" + sc.getNotifyee();
            sql += "')";

            Connection con = getDB();

            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);

            con.close();
            // endTransaction
        } catch(Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

MT: だいぶすっきりしたね. あとは残った赤字を括りだせばOKかな?メソッド名 execute で括り出そうか.

    public void addSchedule(Schedule sc) throws SSSException {
        checkSchedule(sc);

        String date = checkDateFormat(sc.getDate());

        String sql = "insert into schedule values (nextval('schedule_id')";
        sql += ",'" + sc.getOwner() + "','" + date;
        sql += "','" + sc.getContent() + "','" + sc.getNotifyee();
        sql += "')";

        execute(sql);
    }

    private void execute(String sql) throws SSSException {
        Connection con = getDB();
        // beginTransaction

        try {

            Statement stmt = con.createStatement();
            stmt.executeUpdate(sql);

            rs.close();
            stmt.close();
            con.close();

            // endTransaction
        } catch(Exception e) {
            throw new SSSException(e.getMessage());
        }
    }

ST: すごいすっきりしましたね.いい感じ♪ modifySchedule はこうなりますね.

    public void modifySchedule(int id, Schedule sc) throws SSSException {
        checkSchedule(sc);

        String date = checkDateFormat(sc.getDate());

        String sql = "update schedule set owner = '" + sc.getOwner();
        sql += "', scheduledate = '"+ date;
        sql += "', content = '" + sc.getContent();
        sql += "', notifyee = '" + sc.getNotifyee();
        sql += "' where id = " + id;

        execute(sql)
    }

MT: そうだね.これでテストを通してっと. やった!通った!!ユニットテストを使うとリファクタリング後の デグレードもきちんとテストできていいね.

開発は,終始,こんな具合に進みました.DB がからんだテストでは, JUnit の setUp() メソッドをうまく使ってDBをクリアして, 各テストが混ざり合わないように工夫をしました.

   クライアント

第2イテレーションまでで,サーバー側(Webサービス)は完成しました. 一応,これで作業は完了なのですが,やっぱりクライアントも作って みたいですよね.今回は,第3イテレーションで, 3月末発売のVisual Studio .NET(製品版) を使って,GUI をもつアプリケーションを作ってみました. Web サービスを実際に呼び出しています.クライアントの GUI を 紹介しましょう.Visual Studio が提供している GUI コンポーネント をふんだんに使っています.

ここで,クライアントの画面と使い方の簡単な紹介だけしておきましょう. このクライアントは,ソースコードを公開しています.後の「公開」の 章を見て下さい.

起動とログイン

SSSClient.exe を起動すると以下の画面が立ち上がります.

『ログイン』ボタンを押すと,ログイン画面が表示されます. 予定入力者のメールアドレスを入力すると,ログイン完了です. このメールアドレスが,通知メールの差出人になります.

カレンダー表示

ログイン画面で入力したメールアドレスで登録されている予定日付が太字で表示されます. 太字の日付を選択すると,その日付の予定一覧がリストに表示されます. 予定を入力したい日付を選択して,『スケジュールの設定』ボタンを押して 次へ進みます.

予定の追加/変更/削除


図の画面が表示されます.必要な項目を入力します. 変更,削除の場合は,リストから予定を選択して処理を行ってください.

以下は入力データの説明です.

予定時刻 予定年月日,時間,分 を選択してください.(必須入力)
内容 予定内容を入力してください.(必須入力)
通知なし 予定を確認するメールが必要でない場合,チェックしてください.
通知先 予定の確認メールの宛先(メールアドレス)を入力してください.(通知なしがチェックされていない場合,必須入力)
通知時刻 予定の確認メールが欲しい年月日,時間,分 を選択してください.(通知なしがチェックされていない場合,必須入力)

   公開

この Web サービスは,クライアントの参照ソースとともに「Webサービス同好会」 で公開しています.

http://objectclub.esm.co.jp/webservice/ml.html

公開の仕様は,次のようなものです.


シンプルスケジュールサービス

予定を入力するとメールで通知してくれるサービスです.
※メール通知は外部Webサービスを使用しています.

サーバーGLUE2.3
SOAPエンドポイントURLhttp://nile.esm.co.jp:8080/glue/urn:simpleScheduleService
メソッドネームスペースURIurn:simpleScheduleService
提供メソッド Schedule[] getSchedules(String owner)

予定入力者がownerであるScheduleクラスの配列を返します.

Schedule[] getSchedules(String owner, String scheduleDate, boolean needDate)

予定入力者がownerで予定日付がscheduleDateであるScheduleクラスの配列を返します.
needDateがtrueの場合は予定日付の年月日(yyyy/MM/dd),falseの場合は年月(yyyy/MM)で取得します.

Schedule[] getSchedules(Date date)

予定日付がdateであるScheduleクラスの配列を返します.

int[] getScheduleIds(String owner)

予定入力者がownerであるスケジュールIDの配列を返します.

int[] getScheduleIds(Date date)

予定日付がdateであるスケジュールIDの配列を返します.

Schedule getSchedule(int id)

idで指定されたScheduleクラスを返します.

int addSchedule(Schedule sc)

Schedule scを追加し,そのidを返します.

void modifySchedule(int id, Schedule sc)

idで指定されたScheduleを sc に変更します.

void removeSchedule(int id)

idで指定されたScheduleを削除します.

Scheduleクラス

詳細は,サンプルコード中のSchedule.javaを参照してください.

public class Schedule {
public int id; // スケジュールID
public string owner; // 予定入力者
public string date; // 予定日付
public string notifyDate; // 通知日付
public string content; // 予定内容
public string notifyee; // 通知先
public bool needNotify; // 通知が必要か
public bool doneNotify; // 通知済みか
}

サンプルクライアントコード http://nile.esm.co.jp:8080/sample/client/sssclientdotnet.lzh
WSDL http://nile.esm.co.jp:8080/glue/urn:simpleScheduleService.wsdl
   反省と感想

さて,こんな風に私たちの開発は進み,3イテレーションでうまく公開 へとこぎ着けました.今回の「プチXP」開発を反省してみましょう.

ミッションステートメント

まずは,個人のミッションステートメントは達成されたでしょうか?

MT さん

  • UMLとJavaのマッピングをスムーズに考えることができる
    UMLとJavaとのマッピングというよりはUML図(ここではクラス図)で コミュニケーションができるかどうかだと思った. クラス図に関しては以前よりは理解が深まった.
  • テストファーストの実践を通してテストファーストに慣れる
    テストファーストしやすいものとしにくいものがあることがわかった. しやすいものに関しては実践できたし,だいぶ慣れたと思う.
  • Webサービスの特徴(くせ?)を知る
    特徴をつかむというところまでは理解できなかった. やってみて動いたからOKと考えてしまうことが多く, どうやって動いているかまでつっこんで考えられなかった.

ST さん

  • Linux環境に慣れる.
    SSS の開発に困らない程度には慣れた.
  • DB への苦手意識をなくす.
    苦手意識がなくなってきた.SQL もマニュアルを見ながらずいぶん かけるようになった.

二人とも,それなりの成果は出たようです.大切なのは,あとで 達成できたかを反省することではなく,ミッションを持っての開発にのぞむと, タスクへのコミットが意識的にできる,という部分だと感じました. では,それぞれのプラクティスに関して二人の感想をまとめてみました.

計画ゲーム

  • プロジェクトに関わる人全員で行うため意識のずれがなくてよいと思った. 各イテレーションのタスクを明確にすることで 終わったこと,するべきことが誰の目からもはっきり わかるのがいいと思った(MT).
  • 計画ゲームをやっていて全体像がだんだん明確になっていくのが 楽しかった(MT).
  • 計画ゲームによって,各イテレーションのタスクが明確にできた. 自分から進んでタスクをコミットできてよかった(ST).
  • 外部 Webサービスを調べたり,利用できる社内の Linux マシンを調査 したり,最初の計画以前の下準備がかなり必要だった(KH).

スタンドアップミーティング

  • 問題が起きても,みんなの前で共有できるので不安がなかった(ST).
  • 朝,今日何をやるのかが確認できてよかった(MT).
  • これがないと,ペアの声をかけるタイミングがよくわからない(MT).
  • このプラクティスだけは,SSS プロジェクトが終ってもチーム で続いている(KH).

メタファ

  • 最初の計画ゲームの時に『モーニングコール』と決めたが それ以降ほとんど意識しなかった. 作ろうとするもの自体がシンプルだったからかなと思う(ST, MT).
  • 「モーニングコール」というメタファは,きれいだが,そこから 内部の仕組みを連想するのが難しい.「宅配便の期日指定」の方が よかったかも.ただし,用語辞書で名前の統一ははかれた(KH).

受け入れテスト

  • 受け入れテストを行うことで単体レベルでは考えていなかった テストケースでの障害を発見することができた. とても有効だと思った(MT).
  • ストーリーにはなかったが,hello() というメソッドを作って Webサービス通信ができているかだけのテストを書いてみた. これを最初に行って,通信や環境がらみの疎通を行えたのはよかった(ST).
  • 今回はWebサービスだったため,受け入れテストが非常に書きやすかった. データベースもうまくテストできた(KH).

スパイクアーキテクチャ

  • アーキテクチャ設計には,その人が関わってきたシステムや チーム文化(経験)が大きく影響することがわかった(MT).
  • ストーリーを眺めてクラスへブレークダウンする,という作業は, やはり経験がいるし,簡単にできるものでもない(KH).

テストファースト

  • 最初,どのクラスのテストから 始めるのかわからなかった(上位から?下位から?)(MT).
  • Unitテストで結果が目に見えるのは楽しい(MT).
  • テストを最初に作ることでどう実装したらいいかが理解しやすかった. テストファーストしにくいものはどうやって実装していくのか, どのレベルまでテストするのか(コードが1行のメソッドはテストしない等) などといった点で少し迷うことがあった(MT).
  • JUnitを使ってテストを書いたが結果が目で見えるのが楽しくて すぐにテストをしたいと思った. リファクタリングをした時などデグレードの確認にも とても有効だと感じた(MT).
  • Model や Schedule など,静的なクラスは テストファーストを実行できたが,自律的に動くWatcher クラスは どうテストしたらよいか分からず,実装が先になってしまった(ST).
  • テストファーストを心がけようと思っているのだが 先に実装したい!という誘惑に負けてしまうことが多い(MT).
  • この方法で開発すると,ときどき頭がこんがらかって,「何を やってたんだっけ?」ということがある.やることを紙に書き出して やった方がよい(MT, ST).

ペアプログラミング

  • 二人で調べながら進んでいった方が動いた時の喜びが大きいと思った(ST).
  • 問題にぶつかった時にそれを解決するための方法が,いくつも 出し合えるという点でペアプロは有効だと感じた(ST)。
  • ツール(CVS)の操作を実際に見ることにより早く覚えることができた(MT).
  • タイプミスをすると恥ずかしいけど,タイプミスによる コンパイルエラーが減った(MT).
  • お互いの癖などが分かって面白いと思った(MT).
  • 今回は実装は主に2人で担当したため仕様の思い違いなどがなく 進むことができた. わからないことはその場で質問できるため 聞くのを忘れたなどということが起きなくて良いと思う(MT).
  • 設計の仕方や考え方、コーディングなど 人のコードを見るのはとても勉強になる(ST, MT).
  • 1人で実装している時よりも頭が疲れるーー!(MT).
  • 設計やりファクタリングの仕方,ツールの使い方など 勉強になることが多かった. 分からないことがあっても話し合いですぐ解決できた(ST).
  • 自分の口臭が気になって,お昼に歯をみがくようになった(KH).

コードの共同所有

  • CVSで管理したのだが,前のバージョンなどをすぐに取り出せて とても便利だと感じた(MT, ST).
  • システム全体の知識が,チームで共有できる(MT).
  • どこを変えたかというのを,CVS で管理するだけではなく, スタンドアップミーティングでも情報を伝えあっていくのが 大事だと思った(MT).

リファクタリング

  • 第1イテレーションが終わってリファクタリングを行った時に 不要なクラスや重複しているコードがたくさんあるのに驚いた. リファクタリングをした後はすっきりとしたコードに なっていてとても満足な出来になった. テストはもう出来上がっているためリファクタリングするのも あまり怖くないと思った(MT).
  • 1メソッドが短くなって,コードが見やすくなっていくのは快感(ST).
  • リファクタリングをしていて,すべてのテストを一気に流すことができる クラスを作っておくことの必要性を実感した(MT).
  • DB定義の変更を行ったとき,それにともなうクラスの修正で かなり戸惑うと思っていたが,割とスムーズに進めることができた. 一番最初に,クラス図を見ながらそれぞれのクラスにどのような 修正を入れればいいかを話あってから実装に入ったのがよかったのだと思う(MT).
  • クラスをきれいにリファクタリングできたとき, ソースが見やすくなるとうれしくなる. 第3者にもすぐ分かるようなコードを書くことを 心がけていきたい(ST).
  • 前にメソッドを共通化したのが,再利用できてとても早く実装が終わった。 リファクタリングの効果を実感でき,自分たちで書いたコードながら すごいなぁと感心してしまった(MT).

シンプルデザイン

  • ついつい拡張性を考えてしまう癖があることに気が付いた(MT).
  • 最初は拡張性を考えた設計になっていたが,途中で 余計な機能を削除して,結果的にシンプルデザインになった(ST).

コーディング標準

  • 今回は2人で実装していたためそれほど必要性を感じなかったが 人数が増えると必要だと思う(MT).

用語辞書

  • コーディング標準と同じで人数が多いときにはとても有効だと思う. 今回は,最初にほとんどの用語の英語を決めてしまったので, 第2イテレーション以降はそれほど必要性を感じなかった(MT, ST).
   まとめ

さて,私たちの XP 体験談はどうでしたか? 最後に,私たちが今回感じたなかで, XPについて期待していることを書きたいと思います.

今までの開発手法では,システムを作って行くときに必ず 担当をしっかり分担して行きます.でもこのやり方だと, システムのある部分を知っている人が限られてきて, その人が抜けるとどうにもならない,という場面が起こります. 「あ,そこは誰だれに聞かないと分からない」という状況です.

分業

XPを使えば,特に,「ペアプログラミング」,「コードの共同所有」 それに「スタンドアップミーティング」をやりながらシステムを 作って行くと,システム全体の知識がチーム全体にゆるやかに 蓄積されて行くのが分かります.ですから,一人抜けたとしても チーム全体でカバーできるのです.

分業

今までの開発手法では,この状況をさけるために一生懸命「仕様書」 を書きました.個人にのみ知識が蓄積されてい くのを防ぐために,ドキュメントを大量に書くのです.これに よって,人が抜けても「仕様書」を読めば別の人がカバーできる というのです.でも,これまでの経験から,仕様書があてになる 可能性はとても低いと思います.仕様書は システムの「ある時期の仕様」を時間を止めて見ているような もので,実際には工程が進むにつれて仕様は変わって行ってしまいます. しっかり書いたドキュメントでも,実装に入る段階ではすでに ズレがたくさん出てきてしまうのです.

死んだシステム

XPでは,「仕様は変わるものだ」ということを頭から受け入れます. そして,「仕様は学習していくものだ」という考え方を取ります. これによって,より人々に蓄積された知識をより重視するのです.

生きてるシステム

ソフトウェア開発は,「システムを作る」ことが目的なのですが,それは 「システムを理解する」という過程を抜きには考えられません.また その理解は,仕様書を作るという作業だけでは得られません. システムを作りながら理解をして行く,という, より柔軟なプロセスが,重要なんだと思いました.

すこし背伸びしたことを書きました が,今後は,より大きなプロジェクトでXPを試してみて,本当に そうなのかを確かめていきたいと思っています. XPについての日本語ポータルサイトは,

http://www.ObjectClub.jp/community/XP-jp/

にあり,そこには入門記事や論文へのリンクがそろっています.メーリング リストも立ち上がっていますので, 次は,みなさんのXP体験談をぜひ聞かせてください.

おしまい


Last modified: Fri Aug 30 09:26:42 2002