エクストリームプログラミングのプラクティス

エクストリームプログラミングのプラクティス #

チームメンバーとしての顧客 #

顧客と開発者は同じ空間で机を突き合わせて、親密に仕事をするのが望ましいです。 同じ空間で仕事をすることで、お互いに相手の問題を把握することができ、その問題の解決に向けて一緒に取り組めるからです。 これは文字通り物理的な距離の話をしていて、顧客と開発者が同じ部屋で作業するのが最も理想的です。 距離が離れれば離れるほど、顧客をほんとうの意味でのチームに組み込むのが困難になります。

ユーザーストーリー #

プロジェクトの計画を練るためには「仕様要求」の概略をある程度知っていないければいけませんが、詳しく把握しておく必要はありません。 計画をたてる段階では「仕様要求」を実装するための必要な作業量を見積もれる程度の情報で十分です。

もちろん、詳細があることは知っているべきですし、それがどんなものか大まかに把握している必要はありますが、 具体的な詳細まで知っている必要はありません。

個々の仕様要求の詳細はプロジェクトが進むにつれて変化していきます。 特に、まとまった形になったシステムを顧客が受け取れるようになるとそれが顕著になります。 初期のシステムが稼働するのを見ることで、本当の意味で仕様要求に焦点を当てられるようになるからです。 そのため、システムに組み込むはるか前に仕様要求の具体的な詳細を把握しておくのは早まった行為と言えます。

短期間のリリースサイクル #

XPとスクラムはリリースの考え方が少し異なります。 ここではXPのリリースの考え方を紹介します。 これもちょうど富士通の公開サイトにプロセスを紹介する図があるのでこちらを引用します。

XPのプロセス 画像出典: アジャイル開発とは(中編)

XPでは動くソフトウェアを1週間から1ヶ月の短いイテレーションでリリースします。 このイテレーションの間に作られる動くソフトウェアは、出資者の仕様要求の一部を実装したのもで、 イテレーションの終わりにステークホルダーからのフィードバックをを得るためにデモを実施します。

イテレーションプラン #

イテレーションは通常2週間程度でイテレーション毎に小さな機能をいくつか実装して納品します。 しかし、それが最終製品に組み込まれるかどうかは決定していません。 開発者が作成した見積もりをベースに顧客が複数のユーザストーリーを選び、それらが実際に実装されることになります。

開発者は前回のイテレーションでこなした仕事量を参考にして、次回のイテレーションでの仕事量を見積もります。 顧客はその見積もりを超えない範囲で好きな数だけ選択できます。

イテレーションがスタートしたら開発者たちはストリーをタスクレベルに分割し、 技術的にもビジネス的にも最も合理的な順序でそれぞれのタスクを実装していきます。

リリースプラン #

XPチームは次の6回分程度のイテレーションを1つにまとめたプランを作成します。 これをリリースプランといいます。 通常一回のリリースは3ヶ月間隔で設定し、 その間、イテレーションを繰り返し、成果物を一纏めにしてリリースします。

イテレーションプラン のところで「最終製品に組み込まれるかどうかは決定していません。」と書きましたが、 リリースのタイミングでリリースに組み込む内容を決定します。 顧客はストーリーの内容をキャンセルしたり、追加したり、あるいはストーリーの優先順位を変えることができます。

受け入れテスト #

受け入れテストはE2Eテストとも言われます。 正確にいうと受け入れテストはフェーズであり、E2Eテストは受け入れテストの実施方法です。

ユーザーストーリーの詳細は、顧客が提示する「受け入れテスト」の書式で記述されます。 ストーリーの「受け入れテスト」はそのストーリの実装直前か、実装と並行して作られます。 通常、「受け入れテスト」は自動的に繰り返し実行できるようある種のスクリプト言語で書かれ、 受け入れテストを自動的に繰り返し行うことで、システムが顧客の要求どおりに動かくをチェックできます。

受け入れテストのツールには様々なものがあります。 有名なものだとSelenium、Puppeteer、TestCafe、Cypress.ioあたりでしょうか。 APIテスト周りだとPostmanおよびそのコマンドラインツールであるNewmanや、Karate、Pactなどがあります。 筆者のプロジェクトではWebブラウザ経由のアクセスの動作チェックにTestCafe、 API周りの動作チェックにPostmanとNewmanを採用しました。 これはツールによって得手不得手があったりするので、プロジェクトやアプリの特性に合わせて選択すると良いでしょう。

また、「受け入れテスト」のスクリプトはシステムと共に成長し、進化していくことになります。 新しいイテレーションが始まり機能が追加されたとき、それまでの「受け入れテスト」に追加する形でスクリプトを追加していきます。 つまり、受け入れテストはリグレッションテストも兼ねています。

ペアプログラミング #

ペアプログラミングは2人一組でプログラミングを行うというものです。 2人で1台のコンピュータを使って共同作業をしてコーディングを行っていきます。 ペアの片方がコードを入力し、もうひとりはコードにタイプミスがないかをチェックしたり、エラーや改良点がないかどうかを探し出したりする役割を担います。 ペアがお互いに強く干渉し、検討をす進めながら作業を進め、ソフトウェアを記述するという行為に全身全霊を注ぎます。

ペアの役割は頻繁に交代します。コード入力担当者が疲れたり行き詰まったりすると、 相方がもっとこうしたらいいんじゃないかとアドバイスを出したり、キーボードを奪って相方に変わってコード入力をしたりします。

ペアプログラミングではペアの組み合わせを毎日変えます。 そうすると、一人のプログラマがイテレーションで組み込もうとする機能全てに関わることになります。 特定の一人にシステムの知識が偏るということがなくなります。 プロジェクトが抱えるリスク指標の1つに「バス係数」というものがあります。 これは「何人がバスに惹かれるとそのプロジェクトが成り立たなくなるか」を示したものです。 特定の機能の仕様を把握しているメンバーが1人しかいない場合、そのプロジェクトのバス係数は1となります。 そのプロジェクトメンバが何らかの原因でプロジェクトから抜けるとそのプロジェクトは破綻してしまいます。 そうした自体を防ぐために、ペアを必ず入れ替えてプロジェクトの知識やノウハウを分散したほうがいいでしょう。

また、ペアプログラミングは有識者が他のメンバにティーチングをするという側面もあり、 ペアプログラミングを繰り返すことで開発チーム全体の開発スキルの底上げが期待できます。

テストファーストの開発 #

テスト駆動開発(Test-Driven Development、以下TDD)についてはテストの章で詳しく書きますので、ここでは概要だけ説明します。

テスト駆動開発ではまず実装しようとする機能の振る舞いをユニットテストとして実装します。 ユニットテストを実装した段階では機能はまだ実装されていないため、テストは失敗します。 そして、失敗したテストをパスさせる目的で機能を実装するという流れで開発していきます。

テストコードが僅かに実装コードを先導しながら、ほとんど同時に進化していきます。 その結果、完璧なテストコードがプロダクトのコード共に形成されることになります。

仕様変更で実装コードに少しでも変更を加えたら、テストを細かく再実行して正常に動作するか確認します。 ユニットテストがリグレッションテストの役割を担い、変更によって思わぬ障害が起きていないか確認できるようになります。 また、完璧なテストコードがあるおかげで リファクタリング ができるようになるというメリットもあります。

なぜ、テストから先に書くのかと言われると、完璧なテストコードを書くためです。 「あとからでもいいのでは?」と思われるかもしれませんが、あとからの実装では、 テストコードの抜け漏れが起きる可能性が高くなります。 そうすると、後述のリファクタリングを行ったときに思わぬバグを作り込んでしまう可能性があります。 最初に失敗するテストを実装する、そしてそのテストを充足するコードのみを書く。このプロセスがとても大事なのです。

共同所有権 #

共同作業をしているペアにはどんなモジュールでもチェックし、かつ、それを改善する権利があります。 しかし、開発者個人がモジュールや技術に対して責任を置くことはありません。 最終的にチームの誰もがプロダクト全般の開発に関わることになるため、誰もが等しく技術を共有することになります。

共有方法には様々な方法がありますが、Gitを使う方法が最も一般的で、 かつ複数人での共同作業に適していると筆者は考えます。 もちろん、ソースコードの共有をする中で変更が衝突したりすることはあるでしょうが、 都度、コンフリクトを解消してテストを走らせれば良く、容易に運用できるでしょう。

継続的なインテグレーション(統合) #

開発者は一日になんども担当しているコードをチェックインしながら作業を進めます。 ルールは単純で先にチェックインした方が優先です。 後からチェックインする場合はそれにマージし、ときに変更がConflictした場合はそれを後からマージする方が解決していきます。

XPではソースコードのコントロールをブロッキングすることはありません。 つまり、誰かがチェックアウトしてるからとかそういうことを気にせずいつでも自由にモジュールを取り出し、修正して、テストを終えて本体に戻す(チェックイン)ことができます。

変更の衝突は変更の規模が大きくなればなるほど起きやすくなります。 そのため、頻繁にチェックインすることを心がけなければいけません。

そして頻繁にチェックインするためには単体テストと受け入れテストを自動化することがとても大事になってきます。

持続可能なペース #

ソフトウェア開発は短距離走じゃありません。マラソンです。 スタートラインを飛び出し全力疾走するチームはゴール前に燃え尽きてしまいます。 素早くフィニッシュするにはチームは持続可能なペースで活力と集中力を維持することが求められます。

XPのルールでは残業は厳禁です。 これには大きな理由があります。 開発チームが単位期間に届けられる要求の量にVelocityというものがあることをスクラムの章で説明したと思います。 Velocityは直近の数スプリントで完了したストーリーポイントの平均で、この実績値をもとに次週以降の計画が立てられます。

もし、ここで残業して仕事を終わらせるとどうなるでしょう? まず、残業時間分、普段より多く働いているのでVelocityの単位期間で届けられる量という前提が崩れます。 そして、普段より多い時間でだした成果で次週以降の計画が立てられてしまうわけです。 そうすると、開発者はさらに無理をして開発をすることが求められるようになってしまいます。 つまり、残業をして無理をすればするほどに開発者は自分自身の首を締めてしまうことになるわけです。

また、一般的にアジャイル開発は準委任契約で遂行するものです。XPのルール的にも契約的にも残業は絶対にしてはいけません。

オープンワークスペース #

チームはオープンな部屋で共に作業します。各ペアは他のペアの会話も聞こえる程度の距離にいて、 別のペアが困っているときには気付けるようにします。 こうしておけば、お互いの状態も分かりますし、開発者同士はいつでも密に話し合えます。

もし、フルリモートワークだったら、ペア同士が密に会話できるチャネルチーム間で緩く会話できるチャネルを用意すると良いです。 zoomsneek といったツールを導入すると良いです。 zoomもsneekも同じビデオチャットツールですが、カバーしているコミュニケーション領域が大きく違います。 zoomはペア同士が密に作業しながら会話するのに適していますし、sneekは他所のチームにちょっとした相談をするといった場面にとても有効的です。 そして、そのどちらのコミュニケーションもプロジェクトを進める上で大事であり、両方採用すべきです。

また、テキストベースのコミュニケーションには Slack のようなチャットベースのものを採用し、コミュニケーションに関するコストを低く抑えるように努めることが大事です。 参考までに 筆者のプロジェクトのSlack運用ルール を掲載します。

シンプルな設計 #

XPチームはできる限りシンプルかつ表現性に富んだソフトウェア設計になるように最善を尽くさなければなりません。 また、現在のイテレーションで計画しているストーリーだけに焦点を絞り、将来組み込むことになるかもしれないストーリーについては考慮してはいけません。 現在のストーリーの処理に最適な設計に都度変えていきます。

最もシンプルな実装を考える #

XPチームは現行のストーリーの一群を処理できる方法のうち、可能な限りシンプルなものを探求しなければなりません。 例えば現行のストーリーを単純なファイルシイステムで実装できるなら、データベースを持ち出すのは不要です。 シンプルな実装は、後から不要になったときに剥がすのも容易です。 とにかくシンプルな実装を心がけましょう。

「後で必要になる」は不要 #

どんなアプリケーションも遅かれ早かれスケールしますし、DBや、複数ユーザのサポートが必要になる時が来ます。 しかし、その準備を今からやる必要はありません。

開発チームがそうした「後から必要になる」実装の追加を検討するのは、 今追加したほうが必要になるまで待つよりもずっと経費の節約になると証明できるか、非常に説得力のある証拠がある場合だけです。

同じことを2度しない #

開発チームはコードの重複を許しません。重複を見つけ次第その場で削除しましょう。 コードの重複の原因は様々ですが、最もありがちなのはコピペで複数箇所にコードをペーストした場合です。 そういった場所を見つけたら、基本クラスや関数を作成してそれらを取り除きましょう。

酷似しているけど微妙に違うアルゴリズムを発見したら、それらを関数に書き換えるか、Template Methodパターンを使うと良いです。 理由はなんであれ、重複を見つけたら徹底的に潰しましょう。

リファクタリング #

どんなコードであっても劣化していきます。 機能を次々と付け加え、バグを潰していくうちに、コードの構造は次第に損なわれていき、放っておくとそうした劣化は手のつけられない混乱状態を生み出すようになります。 開発チームは頻繁にリファクタリングをすることで、こうした劣化を防いでいかなければなりません。

リファクタリングとは機能自体は変えずに小さな変更を重ねることで、システムの構造を改善するプロセスです。 個々の変更は些細なものですが、それが積み重なるとシステム設計とアーキテクチャを大幅に変えることになります。

少しでもソースコードを変更したらすぐりユニットテストを実行して、何も壊していないことを確認しながらリファクタリングを行っていきます。 リファクタリングは頻繁に行われるべきもので、1日の終りでも、イテレーションの終わりでも、 また、また1時間おきでも構いません。 頻繁なリファクタリングによって、コードをクリーンでシンプルなものに保つことが開発者には求められます。


最後にXPのまとめです。

まとめ