🥷

精読「アジャイルサムライ」(第五部  アジャイルなプログラミング)

に公開


アジャイルサムライ――達人開発者への道
アジャイル開発を実践するための具体的な方法論と心構えを学べる一冊です。チームで成果を出す秘訣や、迅速かつ柔軟に価値を届けるためのツールや考え方をわかりやすく解説。初心者から経験者まで、アジャイルの本質を知りたいすべての人におすすめのガイドブックです!

関連記事

ユニットテスト:動くことがわかる

アジャイルな開発プロセスを機能させるには、確固たるエンジニアリングプラクティスが必要。以下の「必須プラクティス」を紹介する

  • ユニットテスト
  • リファクタリング
  • テスト駆動開発(TDD)
  • 継続的インテグレーション

これらは技術的背景を問わず、チームで実践可能なレベルで解説される。基盤となるのは「広範かつ徹底的なユニットテスト」。

ラスベガスへようこそ!

ブラックジャックのデッキにジョーカーが混入するバグが発生した話。

初めにバグを修正したが、その後インターンが「ジョーカーがないのはバグ」と勘違いし、再びジョーカーを追加してしまった。結果、重大なバグとして発覚。

このような問題を防ぐには、ユニットテストを活用して修正したバグが再発しない仕組みを作る必要がある。

はじめてのユニットテスト

  • ユニットテストの重要性

    • 小さな単位でコードの正しさを検証する。
    • 変更が期待通りに動作することを確認するために使用する。
    • 自動化されたテストにより、変更時に即座に不具合を発見できる。
  • ユニットテストのメリット

    • 素早いフィードバック:コード変更後に即座に問題点を発見できる。
    • 低コストでのリグレッションテスト:リリース前後にテスト作業を大幅に効率化。
    • デバッグ時間の削減:問題箇所を正確に特定できる。
    • 安心してデプロイ可能:テストがシステムの信頼性を支える。
  • 具体例

    • デッキに52枚のカードが含まれていることを検証する。
    • スート(ハート、クラブ、ダイヤ、スペード)ごとに13枚が存在することを確認する。
    • ジョーカーが含まれていないことをチェックする。
  • 注意点

    • 自動化が難しいケース(ランダム性や並行性など)もあるが、可能な限り部分的にでも自動化するべき。
    • 設計の見直しが必要な場合もある。
  • 心構え

    • テストはプロダクトコードに含めず、あくまで検証用として扱う。
    • 常に「どのような状況でも信頼できる甲冑」のようなテストを目指す。
  • 次のアクション

    • ユニットテストの基本をさらに深めたい場合は、関連書籍(例: 『レガシーコード改善ガイド』)の読破がおすすめ。
    • プロジェクトに適したテストフレームワーク(例: NUnitやxUnitなど)の学習と導入。
    • テスト駆動開発(TDD)を実践しながら、テスト設計のスキルを向上させる。

リファクタリング:技術的負債の返済

住宅ローンのように、ソフトウェアにも返済し続けなければならない負債があって、リファクタリングはその返済方法として紹介されている。リファクタリングを使うことで、コードベースを柔軟に変化に対応できる状態に保つことができ、メンテナンスコストを削減し、コード改善のための共通の語彙を提供する。リファクタリングを身につければ、新機能を追加するスピードも上がる。

どうしてこうなった

競合がリリースした「子供でも遊べるブラックジャック・シミュレータ」がヒットし、それに対抗するために新機能を追加しようとしたが、コードのコピーアンドペーストや乱雑なコードが原因で問題が発生した。コピペしたコードは修正がしづらく、既存のコードがメンテナンス性に欠けるため、修正するには大きな時間とコストがかかる。

特に、初期に書かれたコードが乱雑で、そのプログラマが辞めているため、問題が深刻化している。こうした状況を「技術的負債」と呼び、コードがどんどん不具合を引き起こし、肥大化する理由を考える必要があることが示唆されている。

技術的負債

開発速度や期日を優先するあまり、手抜きやハック、重複したコードなどが積み重なり、それが技術的負債となっていく。最初は小さな問題に見えるが、時間とともにその負債が積み重なり、最終的に大きな問題を引き起こす。技術的負債にはスパゲティコードや複雑さ、重複などがあり、これらは一つ一つは小さくて無害に思えるが、累積することで大きな影響を及ぼす。

負債を返済していくためには、ソフトウェアの整合性を保ちながら、設計を少しずつ改善していく方法が必要で、それが「リファクタリング」としてアジャイル開発で行われる。

リファクタリングで技術的負債を返済する

リファクタリングは、外部の振る舞いを変えずに、内部の設計やコードを改善すること。リファクタリングすることで、コードが読みやすくなったり、変更しやすくなったり、将来のメンテナンスが楽になる。

リファクタリングでやることとしては、以下のような改善がある

  • 変数やメソッド名の変更
    コードが理解しやすくなるように、もっと分かりやすい名前にする。
  • コードの整理
    重複したコードをまとめてメソッド化したりして、冗長性を減らす。
  • 小さな改善を積み重ねる
    大きな変更を避けて、日々の開発の中で少しずつ改善していく。

リファクタリングをコツコツやると、ソフトウェアの設計が維持されて、新機能の追加やバグ修正が効率的になる。コードが整理されるから、後からの変更や修正も楽になるし、チーム全体の開発効率が上がる。

リファクタリングは、コードの改善だけじゃなくて、開発者の作業環境も良くして、プロジェクトが進むにつれてソフトウェアの品質を高めるための大事なプロセス。

テスト駆動開発

テストを先に書く

テスト駆動開発(TDD)は、ソフトウェア開発において、テストを書いてからコードを実装し、リファクタリングを行う技法。

進め方は以下の通り

  1. レッド: 失敗するテストを先に書き、テストで意図を示す。
  2. グリーン: テストを通すコードを実装する。最初は最小限でも構わない。
  3. リファクタリング: コードを整理し、重複や無駄を省いて明確でわかりやすいコードにする。

重要なルールとして、テストを書く前に新しいコードを書かないこと、そして「危なっかしい所」をテストすることが挙げられる。

テストを使って複雑さに立ち向かう

TDDでは、まずテストを書き、その後にコードを実装するという手順を踏むことで、複雑な設計判断やトレードオフをシンプルにし、コードの保守性や修正のしやすさが向上する。TDDのメリットとして、迅速なフィードバックが得られ、自分の進んでいる方向が正しいことを確認できる。

さらに、TDDの真髄を深く学ぶためには、ケント・ベックの『テスト駆動開発入門』を読むことが推奨されている。

継続的インテグレーション:リリースに備える

ショータイム

継続的インテグレーション(CI)を日常的に行うことで、デプロイやデモの準備をストレスなく進め、プロジェクトを順調に進める文化を作ることが重要。

リリースに備える文化

「プロジェクトの本番は初日から始まっている」という考え方が紹介され、コードは最初から本番環境を意識して扱うべき。リリースに備える文化を早期に取り入れることで、チームはデプロイやシステム変更に自信を持てるようになり、競合に対して優位に立つことができる。継続的インテグレーション(CI)がこの文化を支える重要なプラクティスである

継続的インテグレーションとは

継続的インテグレーション(CI)は、ソフトウェアの変更を頻繁に統合することで、後々の統合作業の複雑さを避ける取り組み。執筆活動を例に取ると、共著者との文章のマージを早期に行えば、変更点を簡単に統合できる。しかし、マージの間隔が長くなると、後で統合するのが難しくなる。ソフトウェア開発でも、長期間統合しないと、コードの統合が難しくなり、問題が増えるため、頻繁な統合が重要。

どうすればうまくいくのか?

継続的インテグレーションツールをセットアップするには、次の4つの準備が必要

  • ソースコードリポジトリ
    コードはリポジトリに格納し、バージョン管理を行う。GitやSubversionなどが有用。
  • チェックイン手順
    適切な手順でコードをチェックインし、インテグレーションをスムーズに行う。
  • ビルドの自動化
    ビルドを自動化して効率的にテストやデプロイが行えるようにする。
  • 作業単位を小さくする姿勢
    小さな作業単位でコードを進め、頻繁にチェックインすることで統合の手間を減らす。

また、悲観的ロックモデル[1]は避け、チームがコードベースを自由に共有できる環境が必要です。

チェックイン手順を習慣づける

アジャイルなチームでは、開発者が以下のチェックイン手順を踏んでいる

  1. 最新のコードを取得: 作業前にリポジトリから最新のコードを取得し、ビルドして確認する。
  2. 変更を加える: 新機能追加やバグ修正などの作業を行う。
  3. テストを実行: 変更がコードを壊していないかテストを実行し、全てが成功することを確認する。
  4. 更新差分を取得: 他のメンバーの変更があるかもしれないので、再度リポジトリから最新コードを取得する。
  5. 再度テストを実行: 他のメンバーの変更とマージした後、再度テストを実行して動作確認する。
  6. チェックイン: すべてがうまくいったら、手元のコードをリポジトリにチェックインする。

また、ビルドを常に健全な状態に保つことが重要で、ビルドできなくなった場合はチームで助け合い修正することが求められる。


【アジャイル】アジャイルサムライを読む その13 ~ テスト駆動開発 / 継続的インテグレーションより

ビルドを自動化する

ビルドの自動化は継続的インテグレーションの基盤であり、プロジェクト全体の作業を自動化することが重要。開発者はTDDの一環としてビルドを自動化し、ビルドエージェント(例: Cruise Control)はコードがチェックインされるたびにビルドを実行する。自動化されたビルドにより、デプロイも自動化でき、ヒューマンエラーを減られる。ビルドは迅速であり、1回のビルド所要時間は10分以内が理想。プログラミング言語に対応したビルドフレームワーク(例: Ant, NAnt, Rake)を活用し、手作業を減らすことが重要。また、継続的インテグレーションを機能させるためには、作業単位を小さく保つ姿勢が最も大切。

作業単位を小さくする

コードの統合は頻繁に行うほど簡単になるため、できるだけ短い間隔(理想的には10~15分、最大でも1時間)でインテグレーションを行うべき。数日や数週間に一度のインテグレーションは避けるべきで、早めに、こまめにコードをマージすることが重要。インテグレーションの頻度を高くすれば、統合が容易になり、作業が面倒にならない。

この先どこへ向かえばいいのか?

これでアジャイルプロジェクトのキックオフや計画、運営ができるようになった。次に進むべき方向は自分次第だ。新しいプロジェクトを始めるなら、インセプションデッキを作り、チーム全員が正しい方向に進むようにする。すでに始まっているプロジェクトでは、ストーリー収集ワークショップを開き、重要なストーリーを選び出し、毎週成果を届けるようにし、新しい計画を立て直すことが大切だ。技術面での課題があれば、アジャイルなエンジニアリングプラクティスに取り組み、技術的負債を返済することを始めるのが良い。最終的には自分で何をすべきかを考え、それを実行に移すことが大切だ。

参考

脚注
  1. ある時点で特定のファイルを編集でいるのを一人の開発者だけに限定する ↩︎

Discussion