デザインは死んだのか?

エクストリームプログラミング(XP)に短時間触れた多くの人にとって、XPはソフトウェア設計の死を招くように見えるかもしれません。多くの設計活動は「ビッグアップフロントデザイン」として嘲笑されるだけでなく、UML、柔軟なフレームワーク、さらにはパターンなどの設計手法は軽視されたり、完全に無視されたりさえします。実際、XPには多くの設計が含まれていますが、確立されたソフトウェアプロセスとは異なる方法で行われます。XPは、進化を現実的な設計戦略にすることを可能にするプラクティスによって、進化型設計の概念を活性化しました。また、単純な設計の方法、リファクタリングを使用して設計をクリーンに保つ方法、進化型スタイルでパターンを使用する方法を学ぶ必要があるため、設計者にとって新しい課題とスキルも提供します。

2004年5月



エクストリームプログラミング (XP)は、ソフトウェア開発に関する多くの一般的な前提に挑戦します。その中で最も論争を呼ぶものの1つは、より進化的なアプローチを支持して、事前設計に多大な労力を費やすことを拒否することです。批判者にとっては、これは「コードと修正」開発(通常はハッキングとして軽蔑される)への回帰です。ファンにとっては、それはしばしば(UMLなどの)設計手法、原則、パターンの拒絶と見なされます。コードに耳を傾ければ、良い設計が現れるので、デザインのことは心配しないでください。

私はこの議論の中心にいます。私のキャリアの多くは、統一モデリング言語(UML)とその前身、そしてパターンを含むグラフィカルな設計言語に携わってきました。実際、UMLとパターンの両方について本を書いています。XPを受け入れるということは、これらの主題について私が書いたすべてを撤回し、そのような反革命的な概念をすべて私の心から洗い流すことを意味するのでしょうか?

さて、劇的な緊張のフックにぶら下がったままにしておくわけにはいきません。簡潔に言うと、答えはノーです。詳しい説明は、この論文の残りの部分です。

計画的設計と進化型設計

この論文では、ソフトウェア開発において設計が行われる2つのスタイルについて説明します。おそらく最も一般的なのは進化型設計です。基本的に、進化型設計とは、システムの設計がシステムの実装とともに成長することを意味します。設計はプログラミングプロセスの1部分であり、プログラムが進化するにつれて設計も変化します。

一般的な用法では、進化型設計は災害です。設計は、一連の場当たり的な戦術的決定の集積になり、それぞれがコードの変更を難しくします。多くの点で、これは設計ではないと主張するかもしれません。確かに、それは通常、貧弱な設計につながります。Kentの言葉によると、設計は、長期間にわたってソフトウェアを簡単に変更できるようにするためのものです。設計が悪化すると、変更を効果的に行う能力も悪化します。ソフトウェアエントロピーの状態になり、時間の経過とともに設計が悪化します。これにより、ソフトウェアの変更が難しくなるだけでなく、バグが発生しやすくなり、発見と安全な修正も難しくなります。これが「コードと修正」の悪夢であり、プロジェクトが進むにつれてバグの修正費用が指数関数的に増加します。

計画的設計はこれに対する対抗策であり、他の工学分野から生まれた概念を含んでいます。犬小屋を建てたい場合、木材をいくつか集めて大まかな形にするだけで済みます。しかし、超高層ビルを建てたい場合、そうした方法ではうまくいきません。半分も完成する前に崩壊してしまうでしょう。そのため、妻がボストンのダウンタウンで働いているような設計事務所で作成されたエンジニアリング図面から始めます。設計を行う際に、彼女はすべての問題を解決します。一部は数学的分析によって、一部は建築基準法を使用して行われます。建築基準法とは、何が機能するかの経験(および基礎となる数学)に基づいて構造を設計する方法に関する規則です。設計が完了したら、彼女の設計会社は設計を別の建設会社に引き渡すことができます。

ソフトウェアにおける計画的設計も同じように機能するはずです。設計者は事前に大きな問題を考え出します。ソフトウェアを構築しているわけではないため、コードを書く必要はありません。設計をしているのです。そのため、プログラミングの詳細から離れ、設計者がより抽象的なレベルで作業できるUMLなどの設計手法を使用できます。設計が完了したら、別のグループ(または別の会社でも)に構築を委託できます。設計者はより大規模に考えているため、ソフトウェアエントロピーにつながる一連の戦術的決定を回避できます。プログラマーは設計の方向に従うことができ、設計に従う限り、優れたシステムを構築できます。

計画的設計アプローチは70年代から存在しており、多くの人が使用しています。コードと修正による進化型設計よりも多くの点で優れています。しかし、欠点もあります。最初の欠点は、プログラミング時に対処する必要があるすべての問題を完全に考え抜くことが不可能であるということです。そのため、プログラミング時に設計に疑問を投げかけるものが見つかるのは避けられません。しかし、設計者が完了して別のプロジェクトに移行した場合、どうなるでしょうか?プログラマーは設計を回避してコーディングを開始し、エントロピーが発生します。設計者がいなくても、設計の問題を解決し、図面を変更し、コードを変更するのに時間がかかります。通常、より迅速な修正と時間的制約があります。したがって、再びエントロピーが発生します。

さらに、文化的にも問題があります。設計者はスキルと経験によって設計者になりますが、設計に忙しいため、コードを書く時間はほとんどありません。しかし、ソフトウェア開発のツールと素材は急速に変化しています。コードを書かなくなると、この技術的な変動に伴う変化を見逃すだけでなく、コードを書く人の尊敬も失う可能性があります。

この建設者と設計者の間の緊張は、建設でも発生しますが、ソフトウェアではより激しくなります。それは重要な違いがあるためです。建設では、設計者と建設者の間のスキルに明確な区別がありますが、ソフトウェアではそうではありません。高度な設計環境で働くプログラマーは、非常に熟練している必要があります。特に設計者が開発プラットフォームの日常の現実についてあまり詳しくない場合、設計者の設計に疑問を呈するのに十分なスキルが必要です。

さて、これらの問題は解決できるかもしれません。おそらく、人間の緊張に対処できるでしょう。おそらく、ほとんどの問題に対処できるほど熟練した設計者を得て、図面を変更するのに十分な規律のあるプロセスを持つことができるでしょう。それでも、別の問題があります。変更される要件です。変更される要件は、私が遭遇するソフトウェアプロジェクトで頭痛の種となる最大の課題です。

変更される要件に対処する1つの方法は、設計に柔軟性を組み込み、要件が変更されたときに簡単に変更できるようにすることです。ただし、そのためには、どのような変更を期待するかを理解する必要があります。設計は変動性の領域に対処するように計画できますが、これは予見された要件の変更には役立ちますが、予見されていない変更には役立ちません(そして害を及ぼす可能性があります)。そのため、要件を十分に理解して、変動性の領域を分離する必要がありますが、私の観察によると、これは非常に困難です。

さて、これらの要件の問題のいくつかは、要件を十分に理解していないことが原因です。そのため、多くの人が要件エンジニアリングプロセスに焦点を当て、より良い要件を取得しようとします。これは、後で設計を変更する必要性を回避することを期待してのことです。しかし、この方向性も解決策につながるものではない可能性があります。多くの予期せぬ要件の変更は、ビジネスの変化によって発生します。要件エンジニアリングプロセスがどれだけ慎重であっても、それらは防ぐことができません。

そのため、これらすべてにより、計画的設計は不可能に聞こえます。確かに大きな課題があります。しかし、「コードと修正」の方法で最も一般的に実践されている進化型設計よりも計画的設計が悪いと主張する気はありません。「コードと修正」よりも計画的設計の方が優れています。しかし、計画的設計の問題を認識しており、新しい方向を探しています。

XPを可能にするプラクティス

XPは多くの理由で論争を呼んでいますが、XPにおける重要な危険信号の1つは、計画的設計ではなく進化型設計を提唱していることです。ご存知のとおり、進化型設計は、場当たり的な設計上の決定とソフトウェアエントロピーのために機能するはずがありません。

この議論を理解する上で中心となるのは、ソフトウェア変更曲線です。変更曲線とは、プロジェクトが実行されるにつれて、変更を行う費用が指数関数的に増加することを示しています。変更曲線は通常、「分析で1ドルで行われた変更は、本番環境では修正するのに数千ドルかかる」というフェーズの観点から表現されます。これは皮肉なことです。ほとんどのプロジェクトはまだ分析フェーズを持たない場当たり的なプロセスで機能していますが、指数関数的な増加は依然として存在します。指数関数的な変更曲線は、進化型設計が機能するはずがないことを意味します。また、計画的設計を慎重に行う必要がある理由も伝えています。計画的設計の誤りには、同じ指数関数的な増加が適用されるためです。

XPの基礎となる根本的な仮定は、進化型設計を機能させるのに十分なほど変更曲線を平坦化できるということです。この平坦化はXPによって実現され、XPによって活用されます。これはXPプラクティスのカップリングの一部です。具体的には、平坦化された曲線を活用するXPの部分は、平坦化を可能にするものを行わなければ実行できません。これはXPに関する論争の一般的な原因です。多くの人が、実現を理解せずに活用を批判します。多くの場合、批判は、活用を可能にするプラクティスを行わなかった批判者自身の経験に由来します。その結果、彼らは火傷し、XPを見ると火を思い出します。

実現のプラクティスには多くの部分があります。中心となるのは、テストと継続的インテグレーションのプラクティスです。テストによって提供される安全性がないと、XPの残りの部分は不可能になります。継続的インテグレーションはチームを同期させるために必要であり、変更を行い、他のユーザーとの統合を心配する必要はありません。これらのプラクティスを組み合わせることで、変更曲線に大きな影響を与えることができます。Thoughtworksで再びこれを思い出しました。テストと継続的インテグレーションを導入することで、開発作業が著しく改善されました。確かに、XPが大きな改善を得るにはすべてのプラクティスが必要であるという主張に真剣に疑問を呈するのに十分です。

リファクタリングも同様の効果があります。XPで提案されている規律のある方法でコードをリファクタリングする人は、より緩やかで場当たり的な再構築を行う場合と比較して、その効果に大きな違いを見出します。Kentが適切にリファクタリングする方法を教えてくれた後の私の経験でした。結局のところ、これほど大きな変化があったからこそ、それについての本を書く気になったのです。

ジム・ハイスミスは、彼の優れたXPの概要サマリーにおいて、天秤のアナロジーを用いています。一方の皿には計画設計、もう一方の皿にはリファクタリングがあります。より伝統的なアプローチでは、後で考えを変えることはできないという前提から、計画設計が優勢です。変更コストが低くなるにつれて、リファクタリングとして後で設計を行うことができます。計画設計が完全に消えるわけではありませんが、今では2つの設計アプローチのバランスを取って作業する必要があります。私にとっては、リファクタリング前は片手で全ての設計をしていたような感覚です。

継続的インテグレーション、テスト、リファクタリングといったこれらの有効なプラクティスは、進化型設計を現実的にする新しい環境を提供します。しかし、まだわかっていないことの1つは、バランス点がどこにあるかということです。外からの印象とは異なり、XPは単なるテスト、コーディング、リファクタリングだけではないことは確かです。コーディング前に設計を行う余地があります。その一部はコーディングが行われる前に行われ、大部分は特定のタスクのコーディング前のイテレーションで行われます。しかし、事前設計とリファクタリングの間に新しいバランスが生まれています。

シンプルさの価値

XPにおける2つの最大の合言葉は、「可能な限り最も単純なことを行う」と「それは必要ないだろう」(YAGNIとして知られる)というスローガンです。どちらも、XPのシンプル設計プラクティスの表れです。

YAGNIは通常、明日必要になる機能によってのみ使用されるコードを今日追加すべきではないと説明されています。一見するとこれは簡単です。問題は、フレームワーク、再利用可能なコンポーネント、柔軟な設計などです。このようなものは構築が複雑です。それらを構築するために事前に追加コストを支払いますが、後でそのコストを取り戻せるという期待があります。この事前に行う柔軟性の構築という考え方は、効果的なソフトウェア設計の重要な部分と考えられています。

しかし、XPのアドバイスは、その機能を必要とする最初のケースのために柔軟なコンポーネントやフレームワークを構築しないということです。これらの構造は必要に応じて成長させましょう。もし今日、加算は処理するが乗算は処理しないMoneyクラスが必要であれば、Moneyクラスには加算のみを組み込みます。次のイテレーションで乗算が必要になることが確実で、簡単に実装する方法を理解しており、非常に迅速に実行できると考えていても、次のイテレーションまで延期します。

その理由の1つは経済的なものです。明日必要な機能にのみ使用される作業を行う必要がある場合、それはこのイテレーションのために実行する必要がある機能からの努力の損失を意味します。リリース計画は現在取り組む必要があるものを示しており、将来の他の作業を行うことは、顧客との開発者の合意に反します。このイテレーションのストーリーが完了しないリスクがあります。このイテレーションのストーリーにリスクがなくても、追加作業を行うかどうかは顧客が決定する必要があります。そして、それは依然として乗算を含まない可能性があります。

この経済的なインセンティブの欠如は、正しく実装できない可能性によってさらに悪化します。この機能の動作方法についてどれだけ確信していたとしても、依然として間違える可能性があります。特に、まだ詳細な要件がない場合はなおさらです。間違ったソリューションを早期に作業することは、正しいソリューションを早期に作業するよりもさらに無駄になります。そして、XPのエキスパートは一般的に、正しいよりも間違っている可能性の方がはるかに高いと考えています(私もその意見に同意します)。

シンプル設計の2つ目の理由は、複雑な設計は単純な設計よりも理解が難しいことです。したがって、システムのいかなる変更も、追加された複雑さによって困難になります。これは、より複雑な設計が追加されてから必要になるまでの間にコストを追加します。

さて、このアドバイスは多くの人々にとってナンセンスに思えるでしょうし、そう思うのは正しいでしょう。XPの有効なプラクティスが整備されていない通常の開発の世界を想像すればの話ですが。しかし、計画設計と進化型設計のバランスが変わると、YAGNIは良いプラクティスになります(そしてその時のみ)。

要約すると、将来のイテレーションまで必要にならない新しい機能を追加することに努力を費やしたくありません。そして、コストがゼロであっても、追加したくないのです。なぜなら、たとえ投入コストがゼロであっても、変更コストが増加するからです。しかし、変更コストを低減するXP、または同様の手法を使用している場合にのみ、このように行動するのは理にかなっています。

そもそもシンプルさとは何か

そのため、コードは可能な限りシンプルにしたいと考えています。結局のところ、誰が複雑になりたがるでしょうか?しかし、もちろん、「シンプルとは何か?」という疑問が残ります。

XPEで、Kentはシンプルなシステムの4つの基準を示しています。(重要度順)

  • すべてのテストが実行される
  • 重複がない
  • すべての意図が明らかになっている
  • クラスまたはメソッドの数が最も少ない

すべてのテストを実行することは、非常に単純な基準です。重複がないことも非常に簡単ですが、多くの開発者はそれを達成する方法に関するガイダンスを必要としています。難しいのは、意図を明らかにするという点です。それは正確にはどういう意味でしょうか?

ここでの基本的な価値は、コードの明瞭さです。XPは、簡単に読めるコードを高く評価しています。XPでは、「巧妙なコード」は侮辱的な言葉です。しかし、ある人の意図を明らかにするコードが、別の人にとっては巧妙なコードとなることもあります。

Josh Kerievskyは、彼のXP 2000の論文で、この良い例を示しています。彼は、おそらく最も公開されているXPコードであるJUnitを見ています。JUnitはデコレーターを使用して、テストケースにオプションの機能(同時実行同期やバッチ設定コードなど)を追加します。このコードをデコレーターに分離することで、一般的なコードをそれ以外の場合よりも明確にすることができます。

しかし、結果として得られるコードが本当にシンプルかどうか自問自答する必要があります。私にとってはシンプルですが、デコレーターパターンに精通しているからです。しかし、そうでない多くの人にとって、それはかなり複雑です。同様に、JUnitはプラグ可能なメソッドを使用しており、ほとんどの人が最初は明確とは程遠いものだと気づきました。したがって、JUnitの設計は経験豊富な設計者にとってはシンプルだが、経験の少ない人にとっては複雑であると結論付けることができるでしょうか?

XPの「一度だけ」とPragmatic ProgrammerのDRY(Don't Repeat Yourself)による重複排除に焦点を当てることは、明白で驚くほど強力な良いアドバイスの1つです。それだけでかなり進歩できます。しかし、すべてではありません。シンプルさは、依然として見つけるのが難しいものです。

最近、過剰設計されている可能性のある作業に関わっていました。それはリファクタリングされ、柔軟性のいくつかは削除されました。しかし、開発者の1人が言ったように「過剰設計をリファクタリングする方が、設計がないものをリファクタリングするよりも簡単です」。必要以上に少しシンプルにするのが最善ですが、少し複雑になるのも大惨事ではありません。

これについて私が聞いた最良のアドバイスは、アンクルボブ(Robert Martin)からのものです。彼のアドバイスは、最も単純な設計にこだわりすぎないことでした。結局のところ、後でリファクタリングできますし、すべきですし、リファクタリングするでしょう。最終的に、最も単純なものをすぐに知るよりも、リファクタリングする意思の方がはるかに重要です。

リファクタリングはYAGNIに違反するのか?

このトピックは最近XPのメーリングリストで取り上げられ、XPにおける設計の役割を検討する上で取り上げる価値があります。

基本的に、問題は、リファクタリングには時間がかかるが機能を追加しないという点から始まります。YAGNIのポイントは、将来ではなく現在のために設計することであるため、これは違反でしょうか?

YAGNIのポイントは、現在のストーリーに必要のない複雑さを追加しないということです。これは、シンプル設計の実践の一部です。設計を可能な限りシンプルに保つためにリファクタリングが必要であるため、よりシンプルにできることに気付いたらいつでもリファクタリングする必要があります。

シンプル設計は、XPプラクティスを活用し、有効なプラクティスでもあります。テスト、継続的インテグレーション、リファクタリングがある場合にのみ、シンプル設計を効果的に実践できます。しかし同時に、設計をシンプルに保つことは、変更曲線を平坦に保つために不可欠です。不要な複雑さは、組み込んだ複雑な柔軟性で予期する方向を除くすべての方向において、システムの変更を困難にします。しかし、人々は予期するのが得意ではないため、シンプルさを目指すのが最善です。しかし、人々は最初に最も単純なものを得るわけではないため、目標に近づくためにリファクタリングする必要があります。

パターンとXP

JUnitの例は、必然的にパターンを取り上げることにつながります。パターンとXPの関係は興味深いものであり、よくある質問です。Joshua Kerievskyは、パターンはXPでは軽視されていると主張し、雄弁にその主張を行っているため、それを繰り返すつもりはありません。しかし、多くの人にとってパターンはXPと矛盾しているように見えることを覚えておく価値があります。

この議論の本質は、パターンがしばしば過剰に使用されているということです。「GOF」を初めて読んだばかりの伝説的なプログラマーの世界は、32行のコードに16個のパターンを含めることで満ち溢れています。ある夜、とても良いシングルモルトを飲んで勢いづいた私は、Kentと共に「デザインパターンではない:23個の安易なテクニック」という論文を検討していました。戦略ではなくif文を使用するなどについて考えていました。冗談には真意があり、パターンはしばしば過剰に使用されますが、だからといって悪いアイデアではありません。問題は、どのようにそれらを使用するかです。

一つの理論として、シンプルな設計の原則に従うことで、自然とデザインパターンにたどり着くというものがあります。多くのリファクタリングはこれを明確に行っていますが、それらを使わなくても、シンプルな設計のルールに従うことで、たとえ事前にパターンを知っていなくても、パターンを思いつくことができるでしょう。これは真実かもしれませんが、本当に最善の方法と言えるでしょうか?目的地を大まかに把握し、問題を解決するための助けとなる書籍があれば、すべてを自分で発明するよりも良いはずです。私自身、パターンが浮かんでくるたびに、今でもGOF(Gang of Fourのデザインパターン本)を参照しています。効果的な設計においては、パターンのコストに見合う価値があるかどうかを判断する必要があると考えています。これは、それ自体がスキルと言えるでしょう。同様に、Joshua(おそらくJoshua Kerievskyのこと)が示唆するように、パターンを段階的に導入する方法にもっと精通する必要があります。この点で、XPはパターンを使用する方法を、他の人々がパターンを使用する方法とは異なって扱いますが、パターンの価値を否定するものではありません。

しかし、いくつかのメーリングリストを読んでいると、多くの人がXPをパターンを推奨しないものと捉えているという明確な印象を受けます。皮肉なことに、XPの提唱者の多くは、パターン運動のリーダーでもあったのですが。これは、彼らがパターンを超越したからでしょうか、それともパターンが彼らの思考に深く根付いているため、もはやそれを意識していないからでしょうか?他の人々の理由は分かりませんが、私にとってパターンは依然として非常に重要です。XPは開発プロセスかもしれませんが、パターンは設計知識のバックボーンであり、どのようなプロセスであっても価値のある知識です。異なるプロセスでは、パターンを異なる方法で使用することができます。XPは、必要になるまでパターンを使用しないことと、シンプルな実装を通じてパターンに進化していくことを強調しています。しかし、パターンは依然として習得すべき重要な知識です。

パターンを使用するXP実践者への私のアドバイスは次のとおりです。

  • パターンについて学ぶことに時間をかける
  • パターンを適用するタイミングに集中する(早すぎないこと)
  • まず、パターンを最も単純な形で実装することに集中し、その後で複雑さを追加する。
  • パターンを実装して、後でそれが役立っていないことに気づいたら、ためらうことなく削除する。

XPはパターンに関する学習をもっと重視すべきだと思います。それをXPの実践にどのように組み込むかは分かりませんが、Kent(おそらくKent Beckのこと)なら方法を思いつくでしょう。

アーキテクチャの成長

ソフトウェアアーキテクチャとは何でしょうか?私にとって、アーキテクチャという用語は、システムの中核となる要素、変更が困難な部分という概念を伝えています。残りの部分が構築される基盤です。

進化的な設計を使用する場合、アーキテクチャは何の役割を果たすのでしょうか?XPの批判者は、XPはアーキテクチャを無視し、迅速にコードを作成し、リファクタリングですべての設計上の問題を解決できると信じていると主張しています。興味深いことに、彼らは正しく、それが弱点となる可能性があります。確かに、最も積極的なXP実践者であるKent Beck、Ron Jeffries、Bob Martinは、事前設計によるアーキテクチャ設計を避けることにますます多くのエネルギーを注いでいます。本当に必要だと分かるまでデータベースを導入しないでください。まずはファイルで作業し、後のイテレーションでデータベースをリファクタリングで導入しましょう。

私は臆病なXP実践者として知られていますが、そのため反対せざるを得ません。私は、幅広い出発点となるアーキテクチャの役割があると考えています。アプリケーションの階層化の方法、データベースとのインタラクションの方法(必要であれば)、ウェブサーバーの処理に使用するアプローチなどを早期に決定することなどが挙げられます。

本質的に、これらの多くの領域は、長年にわたって学んできたパターンです。パターンの知識が増えるにつれて、それらを使用するための妥当な最初の方法を考え出すことができるはずです。しかし、重要な違いは、これらの初期のアーキテクチャの決定は、不動のものになることが期待されていない、あるいはチームは初期の決定で誤る可能性があることを認識しており、それらを修正する勇気を持つべきだということです。他の人は、あるプロジェクトが、展開直前にEJBが不要だと判断し、システムから削除したという話をしています。それは大規模なリファクタリングであり、遅れて行われましたが、イネーブルリングプラクティスのおかげで、可能になるだけでなく、価値のあるものになりました。

逆はどうだったでしょうか?EJBを使用しないと決定した場合、後で追加することはより困難になるでしょうか?したがって、EJBを使用せずに試してみて不足していることが分かった場合を除いて、EJBから始めるべきではないでしょうか?これは多くの要因が関係する質問です。確かに、複雑なコンポーネントを使用しないことで、シンプルさが増し、作業が迅速になります。しかし、時には、そのようなものを取り除く方が、追加するよりも簡単です。

そのため、私のアドバイスは、まず可能性のあるアーキテクチャを評価することです。大量のデータと複数のユーザーがいる場合は、初日からデータベースを使用してください。複雑なビジネスロジックがある場合は、ドメインモデルを導入してください。しかし、YAGNI(You Ain't Gonna Need It)の神々に敬意を表して、疑わしい場合は、シンプルさを優先してください。また、アーキテクチャの一部が何も追加していないことに気づいたらすぐに、アーキテクチャを簡素化する準備をしましょう。

UMLとXP

XPへの関与について私が受ける質問の中で、最も多いものの1つは、UMLとの関連性に関するものです。この2つは互換性がないのではないでしょうか?

いくつかの非互換性のポイントがあります。確かに、XPは図を大幅に軽視しています。公式の立場は「役立つなら使用してください」というものでしたが、「真のXP実践者は図を描かない」という強い含みがあります。これは、Kentのような人々が図に全く慣れていないという事実によって強化されています。実際、私はKentが任意の固定表記でソフトウェアの図を自主的に描いたのを見たことがありません。

この問題は、2つの別々の原因から生じていると思います。1つは、ソフトウェアの図を役に立つと感じる人もいれば、そうでない人もいるという事実です。危険なのは、役に立つと考える人が、役に立たないと考える人にもそうすべきだと考え、その逆も同様であるということです。代わりに、図を使う人もいれば、使わない人もいることを受け入れるべきです。

もう1つの問題は、ソフトウェアの図がヘビーウェイトなプロセスと関連付けられる傾向があることです。そのようなプロセスは、役に立たない図を描くのに多くの時間を費やし、実際には害を及ぼす可能性があります。「必要な場合のみ(臆病者)」というXP実践者からよく出てくるメッセージではなく、図をうまく使用し、落とし穴を避ける方法を人々にアドバイスすべきだと思います。

そこで、図をうまく使用するための私のアドバイスを以下に示します。

まず、図を描く目的を心に留めておきましょう。主な価値はコミュニケーションです。効果的なコミュニケーションとは、重要なものを選択し、重要でないものを無視することです。この選択性がUMLをうまく使用する鍵です。すべてのクラスを描く必要はありません。重要なものだけを描きます。各クラスについて、すべての属性と操作を表示する必要はありません。重要なものだけを表示します。すべてのユースケースとシナリオについてシーケンス図を描く必要はありません…お分かりいただけたと思います。図の一般的な使用方法でよくある問題は、人々が図を包括的にしようとすることです。コードは包括的な情報の最良のソースであり、コードをコードと同期させるのが最も簡単なものです。図の場合、包括性は理解の敵です。

図の一般的な用途は、コーディングを開始する前に設計を検討することです。そのような活動はXPでは違法であるという印象を受けることがよくありますが、それは真実ではありません。多くの人が、難しいタスクがある場合、最初に集まって迅速な設計セッションを行う価値があると述べています。ただし、そのようなセッションを行う場合は

  • 短くする
  • すべての詳細に対処しようとしない(重要なものだけ)
  • 結果として得られた設計をスケッチとして扱い、最終設計としては扱わない

最後の点は詳しく説明する価値があります。事前に設計を行うと、設計のいくつかの側面が間違っていることが避けられず、コーディング時にのみ発見されます。その後で設計を変更すれば、それは問題ではありません。問題は、人々が設計が完了したと考えて、コーディングを通じて得られた知識を設計に反映させない場合です。

設計を変更するとは、必ずしも図を変更するという意味ではありません。設計を理解するのに役立つ図を描いて、その後図を破棄することは完全に理にかなっています。図を描くことで助けになり、それが図を価値のあるものにするのに十分です。永続的な成果物になる必要はありません。最高のUML図は成果物ではありません。

多くのXP実践者はCRCカードを使用しています。それはUMLと矛盾しません。私は常にCRCとUMLを組み合わせて使用しており、その場に応じて最も役立つ手法を使用しています。

UML図のもう1つの用途は、継続的なドキュメントです。通常の形では、これはCASEツールにあるモデルです。このドキュメントを維持することで、システムに取り組む人々が助けられるという考えです。実際には、ほとんど役に立ちません。

  • 図を最新の状態に保つのに時間がかかりすぎるため、コードと同期しなくなります。
  • CASEツールまたは厚いバインダーに隠されているため、誰も見ていません。

そのため、継続的なドキュメントに関するアドバイスは、これらの観察された問題から導き出されます。

  • 目立った苦労をすることなく最新の状態に保つことができる図のみを使用する。
  • 誰もが簡単にアクセスできる場所に図を配置する。私は壁に掲示するのが好きです。簡単な変更については、ペンで壁の文書を編集することをお勧めします。
  • 人々がそれらを使用しているかどうか注意し、使用していない場合は破棄する。

UMLの使用の最後の側面は、あるグループから別のグループへの引き継ぎなど、引き継ぎの状況におけるドキュメントです。ここでXPのポイントは、ドキュメントの作成は他のユーザーストーリーのようなものであり、したがってそのビジネス価値は顧客によって決定されるということです。ここでもUMLは役立ちますが、コミュニケーションを支援するために図を選択する必要があります。コードは詳細情報のリポジトリであり、図は重要な問題を要約して強調表示する役割を果たしていることを覚えておいてください。

メタファーについて

まあ、公に言ってもいいでしょう。私はまだこのメタファーというもののやり方が分かりません。C3プロジェクトでうまく機能するのを見ましたが、それをどのように行うか、ましてやそれを説明する方法が分かるわけではありません。

XPのメタファーの実践は、Ward Cunninghamのアプローチである名前のシステムに基づいています。ポイントは、ドメインについて話すための語彙として機能する、よく知られた一連の名前を考案することです。この名前のシステムは、システム内のクラスとメソッドの名前の付け方に影響を与えます。

ドメインの概念モデルを構築することで、命名体系を構築しました。これは、UMLまたはその前身を用いて、ドメインエキスパートと共に実施しました。この作業には注意が必要であることを学びました。最小限のシンプルな表記法を維持し、技術的な問題がモデルに侵入するのを防ぐ必要があります。しかし、これを行うことで、ドメインエキスパートが理解し、開発者とのコミュニケーションに使用できるドメインの語彙を構築できることが分かりました。モデルはクラス設計と完全に一致するわけではありませんが、ドメイン全体に共通の語彙を提供するのに十分です。

この語彙が、給与計算を工場の組立ラインに変えたC3メタファーのような比喩的なものであっても、何ら問題はないと考えます。しかし、命名体系をドメインの語彙に基づけることが悪い考えだとも思いません。また、自分にとってうまく機能する命名体系構築の手法を放棄するつもりもありません。

XPは、少なくともシステムのアウトライン設計が必要であるという理由で批判されることがよくあります。XP実践者はしばしば「それはメタファーだ」と答えます。しかし、メタファーが納得のいくように説明されているのを見たことがありません。これはXPにおける真の欠陥であり、XP実践者が解決する必要がある点です。

大きくなったらアーキテクトになりたいですか?

過去10年間、"ソフトウェアアーキテクト"という用語が普及しました。私自身は、この用語の使用に個人的な抵抗を感じています。私の妻は構造エンジニアです。エンジニアとアーキテクトの関係は…興味深いものです。「アーキテクトは3つのB(バルブ、ブッシュ、バード)に適している」というのが私の好きな表現です。アーキテクトは美しい図面をたくさん作成しますが、実際にそれが建つことを保証するのはエンジニアであるという考え方です。そのため、私は「ソフトウェアアーキテクト」という用語を避けてきました。結局のところ、自分の妻ですら私にプロとしての敬意を持って接することができないなら、他の人から敬意を得られる見込みはほとんどありません。

ソフトウェアにおいて、「アーキテクト」という言葉は多くの意味を持ちます。(ソフトウェアでは、どの用語にも多くの意味があります。)しかし一般的に、それはある種の威厳を伝え、「私はただのプログラマーではありません。私はアーキテクトです」といった意味合いになります。これは「私は今アーキテクトだ。プログラミングをするには重要すぎる」と解釈される可能性があります。問題は、技術的なリーダーシップを発揮したい場合に、日常的なプログラミングの努力から身を引くべきかどうかです。

この問題は、非常に多くの感情を生み出します。もはやアーキテクトとしての役割がないという考えに激怒する人々を見てきました。「XPには経験豊富なアーキテクトのための場所はない」という叫びをよく耳にします。

設計の役割と同様に、XPが経験や優れた設計スキルを重視していないとは思いません。実際、XPの提唱者であるKent Beck、Bob Martin、そしてもちろんWard Cunninghamは、私が設計について多くのことを学んだ人々です。しかし、それは彼らの役割が、多くの人が技術的リーダーシップの役割と考えるものから変化することを意味します。

例として、Thoughtworksの技術リーダーの一人であるDave Riceを取り上げます。Daveはいくつかのライフサイクルを経験し、50人規模のプロジェクトの非公式な技術リーダーとしての役割を担っていました。リーダーとしての彼の役割は、すべてのプログラマーと多くの時間を過ごすことを意味します。彼は、プログラマーが助けを必要とする際に協力し、誰が助けを必要としているかを常に見て回ります。彼の座席位置は重要な指標です。長年のThoughtWorkerとして、彼は好きなオフィスを選べます。彼はしばらくの間、リリースマネージャーであるCaraとオフィスを共有していました。しかし、ここ数ヶ月で、彼はプログラマーが働くオープンなベイ(XPが好むオープンな「ウォー・ルーム」スタイルを使用)に移りました。これは彼にとって重要です。なぜなら、これにより彼は何が起こっているのかを見ることができ、必要な場所にいつでも手を貸すことができるからです。

XPを知っている人は、私がXPの明示的な役割である「コーチ」について説明していることに気付くでしょう。実際、XPが行う言葉遊びの一つに、主要な技術者を「コーチ」と呼ぶことが挙げられます。その意味は明確です。XPでは、技術的リーダーシップはプログラマーを指導し、意思決定を支援することで示されます。これは、優れた技術スキルだけでなく、優れた人間関係スキルも必要とする役割です。XP 2000でJack Bollesは、孤独なマスターのための余地はほとんどないとコメントしました。コラボレーションと指導が成功の鍵です。

あるカンファレンスの夕食で、Daveと私はXPの熱心な反対者と話をしました。私たちが行っていることを議論する中で、私たちのやり方の類似点は非常に顕著でした。私たちは皆、適応的な反復開発が好きでした。テストは重要でした。そのため、彼の反対の激しさに困惑しました。「私が最も望まないのは、プログラマーがリファクタリングを行い、設計をいじくり回すことだ」という彼の発言が出た時、すべてが明らかになりました。概念的な隔たりは、Daveが後で私に言った「彼が自分のプログラマーを信頼していないなら、なぜ彼らを雇うのか?」という言葉によってさらに明確になりました。XPでは、経験豊富な開発者ができる最も重要なことは、可能な限り多くのスキルをよりジュニアな開発者に伝えることです。すべての重要な決定を行うアーキテクトの代わりに、開発者に重要な決定を下すよう指導するコーチがいます。Ward Cunninghamが指摘したように、それによって彼は自分のスキルを増幅し、孤独なヒーローよりもプロジェクトに多くのものを追加します。

可逆性

XP 2002で、Enrico Zaninottoは、アジャイル手法とリーン製造の関連性について議論する興味深い講演を行いました。彼の見解では、両アプローチの主要な側面の一つは、プロセスの不可逆性を減らすことで複雑さを解消することでした。

この見解では、複雑性の主な原因の一つは、決定の不可逆性です。決定を簡単に変更できる場合、それらを正しく行うことがそれほど重要ではなくなり、生活がはるかにシンプルになります。進化型設計への帰結として、設計者は、意思決定における不可逆性をどのように回避できるかを考える必要があります。今すぐ正しい決定を得ようとするのではなく、後で決定を延期する(より多くの情報が得られるまで)、または後で容易に反転できるような方法で決定を行う方法を探します。

この可逆性をサポートするという決意は、アジャイル手法がソースコード管理システムを重視し、すべてをそのようなシステムに配置する理由の一つです。これは特に長期間にわたる決定については可逆性を保証するものではありませんが、めったに使用されない場合でも、チームに自信を与える基盤を提供します。

可逆性を考慮した設計は、エラーを迅速に検出するプロセスも意味します。反復型開発の価値の一つは、迅速な反復により顧客がシステムの成長を目撃でき、要件に誤りがあった場合、修正コストが高騰する前に発見して修正できることです。この迅速な検出は、設計においても重要です。これは、潜在的な問題領域を迅速にテストして問題が発生するかどうかを確認する必要があることを意味します。また、実際には変更を行わなくても、将来の変更がどの程度困難であるかを調べる実験を行う価値があります。つまり、システムのブランチ上で使い捨てのプロトタイプを作成します。いくつかのチームが、将来の変更をプロトタイプモードで早期に試行して、それがどの程度困難であるかを確認していると報告しています。

デザインへの意志

この記事では多くの技術的な実践に焦点を当ててきましたが、簡単に省略されがちなのは人間の側面です。

進化型設計を機能させるためには、それを収束させる原動力が必要です。この原動力は人々からしか得られません。チームの誰かが、設計品質を高く維持するという決意を持たなければなりません。

これは全員から来る必要はありません(全員から来るのは良いことですが)、通常はチームの1人か2人が設計全体を維持する責任を負います。これは通常、「アーキテクト」という用語に含まれるタスクの一つです。

この責任は、コードベースを常に監視し、どの領域が混乱し始めているかを確認し、制御不能になる前に迅速に対処することを意味します。設計の管理者は、修正を行う必要はありませんが、誰かが修正することを確実にしなければなりません。

設計意欲の欠如は、進化型設計が失敗する主な理由のようです。たとえ人々がこの記事で説明したことに精通していても、その意欲がなければ設計は行われません。

リファクタリングが難しいもの

すべて設計上の決定にリファクタリングを使用できますか?それとも、後で追加するのが困難なほど広範な問題がありますか?現時点でのXPの正統な見解は、必要なときにすべてのものが簡単に追加できるため、YAGNIが常に適用されるというものです。例外があるかどうか疑問に思います。後で追加することが物議を醸すものの良い例は国際化です。これは、後で追加するのが非常に困難なため、最初から始めるべきものですか?

このカテゴリに分類されるものがあることは容易に想像できます。しかし現実は、私たちはまだ非常に少ないデータしか持っていません。国際化など、後で何かを追加しなければならない場合、そのための労力は非常に意識します。実際には、必要になる前にそれを週ごとに追加して維持するのにかかった労力はあまり意識しません。また、誤って行った可能性があり、そのためリファクタリングが必要になる可能性もあるということもあまり意識していません。

YAGNIの正当性の部分としては、これらの潜在的なニーズの多くは、必要なくなるか、少なくとも予想した方法では必要なくなるということです。それらを行わないことで、かなりの労力を節約できます。単純なソリューションを実際に必要なものにリファクタリングする労力は必要になりますが、このリファクタリングは、すべての疑問のある機能を構築するよりも少ない労力になる可能性が高いです。

ここで考慮すべきもう一つの問題は、本当にそれを実行する方法を知っているかどうかです。国際化を何度も行ったことがある場合は、使用する必要があるパターンが分かります。そのため、正しく行う可能性が高くなります。問題に慣れていない場合よりも、そのような立場にいる場合は、先回りして構造を追加する方が良いでしょう。そのため、私のアドバイスは、実行方法を知っている場合は、今行うコストと後で実行するコストを判断できるということです。しかし、以前行ったことがない場合は、コストを十分に評価できないだけでなく、うまく行う可能性も低くなります。その場合は、後で追加する必要があります。追加したときにそれが困難であることが分かったとしても、早期に追加した場合よりも良い状態になっている可能性が高いです。チームはより経験豊富になり、ドメインをよりよく理解し、要件をよりよく理解します。多くの場合、このような状況では、20/20の視力で考えるとどれほど簡単だったかを振り返ります。思ったよりも早く追加するのが困難だった可能性があります。

これは、ストーリーの順序付けに関する質問にも関連しています。Planning XPでは、ケントと私は公に意見の相違を示しました。ケントは、ビジネス価値をストーリーの順序付けを決定する唯一の要因とすることに賛成しています。当初の意見の相違の後、ロン・ジェフリーズも現在はこの意見に同意しています。私はまだ確信がありません。ビジネス価値と技術リスクのバランスだと考えています。このリスクを軽減するために、少なくとも初期段階で国際化をある程度行うことを促すでしょう。ただし、これは最初のリリースで国際化が必要な場合にのみ当てはまります。できるだけ早くリリースすることが非常に重要です。最初のリリースで必要ない場合は、その追加の複雑さは最初のリリース後に行う価値があります。リリースされた稼働コードのパワーは計り知れません。顧客の注意を引きつけ、信頼性を高め、学習の大きな源となります。その日を近づけるためにできる限りのことを行ってください。最初のリリース後に何かを追加する方が多くの労力を要する場合でも、早くリリースする方が良いです。

新しいテクニックでは、その提唱者たちが境界条件を確信していないのは当然です。ほとんどのXP実践者は、ある問題に対して進化型の設計が不可能だと教えられてきましたが、実際には可能であることを発見しました。「不可能」な状況を克服することで、そのような状況はすべて克服できるとの自信につながります。もちろん、そのような一般化を行うことはできませんが、XPコミュニティが限界に達して失敗するまで、これらの限界がどこにあるのかを知ることはできません。そして、他の人が見ている可能性のある限界を超えようとするのは正しいことです。

(ジム・ショアによる最近の記事では、国際化を含むいくつかの状況について、潜在的な境界が実際には障壁ではなかったことが議論されています。)

デザインは行われているのか?

進化型設計の困難さの1つは、設計が実際に進んでいるかどうかを判断するのが非常に難しいことです。設計とプログラミングを混在させる危険性は、設計なしにプログラミングが行われる可能性があることです。これは、進化型設計が逸脱して失敗する状況です。

開発チームにいる場合は、コードベースの品質によって設計が行われているかどうかを感知できます。コードベースがより複雑になり、扱いづらくなっている場合、十分な設計が行われていません。しかし悲しいことに、これは主観的な見解です。設計品質に関する客観的な見解を与えることができる信頼できる指標はありません。

この可視性の欠如が技術者に難しい場合、チームの非技術メンバーにとってはさらに深刻です。あなたがマネージャーまたは顧客である場合、ソフトウェアが適切に設計されているかどうかをどのように判断できますか?将来、設計の悪いソフトウェアの変更コストが高くなるため、これは重要です。簡単な答えはありませんが、いくつかのヒントを以下に示します。

  • 技術者の意見に耳を傾けてください。変更が困難だと不満を言っている場合は、その不満を真剣に受け止め、問題を解決するための時間を与えてください。
  • 削除されるコードの量に注意してください。適切なリファクタリングを行うプロジェクトでは、不良コードが着実に削除されます。何も削除されていない場合は、ほとんど確実に十分なリファクタリングが行われていない兆候であり、設計の劣化につながります。ただし、どの指標も悪用される可能性があるため、主観的であるにもかかわらず、優れた技術者の意見はどの指標よりも重要です。

では、デザインは死んでいるのか?

決してそうではありませんが、設計の性質は変化しました。XP設計では、次のスキルを探します。

  • コードを可能な限り明確でシンプルに保つための絶え間ない願望
  • 必要性を感じたときに自信を持って改善できるリファクタリングスキル
  • パターンに関する優れた知識:解決策だけでなく、いつそれらを使用し、どのように進化させるかを理解すること。
  • 将来の変更を考慮して設計し、現在行われた決定は将来変更される必要があることを認識すること。
  • コード、図、そして何よりも会話を使用して、理解する必要がある人に設計を伝える方法を知ること。

それは恐ろしいほどのスキルですが、優れた設計者になることは常に困難でした。XPはそれをそれほど簡単にはしません。少なくとも私にとってはそうではありません。しかし、XPは進化型の設計を再び実現可能な戦略にしたため、効果的な設計について考える新しい方法を与えてくれると思います。そして、私は進化の大ファンです。そうでなければ、私は一体何になるか分かりません。


謝辞

過去数年間に、多くの優れた人々から多くの優れたアイデアを取り入れ、盗みました。これらのほとんどは、私の記憶の薄暗がりの中で失われています。しかし、ジョシュア・ケリエフスキーから良いアイデアを拝借したことは覚えています。フレッド・ジョージとロン・ジェフリーズからの多くの役立つコメントも覚えています。ワードとケントから常に多くの良いアイデアが出てくることも忘れてはいけません。

質問をしてタイプミスを見つけてくださった方々に常に感謝しています。それらを記録して謝意を表すことは怠っていましたが、クレイグ・ジョーンズ、ナイジェル・ソーン、スベン・ゴーツ、ヒラリー・ネルソン、テリー・カメルレンゴが含まれています。

参考文献

ソフトウェア設計に対する私のアプローチについて説明する記事については、私のウェブサイトのソフトウェア設計ガイドページを参照してください。これには、データベースの進化型設計サービス契約インターフェースなど、進化型設計の重要な側面に触れた記事が含まれています。

進化型設計手法の詳細については、ニール・フォードのdeveloperWorksシリーズビデオワークショップをご覧ください。

重要な改訂

2004年5月:「設計への意志」、「可逆性」、「設計が行われているか」のセクションを追加

2001年2月:アーキテクチャの成長、アーキテクトの役割、リファクタリングで追加が難しいものの場所に関するセクションを更新して記事を更新

2000年7月:元の論文がXP 2000に提出され、martinfowler.comに投稿されました。