2013.01.10
「DRY」はつねに正しいわけではない 重複と密結合のトレードオフ
ウィキペディア - Don't repeat yourself
http://ja.wikipedia.org/wiki/Don%27t_repeat_yourself

<Don't repeat yourself (DRY) あるいは Single Source of truth(英)は、特にコンピューティングの領域で、重複を防ぐ考え方である。この哲学は、情報の重複は変更の困難さを増大し透明性を減少させ、不一致を生じる可能性につながるため、重複するべきでないことを強調する>。

<DRY は、Andy Hunt と Dave Thomas の著書 The Pragmatic Programmer (邦題:達人プログラマー) において中心となる原則である。 彼らはこの原則を、データベーススキーマ、テスト計画、ビルドシステムや、ドキュメンテーションにいたるまで非常に幅広く適用している>。

この「DRY」原則、「Don't repeat yourself (同じことを繰り返すな)」は、プログラマのあいだでわりと知られている。

「DRY」という言い方を知らなくても、プログラミングでは「同じことを繰り返さない」こと、「重複」をできるだけ排除すべきことは、常識である。ベックの『実装パターン』でも、「繰返しの最小化」は2番目の原則になっていた。

しかし、「DRY」はつねに正しいわけではない。「重複」を徹底的に排除することには、デメリットもある。上のウィキペディアのページからリンクされている以下の記事は、この「DRY」のデメリットについて、よく説明している。

InfoQ - DRY原則の利用: コードの重複と密結合の間(2012年5月31日)
http://www.infoq.com/jp/news/2012/05/DRY-code-duplication-coupling

<DRYは重複とそれに伴うメンテナンスの問題を軽減するものだが、誤用すると密結合を生み、可読性を損うおそれがある。教訓:ソフトウェア開発原則は、ほかの原則やパターン、プラクティスを考慮して適用しなくてはならない>。

記事中に、Greg Young氏によるこういう発言がある。

<DRYにしたがうことに対する基本的な議論は、ものごとには別の側面があるということです。"DRY"にしたがうことで、ソフトウェアに結合や複雑さをもたらすのは珍しいことではありません。トレードオフの一方は非常に測定しやすいですが(複数の場所にあるバグを修正しなくてはならないときの時間当たりの面々の数)、もう一方はかなり困難です(DRYの名のもとにソフトウエアにもたらされた結合や複雑さ)>。

「DRY」にしたがって重複を排除していくと、ソフトウェアの部分どうしに結合が生じて、複雑さが増す、ということがよくある。重複は測定しやすく、わかりやすいが、結合度や複雑さは測定しにくく、わかりにくい、という指摘だ。その通りだろう。

また記事中には、David Chelimsky氏(RSpecの作者でありリードデベロッパ)による、こういう発言がある。

<同じオブジェクトにある2つのメソッドがある同じ仕事をしているとき、私たちはそれら2つのメソッドが委譲する第三のメソッドを抽出します。もとの2つのメソッドはいずれも抽出されたメソッドに結合しており、間接的ですがお互い結合しています。これは単一オブジェクトのコンテキストにおいては、まったく論理的であって危険はないように見えます。しかし、2つのオブジェクトを横断した同様の振舞いを考えるとどうでしょう?重複をなくすため、私たちはそれらが依存する新しいオブジェクトを導入することになるか、よくあることですが、さらにひどくて悲惨なことに、あるオブジェクトをほかのオブジェクトに依存させます。後者のアプローチでは、関係のないオブジェクト間に依存関係を作ってしまうことが多く、やがて進化の妨げになります。新しいオブジェクトを導入すると、システム全体の界面が増えてしまい、導入時やリファクタリング時に余計な検討や配慮を必要とします>。

やや専門的な記述だが、大雑把に言えば、「重複を排除しようとした結果、ソフトウェアの部分どうしに依存関係ができてしまって、それがソフトウェアの進化をさまたげる」といった話である。言っていることは、上のGreg Young氏の指摘とほぼ同じだ。

記事の最後には、このようにある。

<DRYは重要な原則だが、それを誤用すると、密結合を増やし、読みやすさを損うといった問題を引き起こすおそれがある。ここでの教訓は、いくら原則がすばらしいからといって、ほかのすぐれたプログラミングプラクティスを軽視してはいけないということだ>。

DRYは重要な原則だが、あくまでも原則に過ぎず、絶対的真理ではないわけだ。DRYは重複をなくすが、それはしばしば密結合を生み出して、システムを硬直させてしまう。

また、極端に冗長性を排したコードは、読みにくく、わかりにくいものになることがある(上の記事には、Rubyのコードによる具体例がある)。人間が読んでわかりにくいコードは、メンテナンスを困難にし、変更のコストも増え、バグも入りやすくなる。DRYによって「わかりやすさ」が失われる場合は、DRYよりも「わかりやすさ」のほうを重視すべきだろう。


関連エントリ:
ケント・ベック『実装パターン』(2008年) 実装パターンの6つの原則
http://mojix.org/2012/11/21/beck-impl-pattern
最適化と柔軟性のバランス
http://mojix.org/2012/10/26/saiteki-juunan