Is TDD Dead? 会談
David Heinemeier Hansson氏の「TDD is dead」は、アジャイル界隈に醸成されていたある種の信仰を、過激な論調で批判したことによって大変なセンセーションを巻き起こした。強い言葉に対しては、やはり感情的な反応が多くなる。中には坊主憎けりゃ袈裟まで憎いという感じで、TDDを超えてRailsの設計思想を批判する人まで現れたが、「TDD is dead」を受けて行われた「Is TDD Dead?」という歴史的な会談の内容を見るに、DHH氏の発言は、規律(信仰)に対する単純なカウンターなどではなく、そこにはプログラムデザインについての重要な論点が含まれているように思える。
- Is TDD Dead?
Is TDD Dead? 会談は、2014年の5月から6月にかけて、TDD提唱者の Kent Beck 氏と今回の騒動の主である DHH 氏、そしてホスト役である Martin Fowler 氏の三者で行われた。全5回の会談の内、今回は第二回までの内容を検討してみたい。
結局のところデザインの意思決定を行うのは開発者自身である
まず全体的な印象として、DHH氏と、TDD肯定派のBeck氏、Fowler氏の意見が真正面から対立しているという感じはそれほどなく、お互いに別のところを見ていて話がすれ違っているような印象を受けた。James Shore氏の以下のツイートは、この件に関するTDD肯定派のフラストレーションを代弁している。
DHH氏の想定するようなTDDは、Beck氏やFowler氏の想定するTDDとは異なり、単にやり方が悪いからうまく行かないだけで、DHH氏の発言は「わら人形論法」に過ぎないというのが、TDD肯定派の反論である。それに対して「うまく行かないのはやり方が間違えているからであって、正しく実践すればいつかは正解に辿り着ける」というのは「faith-based TDD」という信仰であって、そのようなものは認められないというのが DHH氏の立場であり、ここがすれ違いの中心になっている。
例えばBeck氏は、DHH氏のTDD批判は、車を運転していて見当違いな場所に行ってしまったからと言ってそれを車のせいにするようなものだと言う。TDDがプログラムデザインに悪影響を与えると言った場合、デザインの意思決定を行っているのはプログラマ本人であり、TDDがデザインを決定しているわけではないと。それに対してDHH氏は、TDDを実践する事によって、あるいは実践しようとすることによって、プログラムデザインにある種の傾向が現れるのは否定出来ないと反論する。
「結局のところデザインの意思決定を行うのは開発者自身である」という話については、「TDD再考」の第二回で紹介した James O Coplien氏も同じような話をしていた。
- TDD再考 (2) – 何故、ほとんどのユニットテストは無駄なのか? | ゆびてく
TDDを実践すれば自然にプログラムデザインが改善するなどということはあり得ず、良いデザインを実現するためには結局のところ自分の頭で考えなければならないというのが、Coplien氏の場合はTDDを批判する根拠の一つになっていた。ところが、TDD提唱者のBeck氏や、肯定派のFowler氏も、この件に関しては全く同じように考えており、TDDというのは彼らにとっては思考を助ける道具に過ぎないと発言している(なので適材適所で使う場合もあれば使わない場合もある)。つまり本当の対立は、TDDを肯定するか否定するかという部分にあるのではなく、それを使えば自動的に結果が好転していくような銀の弾丸として祭り上げている勢力とそれ以外の対立という事で、このブログで繰り返し取り上げてきた問題と全く同形の問題のように思える。
凝集性と結合性は頻繁に対立する?
第二回目の会談では、「TDD再考 (6)」でも紹介した、TDDが及ぼすプログラムデザインへの悪影響について検討を行っている。Railsのようなフレームワークを利用した開発で(厳密な)TDDを実践しようとすると、各層を単独でテスト出来るようにするために間接層(indirection)やモックオブジェクトを導入する必要が出てくる。それが結果としてコードを複雑にし、メンテナンスを難しくするというのがDHH氏の指摘だ。もちろん間接層が絶対悪というわけではなく、間接層にも依存モジュールを置き換えやすくするというメリットがあるわけだが、それをテストをやりやすくするという目的のためだけに導入するのは間違っているのではないかという指摘である。
この一連の話の中で最も興味深いと思ったのが、「凝集性と結合性は頻繁に対立する(cohesion and coupling are often opposed)」というDHH氏の主張である。
凝集性と結合性、あるいは凝集度と結合度は、プログラムデザインの良し悪しを計るための最も基本的な尺度だと言われる。凝集度はより高い方が望ましく、結合度はより低い方が望ましいとされる。モジュール間の依存関係はプログラムの構造的にはっきりと見えるので、結合性というコンセプトは比較的理解しやすいが、凝集性というのは具体的にどのようなものを指しているのだろうか?
凝集性・結合性は、多くの場合、相関があるとされる。具体的には「凝集度が高いモジュールは他との結合度が低いことが多く、逆に凝集度が低ければ結合度が高くなる傾向がある(Wikipediaより)」と言われている。しかし、DHH氏は「凝集性と結合性は頻繁に対立する」と言う。
DHH氏の主張を簡単に図解してみよう。
Railsのようなフレームワークには、モデルとデータベースを密結合させた Active Record という仕組みがある。アプリケーションロジックを担当するコントローラは、この Active Record を直接操作するため、そのままだとデータベースにアクセスせずにアプリケーションロジックをテストする事は出来ない。そこでまずはアプリケーションロジックをコントローラから切り離して Action Runner というオブジェクトに移してフレームワークへの依存をなくし、その上で Action Runner は Repository という間接層を経由して Active Record の機能にアクセスするようにする。このようにすればアプリケーションロジックを Rails の枠組みに載せる事なくテスト出来るようになるというわけである。
この改造によって、確かにレイヤー間の結合度は下がったと言える。しかし、それと引き換えに凝集性が犠牲になっているというのが DHH氏の主張だ。ここで言う凝集性とは具体的に何を指しているのだろうか?
論理的凝集と機能的凝集
「凝集性」という日常的に馴染みのない言葉だと分かりづらいが、凝集性とは平たく言えば「まとまり度合い」のことを指す。例えば、今回問題にされているレイヤーアーキテクチャ一般について考えてみると、レイヤーアーキテクチャとは、アプリケーションの構造の中での役割分担を見出して、それらを疎結合となるように分割したものだと言える。分割されたそれぞれの層は単一の役割を引き受けており、その意味では全体としては凝集性が高くなる、つまりまとまりのある構造になっているはずである。
実は上のような凝集性を、分類的には「論理的凝集(Logical Cohesion)」と呼ぶ。論理的凝集とは、プログラムの構造、あるいは技術的な特徴によってまとまりを作ることであり、論理的凝集の尺度で言えば、レイヤーアーキテクチャの凝集性は高いことになる。
そのように考えると、DHH氏の言う凝集性は論理的凝集ではなく「機能的凝集(Functional Cohesion)」のことを指しているのだと思われる。この論理的凝集と機能的凝集の違いをクリアに説明している素晴らしいコメントが StackExchange にある。
- code quality – What is logical cohesion, and why is it bad or undesirable? – Programmers Stack Exchange
論理的凝集は機能的な特徴よりも技術的な特徴でグルーピングを行うという意味であまり望ましくないと言える。… 例えば、データアクセスを行うモジュールをグルーピングすれば、それは論理的凝集を実現したことになる。… しかし、実際にモジュールの境界を決めるのは技術ドメインではなくビジネスドメインなので、論理的凝集はここで問題となる。論理的凝集を実現することによって、結果的に機能的凝集を失う事になる。
機能的凝集はビジネスドメインの概念によって決まるので、先ほどのレイヤーアーキテクチャの例で言えば、レイヤーを分割する事によって、ビジネスドメイン上の一つのコンセプトが複数のレイヤーの間に引き裂かれて分散してしまうことになる。
一つのビジネスオブジェクト上の変更が複数のレイヤーにまたがって影響を及ぼすというケースは、フレームワーク上で開発する多くの人が経験しているのではないだろうか。
Cohesion と Coherence
凝集性は、英語では「cohesion」と呼ばれている。この言葉には以前から違和感を感じていたのだが、cohesion はライティングにおいて「文と文との繋がり具合」を指す言葉である。これは単に文の論理的なつながり、つまり構造的なまとまり表すだけで、意味のまとまりを表すのには別に「coherence」という言葉がある。どちらも「まとまる」という意味の「cohere」から来ているようであるが、それぞれ「構造的なまとまり」と「意味的なまとまり」で指す意味が微妙に違う。
ソフトウェアデザインにおける cohesion も、あくまで構造的なまとまり、つまり論理的凝集を指す言葉とし、機能的凝集については coherence という言葉を当てた方が良いのではないだろうか。というのは、上の話を鑑みても、この二つを言葉(コンセプト)としてはっきりと区別しておくことが重要であるように思われるからである。
- IEEE Xplore Abstract – Coherence equals cohesion-or does it?
- IEEE Xplore Abstract – Cohesion is structural, coherence is functional: different views, different measures