InfoQ

InfoQ

News

マイブックマーク

ブックマークするためにログイン または 会員登録 する

ブックマークされました!

ブックマークがエラーになりました。もう一度お願いします。

テスト駆動開発とレガシーコードのトラブル

作者 Mark Levison , 翻訳者 吉田 英人 投稿日 2009年11月23日

セクション
プロセス/プラクティス,
デベロップメント,
設計/アーキテクチャ
トピック
アジャイル技術 ,
Agile ,
プログラミング ,
Architecture
タグ
Legacy Code ,
TDD ,
テスト

原文(投稿日:2009/11/19)へのリンク

Complex MazeAlan Beljeu 氏は古い (レガシー) C++ コードベースで TDD を行っていて,トラブルに見舞われた。その理由はこうだ。

機能を完全に実装できていないクラスが最後に残ります。いつか必要になるかも知れない,というやつです。他のクラスからそれを利用しようとして,実装を完成させる時がきた,まさにその時になって当初の設計不足が明らかになるのです。設計は新たにやり直し,外部仕様(とそのテスト)も修正が必要。そのクラスを使っていた既存コードも変更しなければなりません。

そして彼は,"事前の大規模設計 (Big Design Up Front)" がこの問題の解決策ではないか,と考えるのだが,アジャイルコーチである George Dinwiddie 氏は,Alan のこの例が訴えているものを指摘する。すなわち,きれいなコード (clean code) の原理に注意を払わなくてはならない,基本的な結合度 (coupling) と凝集度 (cohesion) が必要である (つまり SOLID),ということだ。

アジャイルコーチ である Mike “Geepaw” Hill 氏は,自身の長年にわたるアジャイルチームのコーチ経験から,次の中のどれかが問題の根源にある,と言っている。

  • リファクタリング作業への習熟不足のため,クラスが最小限になっていない
  • 簡略化に関するスキル不足のため,クラスが最小限になっていない
  • マイクロテスト (別名ユニットテスト) が積極的かつ迅速に行われていないため,コード変更によるテスト失敗の頻度が高すぎる
  • チーム間の依存性,公開された依存性の扱い方が分かっていない 例)API 出荷
  • おそらくは,揺れのないビルド (jiggle-less build) が存在しない
  • 1940年台のツールを使用しているのかも知れない

XP コーチKeith Ray 氏は,レガシーコードのように大きな技術的負債を持つシステムを扱う場合には,その返済コストがストーリの実装コストの大部分を占める,と指摘した上で,次のようなアプローチを提案する。

コードを構造的に改善する (技術的負債の支払いを行う) ためには,新機能の実装が必要なときには常に,新しいコードと古いコード両方の状態に十分な注意を払わなければなりません。その結果としてどちらかのコードにまずい部分が見つかったならば,リファクタの実施を検討するべきです。

リファクタは手作業で,安全な大きさを単位として行うのがよいでしょう (たとえ C++ であっても)。リファクタリングに関する Fowler 氏の著書にある説明を読んで,それが暗記できるまで注意深く従いましょう。Eclipse 上で gcc を使用する場合には,抽出 (Extract) や名前変更 (Rename) などいくつかのリファクタリング機能が利用できます。名前変更はスコープを認識するので,検索・置換よりも安全です。ただし抽出メソッドと,Eclipse のこれ以外のリファクタリングはバグがあります。使用する場合には注意してください。また,関数のシグネチャを変更するような場合には,変更が必要な部分を"コンパイラ頼み"で見つければよいでしょう。

リファクタリングが既存コードを壊していないことを確認するためには,テストを行う必要があります。Feathers 氏の著書である “working with legacy code” には,レガシコードにテストを追加するためのテクニックがたくさん紹介されています。もっと上位の作業レベルから見て,まずいコード (code smells) というのは,よい設計指針に従っていないものです。例えば単一責任原則 (Single Responsibility Principle,SRP)によると,すべてのクラス/メソッド/モジュールの目的はひとつでなければなりません。他にも凝集度,結合度,依存管理などに関する原則があります。一方でこのような抽象的な原則を適用するよりも,まずいコードを探す方が簡単な場合もよくあります。"巨大なクラス","巨大なメソッド" は "クラス抽出" や "メソッド抽出/移動" で治療できます。それでも SRP を知っていた方が,クラスやメソッドのどの部分を抽出すべきかを決定する上で役には立ちます。

最も重要な設計原則はおそらく "命じよ,求めるな (Tell, don't ask)" でしょう。機能とデータを合わせて保持せよ,という意味です。悪いコードでは機能と,それに必要なデータが別々のことがよくありますが,これはローカル性の欠如と依存性の問題を引き起こします。その象徴が "機能追加時に多くのコード変更が必要になる" という現象でしょう。まずいコードのパターンである "ショットガン手術 (shotgun surgery)","機能の嫉妬 (Feature Envy)","長いパラメータリスト" などがこれにあたります。

迅速なフィードバックの獲得がさらなるリファクタリングを可能にして,(ついには)新機能のより早い開発を可能にします。並列ビルド (分散コンパイル) が実行できるようにしましょう。より小さなソースファイル,ヘッダファイルを作りましょう。ヘッダファイルの複雑性を下げるために,前方参照定義の利用,インラインコードの回避を心がけましょう。ヘッダファイル/ソースファイルにはひとつのクラスを記述するようにしましょう。"pimpl" イディオムを広く採用するとコンパイル時間を10%程度減少できますが,"大きなクラス" や "機能の嫉妬 (Feature Envy)" が隠れている場合もあります。

書き直しを行う場合と比較すると,リファクタリングの利点は "動作するコードが常に手元にある" ということです。手動ないし自動で行うテストの内容が十分なものであれば,たとえ状態が悪い設計からよい設計への中間段階にあったとしても,コードの出荷は可能です。

Keith は “Refactoring: Small Steps Guaranteed to Help You Clean Up Your Code” という,C++ コードをリファクタする記事を Better Software Magazine に寄稿してもいる。

これまでに InfoQ で取り上げた関連記事は次のものだ。"Dealing with Legacy Code","Bobおじさんが述べるTDDの適用可能性","TDDを根づかせる:導入の問題と解決策"

特集コンテンツ一覧

GAE開発の落とし穴

Googleのクラウド環境をつかったGoogle App Engineによる開発するにあたり、初めての試みで苦悩する開発者達の経験をもとに、各開発フェーズにあわせて問題点やどう解決したかをご紹介します

イベントレポート:「Coqチュートリアル#1」

去る1月12日、定理証明支援系ツールCoqの初心者向けチュートリアルが開催さ れた(http://kokucheese.com/event/index/23667/)。今後も2月2日 (http://kokucheese.com/event/index/23744/)、2月9日、2月16日と引き続き開 催されていく予定である。本記事では、開催の様子をレポートする。

Javaの未来についてのNeal Gafter氏とのディスカッション

Choosing Options

Neal Gafter氏はOracleによるJava買収の影響に関する議論、Javaにセグメンテッドスタックやメタオブジェクトプロトコルを追加することについての主張、そしてJavaとC#との比較について話をしてくれた。

Google Dartのエッセンス:アプリケーションの構築、スナップショット、Isolate

GoogleはVMをともなう新しい言語であり、JSコンパイラでもあるDartをプレビューした。 InfoQはDartのアプリの構築に貢献する文法の裏側を探った:スナップショット、Isolate、モジュール方式

CSPベースのモデル検査ツール「Process Analysis Toolkit」

本記事ではCSPベースの「マルチドメイン・モデル検査ツール」である、PAT(Process Analysis Toolkit)について紹介する。モデル検査は、形式手法(Formal Method)という方法論を基礎とする技術であり、複雑さが増大しながらも安全性を求められる、現在のソフトウェア開発の状況に対する処方箋の1つとして注目されている手法である。

Jenkinsによる継続的インテグレーションのススメ(4) ~CloudBeesでJenkinsをサービスとして使う~

前回まで、Jenkinsの幾つかの側面に注目して解説をしてきました。シリーズ最後の今回は、Jenkinsをサービスとして使う方法を紹介します。

書籍『抽象によるソフトウェア設計-Alloyではじめる形式手法-』の紹介

Alloyは、MITにて開発された仕様記述言語であり、ツールによる自動解析を使い、インクリメンタルに形式仕様が書けることが特長である。筆者らはAlloy開発者による、Alloyを使った形式手法入門書を翻訳、今夏にオーム社より刊行した。本記事では、Alloyの簡単な概要と、翻訳書『抽象によるソフトウェア設計』(「Alloy本」)を紹介する。

Windows デバイスで開発するタッチユーザーインターフェイス

スマートフォンを中心としたマルチデバイスにおけるタッチユーザーインターフェイスへの対応は、既に必須の項目となりつつある。本記事では、Windows デバイスにおける UX のベースとなっている「メトロ」というデザイン言語を掘り下げながら、既存環境を意識しつつもどのようにタッチユーザーインターフェイス開発に取り組んでいくべきであるかについて解説していく。