|
漁師プログラマ 山崎敏 YAMAZAKI Satoshi
vol.05 |
|
|
●●ある日 |
|
|
●リリース直前の出来事
筆者がまだ就職したばかりのころ,システム開発という仕事に慣れていなかったこともあり,ひたすら先輩の言葉を信じて業務に邁進していました.その日は,なんとか日程どおりシステムを完成させ,あとは品質チェックを行ってリリースされるのを待つばかりとなったのです.
このころのシステム開発は,システムの品質を2回チェックする意味から,システムのすべてのテストをしたあとに開発チームとは別の品質管理部の人たちが独自にテストを行いシステムの品質を確保するという,当時にしてはなかなか優れた開発体制になっていたのです.
品質チェックの作業中は仕事の量も減り,比較的のんびりできるのです.その週末の日曜日に,久しぶりに夏の休暇をのんびり過ごそうと友達とプールに行く約束をしました.水着のおねーさんがたくさんいるに違いないと,勝手な妄想がふくらみます.
そして金曜の帰宅直前です.取ってはいけない電話のベルが鳴るのです.すでに「お先に失礼しまーす」と声に出してしまったあとなのに,電話が鳴るのです.そのまま気が付かないふりをして帰ってしまっても良かったのですが,まだ新人であった筆者はしぶしぶ電話をとるのでした.
「もしもし…,例のシステムだけど,コケたから『3倍返し』ね.よろしく.(ガチャン……)」って,え?コケた?3倍返し?何言ってるのこの人…(汗)「せんぱーい,3倍返しってなんですかぁ?」と素直に聞く筆者.「マジかよー」と悪態をつく先輩.要するに,品質管理部でバグが発見されたらそのバグ数の3倍,バグが見つかるまで開発チームで再度テストをすることだとか….なんとも無茶苦茶なルールに悪態をつきながらも,非情にも休日出勤が決まり,当然日曜の水着…いやプールの予定はキャンセル.先輩と男2人で土日の2日間,延々と再テストをすることになるのでした.
●ペアプログラミング?
夏のギラギラと暑い太陽の下,休日でエアコンの入らない蒸し暑い部屋で,もくもくとテストをする男2人.悪夢以上に過酷な現実.ところが,普段のペースでは絶対に終わらないようなテスト項目数であるにも関わらず,1秒でも早く抜け出したい一心で驚くようなペースでテスト項目が消化されるのです.休日で雑談をする相手もいないし,電話がかかってきて作業が中断されることもない.誰も使っていないメインフレームは快適に処理を返すのです.
「いつもこのくらい快適だといいのに…」と思いながらテストを終わってみれば,土日2日間の予定を1日で完了し「火事場の馬鹿力」を体感することになったのでした.逆に言えば,普段はなんとゆっくりしたペースで仕事をしているのかということにもなりますが….そんなわけで,日曜日にはキャンセルしたはずの夏のプールがなんともまぶしく広がるのでした.くぅーっ.
その当時,そんな考えはまったくなかったのですが,今思い返すとXPでいう「ペアプログラミング」を実施していたように思えます.
|
|
|
●●ボトルネック |
|
|
『ザ・ゴール−企業の究極の目的とは何か』(エリヤフ・ゴールドラット著/三本木亮訳/ダイヤモンド社/ISBN:4478420408)というベストセラーがあります(注1).この本にはTOC(Theory of Constraints)という概念が書かれているのですが,その中に「ボトルネックの解消にはコストをかけるべき」という話があります.この本を読んで考えたのですが,システム開発でのボトルネックとは何なのでしょうか?筆者の今までの経験から考えると,ボトルネックを3つ挙げることができます.
注1)システム開発の話はありませんが,広い意味でモノづくりの概念として参考になります.
●@要求定義
まず最初のボトルネックとして,顧客からの要求定義があると思います.顧客自身,何が欲しいと思っているのか?何をどうしたいのか?何に価値を感じているのか?そこが明確になっていないと,プログラマも何を作れば良いのかわからないわけです.
顧客の立場としても,システム開発を頻繁に依頼しているわけではないし,初めての開発依頼であったり,今までにない新しい試みにチャレンジするといった不安な要素もあるでしょう.また,実際に動いているところを見てみないと決められないといった未踏な要素などもあるわけで,完全な要求定義など本当に可能なのだろうか?と疑問に思うくらいです.
とはいえ,ここが決まらないことには先に進めないわけで,ここで決まった要求(価値)をプログラマが実現することで対価がもらえるのに,その最初の価値があやふやになれば実現したモノもあやふやで対価までもあやふやになってしまうわけです.まさに「砂上の楼閣」なのです.
こんな状態であっても,納期に迫られてやむを得ず見切り発車してしまうのが現状なのでしょう.こうなると終盤の仕様変更や機能追加による日程遅延(デスマーチ)は必至です.とくにウォーターフォールモデルを採用する場合は,最初の段階でいきなりこの問題に立ち向かうことになるわけです.
●Aコミュニケーション
1人のプログラマがすべてのコードを書いてしまうような小規模なシステム開発の場合にはとくに問題にはならないのですが,やはり大規模なシステムになるとコミュニケーションがボトルネックになります.システムの全体像が把握できていないとか,誰が何を作っているのかわからないとか,同じモノを2つ作ってしまったりとか.ここまでひどくはないにしても,忙しい人と暇な人の差ができてしまったり,各自で設計思想がちぐはぐであったり,新たな仕様変更やバグが発覚してもコードを書いた人でないと修正できなかったり,いろいろ小さな不具合に遭遇するわけです.これらは情報伝達や情報の共有がボトルネックになっていると思うのです.
要求定義のボトルネックも,広い意味では顧客とのコミュニケーションのボトルネックと言い換えられるとも思います.
●Bテスト
そしてテストです.テストがうまくいけばバグを出すことはないはずなのですが,品質を決める大事なテスト工程が実は大きなボトルネックなのです.
おそらくシステム開発で一番重要であり,なおかつ一番大きなボトルネックなのではないでしょうか.
テスト工程はウォーターフォールモデルでは日程の最後に位置付けられていることなどもあり,ほかの工程の日程遅延の影響をもろに受けてしまいます.そもそもなぜ一番大事なテスト工程を犠牲にしなければならないのでしょうか?やはりテストに関する認識が甘いところから「なんとかなるだろう」とか「人を増やせば対応できるだろう」という安易な考えに流れてしまうことも問題のようです.
また,面倒な作業は避けたかったり,実環境がなかったり,納期厳守であったり,なにかとテスト作業を阻害する要因も多く存在することも事実だと思います.
●システム開発のボトル
オブジェクト指向が理解できないとか,C++の書き方がわからないとか,デザインパターンがわからないとか,どの言語を使うべきかとか,そういった設計手法や実装手段については,これまでにもたくさんの場所で議論されてきましたし,今もなお議論は続いています.その結果,多くの戦術が生まれてきたように思います.しかし,現在のシステム開発においては,設計手法や実装手段以外の「要求定義」や「テスト方法」のところが大きなボトルネックになっていると思うのです.そのイメージを図1に示してみます.

簡単に言えば,どんなに高度な設計手法や最新の実装方法を実行しても,顧客の要求を満たしていないシステムやテストの質の悪い(バグが多く品質の悪い)システムでは,使い物にならない(売り物にならない)ということなのです.そうであるはずなのに,今もなお,設計手法や実装手段に関して議論が続いているというのは「ある意味,滑稽だ」と言われても仕方のないことなのかもしれません.もっと大きな視野を持つべきなのでしょう.
これらのボトルネックを解消するために,先ほどご紹介した『ザ・ゴール』の言葉で言うところの「ボトルネックの能力を高める」努力をするのです.
筆者の解釈では「つねにボトルネックを意識する」となります.システム開発では要求定義やテスト工程をつねに意識する(能力を高める)べきだと思うのです.
|
|
|
●●エクストリームプログラミング |
|
|
●XPで作るループ
エクストリーム・プログラミング(XP)の詳細については『XP エクストリーム・プログラミング入門―ソフトウェア開発の究極の手法』(ケント・ベック著/長瀬嘉秀監訳/永田渉,飯塚麻理香訳/ピアソン・エデュケーション/ISBN:489471275X)など,関連する書籍がいくつかありますので,これらの本を読んでください.
筆者は,これらのすべての本を読破したわけではないし,XPを実践したこともありません.漁師プログラマ(注2)としては,実践していないことについてあれこれ書くのは気が進まないのですが,今まで感じてきたシステム開発の問題点に対してその一部でもXPによって解決できるのではないかと思ったのです.そのようなわけで,漁師プログラマとしてXPに期待することを書いてみたいと思います.
XPには複数のプラクティスがありますが,まずはいいとこ取りで,次の4つのプラクティスに注目します.
@ テストファースト(Test first)
A ユニットテスト(Unit test)
B シンプルデザイン(Simple design)
C リファクタリング(Refactoring)
この4つのプラクティスから,小さなループ(図2)を作るのです.
注2)理論ではなく実践を重視する(コードは動いてナンボと思っている)プログラマのこと.筆者の造語
●テストファースト
XPの着目点で筆者が一番すばらしいと思ったのが,テスティング(Testing)の概念でした.前のボトルネックのところにも書きましたが,システム開発で一番大きなボトルネックがこのテストだと感じでいたからです.筆者は以前からテストの重要性は認識していましたし,ユニットテストを早い段階から始めることも推奨してきました.
しかし,XPではテストをさらに重要視し,テストを中心に開発作業全体を組み立てると言っても過言ではないように思えます.XPでは,「すべてはテストに始まりテストで終わる」という考え方なのです.筆者はこの部分がXPの中でも最も重要だと思うのです.
まず,テストファーストという概念では,実際に対象となるコードを書く前に,テスト用のコードから書きはじめます.「何を提供するか?」という売り手の立場で考えるのではなく「何が欲しいか?」という買い手の立場から考えるということなのです.筆者にも経験があるのですが,売り手(作り手)の立場で考えると,つい余計なモノを作ってしまったり,それでいて肝心なモノを用意していなかったり,何が必要とされているかを正しく推測できないため,無駄な努力が多いのです.
この問題を買い手(使う側)の立場から考えはじめることで解決するわけです.自分が使うのならこんな機能が欲しいとか,こんな具合に表記できたら楽などと,まずは必要と思われる機能から書いていくわけです.たとえば,ToString()が欲しいとか,IsEmpty()が欲しいと,要望をそのまま書いていきます.それをそのままユニットテストのコードにするのです.
たとえば,リスト1のように書きます.そして,ひととおりテストコードを書いたあとに,リスト2のようにclass
Aの中身を実装するわけです.必要とされるコードのみを実装するのです.
『ザ・ゴール』の言葉を借りるなら「必要のない在庫(コード)は作らない」わけです.
| リスト1 ユニットテストのコード |
{
A a( 100 ) ; //class A はターゲット
//文字列を返すテスト
assert( a.ToString() == "100") ;
//空のテスト
assert( a.IsEmpty() == false ) ;
}
{
A a ; //class A はターゲット
//文字列を返すテスト
assert( a.ToString() == "0" ) ;
//空のテスト
assert( a.IsEmpty() == true ) ;
} |
| リスト2 class Aの実装 |
class A
{
int m_val ;
public:
A( int in = 0 )
: m_val( in ){} ;
//文字列を返す
std::string ToString()
{
char buff[64] ;
sprintf( buff, "%d", m_val ) ;
return buff ;
}
//空かどうかを返す
bool IsEmpty()
{
return m_val == 0 ;
}
}; |
●ユニットテスト
XPでは,まずテストファーストを行い,次に実体の実装をします.これらの作業が終わったあとで,必ずユニットテストを行うこととしています.しかも,中途半端な状態ではなく「必ず100%ユニットテスト完了の状態にすること」が大事であるとしています.
筆者はこの考え方に共感します.とにかく,コードは正しく動く状態に保つことが大切だと思うのです.中途半端な「すべてのコードが揃わないとテストできません」という状態では,それだけバグの発見が困難になります.小さい単位でテストすることで,バグの発見も小さい範囲から探すことができるのです.また,3分前に書いたコードからバグを見つけるのと,3ヶ月前に書いたコードからバグを見つけるのでは,たとえ同じコードであってもその容易さに大きな違いがあるのです.問題を発見するのは早ければ早いほど良いのです.遅くなるほど,ほかの物事との絡みが多くなり,問題の発見や解決方法がより困難になるのです.
設計方針によっては,ほかのコードが完成しないとテストできないところも出てきてしまうでしょう.ですから,どの部分からコードを書けば良いか方針を決めるのが,プログラマの大切な仕事になってきます.
XPでは,ユニットテスト用のツールを使うと良いと言っています.しかし,ツールを使わなければユニットテストができないわけではないし,必ずしも効率的であるとも思っていません.すべての開発環境に必ずしもユニットテスト用のツールが用意されているわけでもありません.話が少し脱線気味ですが,ツールを使うとたしかに便利です.ツールはあくまでも道具であって目的ではありません.ツールを使うことが目的ではないのです.
筆者はXPに出会う前から,ユニットテストを重視するコードを書いていました.テストコードと実装のコードを1つのファイルにして保存するというやり方です.それは“#ifdef”を使ってリスト3のように書きます.
| リスト3 テストコードと実装コードを一緒に |
class A
{
... // 実装コード
} ;
#ifdef __A_cxx__UnitTest__
int main()
{
... //ユニットテストコード
return 0 ;
}
#endif //__A_cxx__UnitTest__
|
ここで,“__A_cxx__UnitTest__”がデファインされていなければmain()関数は展開されません.テストコードはコンパイルされないわけです.ユニットテストがしたい場合のみコンパイル時に“__A_cxx__UnitTest__”をデファインして実行するのです.
こうすることで,ユニットテストのコードが行方不明になることを防いでいます.ユニットテストのコードを本体とセットにしておくことで,リファクタリングなどのコード修正時の再テストは楽になります.また,使う人のリファレンスマニュアルの代わりにもなるので,使い方の説明する手間が省けるわけです.以前から筆者がお勧めしている小技です.
ユニットテストの別の効用としては,つねに繰り返しテストを続けていると,だんだんと「テストをしているから大丈夫」という自信というか安心感が持てるようになります.この安心感を一度覚えると,逆にテストをしないことが不安になるという良い効用になります.
●シンプルデザイン
XPでは設計という工程をとくに設けていません.多くの人は「設計をせずにモノができるわけがない」と思われるかもしれませんが,XPではまず「オンサイト顧客」により仕様決定者が常時滞在していることが前提条件なのです.実装の前にきちんと設計をしてもどうしても修正が入ってしまうのなら,あとからでも設計を進めていける姿勢をとるのです.
つねにコードを修正し,同時に設計も続けていこうというスタンスなのです.
そのため,つねに修正が入ることを前提にして「シンプルデザイン」を心掛けます.できるかぎりムダを省き,最小のコードで実装するのです.筆者がいつも意識している「可読性の向上」(保守のしやすさ)と同じメリットを持つ作業だと思います.
シンプルデザインを実行することで,修正しやすいコードの状態を保ち続けるわけです.XPでは,修正を嫌うのではなく修正を受け入れるスタンスをとるわけです.
シンプルデザインを実行することはテストしやすい設計をすることでもあり,逆にテストしやすい設計をすることはシンプルデザインをすることでもあるのです.相互的な作用があるのです.テストしやすい設計は,そのまま「多くの顧客にとって使いやすい設計」にも繋がるわけです.
ここで注意してほしいのは,「シンプル」とは単純に「短いコード」のことではないということです.
短すぎるコードは必要な情報が欠落するため,理解しがたいコードになります.コードの可読性には十分配慮しましょう.このようにシンプルデザインは可読性が良くなり,可読性の良いコードはシンプルデザインを継続できるというポジティブなループにもなるわけです.
●リファクタリング
日本語で書くと「改善」です.日本ではわりとよく聞く言葉なので,なぜ今さら改善なのかと思う人もいるのではないでしょうか.もっとストレートな言葉で書くなら「変化に追従せよ!」となるでしょう.世の中はつねに変化しているのだし,自分の立場や自分自身の考え方も変化していると思うのです.変化に追従することを止めてしまったら,止まるのではなく後退しているのではないでしょうか.
XPではつねに修正し続けると書きました.修正し続けているとだんだんと歪みがたまり,シンプルデザインではなくなってくることもあるわけです.
ここでリファクタリングするわけです.同じ機能でありシンプルで,かつ理解しやすいコードに書き換えるのです.コードは一度書いたら二度と直さないのではなくて,つねに直し続けてよりシンプルな方向へ圧力をかけるのです.
また,同じ人が直すのではなく,異なる人がリファクタリングするところにも意味があると思います.同じ人ではやはり考え方が固定化してしまうので,異なる人の考え方を入れて新しい突破口を発見できるようにするわけです.
リファクタリングをするには機能が固まっている必要があり,その機能がリファクタリングする前と変わらないことを検証しなければなりません.リファクタリングをして機能が変わってしまうことを避けなければなりません.要するに,リファクタリングには検証情報すなわちテストコード(ユニットテスト)が必要なのです.
これらの4つのプラクティス(テストファースト,ユニットテスト,シンプルデザイン,リファクタリング)を含んだ小さなループ(イテレーションやタスク)が,設計という工程の代わりになります.あらかじめ設計をしなくても,設計はつねに行われ,コードはシンプルな状態に保たれるのです.
はじめに書いた最大のボトルネックである「テスト」の問題を,XPは「つねにテストをする」という考え方で解決しようとしているように思います.
|
|
|
●●XPとコミュニケーション |
|
|
●ペアプログラミング
筆者は以前に,コードレビューのメリットを書きました.コードレビューをすることで全体のレベルを上げ,考え方を統一することができます.このことは,可読性の良いコードを書くことにも役に立つと書きました.XPでは,コードレビューにメリットがあるのなら,つねにコードレビューをし続けよう,コードを書きながらリアルタイムにレビューをしようという考え方に発展し,それがペアプログラミングとなったようです.
ペアプログラミングのメリットはいくつかあると思います.
@ どのコードも2人以上が知っている
A どのコードもレビューされている
B どのコードの偏りが少なくなる
さらに,開発メンバーのばらつきをなくす(全体的にレベルを押し上げる)方向への圧力になると思うのです.多少ばらつきがあっても,ペアプログラミングを行ううちに「どういうところで困っているのか?」「どんな伝達の方法が有効なのか?」という希少な情報を含んだ技術的な情報も交換され,チーム全体のレベルも上がると思うのです.マニュアルなどでは表現しきれない職人技や微妙なニュアンスなども伝わると思うのです.
開発チームに偏りのある場合では,ペアプログラミングによって戦力が半分になってしまうとネガティブに考えずに,戦力が全体として上がる方向へフィードバックがかかっているとポジティブに認識するべきだと思います.
ペアで意見が対立したり喧嘩になり生産性に影響した場合はどうするのか?と心配する人も多いかと思いますが,そのようなペア間の問題は実は小さなこだわりであったり,多数決やジャンケンでその場は決めてしまったり,さんざんもめたあとであっても,別のペアによってリファクタリングされてしまったりと,あっさり解決するのではないでしょうか.むしろ,早めに問題が出たほうが,問題が大きくなる前に回避できるメリットがあると考えるべきかもしれません.
株式の本などには,あたりまえのように「リスク分散」という言葉が出てきます.ある1つの会社の能力には良いときもあれば悪いときもあり,つねに波を持っているわけです.この悪くなってしまうリスクを2つ以上の会社に分散投資することで,波を打ち消す効果を得るという考え方です.
このリスク分散の考え方をそのまま人の能力にも当てはめられると思うのです.人にはそれぞれ波があると思われるし,1人で開発する場合よりも,ペアで開発したほうがリスクは下がることになると思うのです.ただし,1つのシステムを複数人で作るという作業では,コミュニケーションの限界という点で人数が多いほど難しくなると思います.筆者の経験では,4人くらいがベストであるように思えます.
やはり,対人関係やコミュニケーション,説明/説得の技術など,プログラミング技術以外にも要求され必要とされる技術項目も多いのです.これらはシステム開発に関わらず社会人として身に付けるべき基本技術なのでしょう.逆に言えば,このあたりの基本技術に関してプログラマは社会人として足りない項目が多いのかもしれません.ペアプログラミングは,そういったコミュニケーション技術を習得する機会を与える1つの方法であると捉えることもできそうです.
●コード共有
ペアプログラミングをサポートするプラクティスとして,「コード共有」があります.コード共有は「1つのコードを1人が抱え込まずに全員で共有する」ということであり,「担当や所有権の主張をしない」ということなのです.コードを放置するのではなく,複数の人でつねにコードをメンテナンスできる状態を保つ考え方なのです.CVSなどのバージョン管理ツールが威力を発揮するところでもあります.もちろん必ずしもツールが必要であるとは限りませんが….
●ループの円滑化
はじめに書いたボトルネックである「コミュニケーションの問題」を,XPでは「ペアプログラミング」と「コード共有」によって解決しようとしているように思えます.これらのプラクティスによって,コミュニケーションを改善し,ループを円滑に加速するしくみなのだと思います.
|
|
|
●●XPと要求定義 |
|
|
最後に残ったボトルネックが要求定義です.図3に書いたように,要求定義の問題に対してXPでは「オンサイト顧客」と「小さなリリース」というプラクティスで対応しています.これらを図2に加えると,図3のようなループになると思います.

●オンサイト顧客
たとえば,あなたが海外旅行に行って迷子になったとします.近くにいた人(もちろん日本人ではない)に近くの駅へ行く道を尋ねたとします.さて,次のどちらが確実に駅に行けるでしょうか?
@ 紙に地図を書いてもらう
A 一緒に駅まで行ってもらう
ちなみに,@が従来の仕様書を書く考え方で,Aがオンサイト顧客の考え方なのです.一般的に,システムの設計には顧客の提出する仕様書が必要です.しかし,顧客にはシステム開発の経験のない人も多いので,仕方なくプログラマの側で仕様書を書いて確認してもらうことも多くなります.そのような顧客がこの仕様書を見ても「これが自分の欲しいモノなのかどうか判断できるのか?」という根本的な問題もあるように思うのです.
XPではこの要求定義の問題を,オンサイト顧客というプラクティスで解決しようとしています.システム開発の手順や方法論など,お互いに知らない概念をすり合わせることがまず必要なのだと言いたいのでしょう.顧客にはプログラマのほうに来てもらい,プログラマも顧客のほうに出向いて行き,積極的にコミュニケーションをとることで,要求定義のボトルネックを解消する考え方なのだと思います.
●小さなリリース
XPでは,つねに100%ユニットテストが終わっているので,開発中のどの状態でもコードは動く状態に保たれているわけです.よって,顧客に対しても動いている状態をいつでも見せることができることになります.
顧客にとって「本当にこのシステムは完成するのだろうか?」という不安は尽きることがないと思います.この不安を「いつでも動いている状態を見せることができる」という状況が解消するわけです.
顧客にとってこれほど心強いことはないのではないでしょうか.また,プログラマにとっても顧客からの「動いているところが見たい」という要望に対して余計な手間をかけずに即刻対応できることも,大きなメリットであるように思えます.
小さなリリースの別のメリットは開発期間の見積もりに関係します.たとえば,開発期間の見積もりが甘くてシステムの9割しか完成しなかったとします.小さなリリースを実施していれば,すべての機能の中の9割は動くことになります.動かないのは優先度の低い1割の機能です.小さなリリースを実施していない場合は,すべての機能が9割しか完成していないことになります.要するに,何も動かないので使い物にはならないということです.
●イテレーション
XPでは,この「オンサイト顧客」と「小さなリリース」を含む大きなループのことをイテレーションと呼んでいるようです.要するに,コミュニケーションを改善するために,顧客との物理的距離を短くして情報の伝達速度を上げることを目指していると言えるでしょう.
顧客との距離だけではなく,開発チーム内の物理的距離も短くし,少数精鋭部隊を作り,機動力を上げることを目指しているのかもしれません.距離が短くなることで,良い点も悪い点も見えるでしょうが,その伝達速度が速いので問題の収束も早いのではないでしょうか.この回転の速さがイテレーションのメリットだと思います.
電話やメール,掲示板などのツールで加速し,時間的距離を短くすることもできますが,やはり開発チームの全員が1つの場所に集まるのが一番高速で情報の伝達量も多いと思います.
|
|
|
●●最後に |
|
|
XPに関する筆者が重要であると思うプラクティスから解説してみました.この記事によって,皆さんの中にXPに関する何か興味のようなモノが残れば良いなぁと思っています.
次回はC++の「STLとテンプレート」について書いてみたいと思います.お楽しみに.
|
|