DRY(don't repeat yourself)するかしないか、その判断基準について

「過剰なDRYが技術的負債を生む」みたいな内容の記事を書きたいが、うまく言語化できない。「過剰な食事制限が健康を損なう」程度の内容に成り下がりそうだけど、そんなんじゃないんだよ…
@methane 実装におけるDRYみたいなものを考えていて、そうすると前者のDRYというのがどこに位置づけられるかはわからないんですが、とにかく暗黙知みたいなものを過剰に増やすDRYは良くないよね、というような話なんです

という@moriyoshitさんのツイート(1, 2)を見かけたので、僕の考え方をコメント。moriyoshitさんの考えたい問題とは、ずれてるかも。


DRY化の功罪とは何か?

僕の理解で言うと、共通するコード片をDRY化することには以下の変化をもたらす。

  • 循環的複雑度は変化しない
  • コールグラフは複雑化する
    • モジュールをまたぐDRY化を行うと、モジュール間の依存関係も複雑化する*1
  • 関数内の複雑度は低下する

過剰なDRY化が行われる背景としては、第2点の議論が見落とされがちなんじゃないか、と思ってる。


ではどうすべきか?

上記の3点より、

  • 関数内の複雑度の低下によるメリットが、コールグラフの複雑度の上昇によるデメリットを上回る場合のみ、DRY化を行う
  • モジュール間の複雑性上昇を抑えるため、DRY化はできるだけ局所的に行う*2

を基本的な指針にしています。

*1:もしくはより結合度が高まる

*2:つまり、まずは関数内での子関数定義であったり、モジュール内に閉じた関数としてDRY化を実装することを考える