DRY を守って開発をするとはどういうことなのか?
DRY を守って開発をするとはどういうことなのか?
DRY (Don't Repeat Yourself) という開発原則があります。いい DRY と悪い DRY があるとかなんとか。DRY を改めて調べて、DRY を守るということが何なのかをまとめます。
DRY そのものは達人プログラマーが原点だそうで、そこから引用します。
なお、参考にしたのは第二版の方です。
まずは ETC
DRY は「第二章 達人のアプローチ」のなかで紹介されています。
その章の始めの方で、「よい設計の本質」について解説しています。
Tip 14
よい設計は悪い設計よりも変更しやすい
これを書籍では ETC (Easier To Change) 原則と呼んでいます。
私見ですが、「変更しやすい」はこういうことだと思ってます。
- 変更に対し、コードの修正箇所を特定しやすい
- 変更に対し、コードの修正が散在しない
- 変更に対し、その修正の影響範囲が特定しやすい
- 変更に対し、その修正の影響範囲が局所化している
DRY がうまくいっていると、「コードの修正が散在しない」ので変更がやりやすくなります。ですが、DRY だけでは ETC は守れません。
「第二章 達人のアプローチ」はこの ETC にかかわる原則を DRY だけでなくいくつか解説しています。
また、常にこの ETC を意識するよう説いています。
しかし、そういう状態にするにはどうすればいいのでしょうか?我々の経験では、最初にある程度の意識改革が必要になります。1週間かそこら、自分自身に「私が実行したものごとで、システムは変更しやすくなったのか、それとも変更しにくくなったのか?」ということを意識的に自問する必要があるでしょう。ファイルを保存した時にこれを実行してください。テストを記述している時にこれを実行してください。バグを修正している時にこれを実行してください。
密接に関係のある直行性
「第二章 達人のアプローチ」の冒頭で DRY と直行性は密接に関連しあっていると書かれています。
次の2つのセクション、「9 DRY原則 ― 二重化の過ち」と「10 直交性」は密接に関連し合っています。最初のセクションではまずシステム全体を通して知識を二重化すること、また次のセクションでは1つの知識を複数のシステムコンポーネントに分割することに対する警鐘を鳴らしています。
直行性の説明の中でも DRY と密接に関係していると改めて解説されています。(大事なことなので二度言ったのでしょうか?)
直行性の解説の中で次のように書かれています。
Tip 17
関係のないもの同士の影響を排除すること
自己完結したコンポーネント、つまり独立し、単機能の、目的にうまく適合したコンポーネント(YourdonとConstantineが『Structured Design』YC79で「凝集度」(cohesion)の高いコンポーネントと呼んでいるもの))を設計するべきです。
直行性を達成するためには凝集度が大事だということです。(もちろん、凝集度だけが大事ってわけじゃないです)
そして結論へ
達人プログラマーでは、変更を容易にする (ETC) ために DRY などの原則があると解説しています。さらに、DRY と直行性は密接に関係しているとも述べています。
DRY を守るということはこういうことではないでしょうか?
- ETC が達成されたかを考え続ける
- DRY と同時に直行性も気にする
ですので、DRY だけに着目して、あーだこーだ言うのは、実は DRY は守れていないのではないでしょうか?
いわゆる悪い DRY
いわゆる悪い DRY (DRY 以外を気にしない) をオンラインショップの決済を例にして解説します。
以前は決済といっても主に銀行振り込み・代引き・クレジットカードでした。今はなんちゃらペイが乱立しまくっています。そのたびにシステムを変更する必要があります。
オンラインショップの決済ページのコントローラーに 10 種類以上の決済についてのコードがべた書きされているとします。新しいなんちゃらペイを導入する場合、このコントローラーを修正することになります。修正するだけでなく、テストも必要です。
このコントローラーはすべての決済についての知識を持っていますので、テストは新しく導入したものだけでなく、もともと対応していた決済についてのテストも必要です。また、テストは正常系だけでなく、異常系も必要です。もう嫌になりませんか?
このコントローラー以外には決済の知識はありませんので、同じような修正を何度も繰り返す必要はありません。そういう意味では DRY だけなら守れています。しかし、そのあとのテスト量を考えると、ETC を守れているとはとてもいいがたいです。
一つのシステムコンポーネントに様々な決済の知識を押し込めている状態は、直行性がなく、凝集度が下がっている状態です。ETC を達成するためには、それぞれの決済ごとにシステムコンポーネントを分割する必要があります。
新しいなんちゃらペイの導入では、新しいそれ専用のシステムコンポーネントを追加します。もともとの決済のシステムコンポーネントは一切修正されませんので、そこにバグが新たに生まれる可能性は低くなります。
影響範囲が分かりやすく、テストを局所化できるので、ETC が達成できています。
反省
最近の私は DRY はほとんど気にしていません。結合度や凝集度などを気にしながらプログラム設計をすれば DRY は達成されていることが多いので気にしなくてよいというスタンスです。
でも、過去には DRY がー! って騒いで ETC が達成できないひどいコードを何度も書きました。
ここから来る反省は...
- 原則の定義を拾い読みして分かった気にならない
- それだけがすべてだと考えず、何が目的なのかをより注意する
ということになります。書籍などの資料でちゃんと調べて、誤解をなるべくへらし、ルールよりも目的の方を意識するようにしたいですね。
身に覚えがある方は、ぜひ達人プログラマー 第二版を読んでください! 解決のためのヒントがたくさんあります。
Discussion