C#におけるDRYの原則:なぜコードの重複がコードベースを傷つけるのか - デレク・コマーティンによる解説
C#で保守可能なコードを書くことについて話すとき、しばしば浮上する基本的な概念の1つがDRY原則です。 これは、冗長性を排除し、コードの重複を減らし、コードの保守性を向上させることを目的としたソフトウェア開発の柱です。
しかし、多くの設計原則がそうであるように、DRYも誤解され、誤用されることがあります。 DRY principle is why your codebase sucks?" というビデオでは、CodeOpinion.com の Derek Comartin 氏が、DRY 原則をどのように使用すべきか、また使用すべきでないか、特に .NET Core や同様のエコシステムで開発する場合について、率直かつ実用的な見解を示しています。
この記事では、デレクの説明を深く掘り下げ、彼の例とビデオからの解説を紹介します。 Visual Studioで新しいプロジェクトを始める場合でも、既存のコードベースを保守する場合でも、コードの再利用性を高めるためにリファクタリングを行う場合でも、デレクの洞察は実用的で適切です。
DRY原則の定義
ビデオの冒頭でデレクは、多くの開発者が直面している、コードの繰り返しや冗長なロジックのもつれといった、修正が難しいシステムへの対処という背景を説明します。
コードの繰り返しを減らす戦略としてC#のDRY原則を紹介しているが、誤解されることが多いと警告している。 デレクが0:28で説明しているように:
DRYがうまく適用されると、システムの任意の1つの要素に変更を加えても、論理的に無関係な要素に変更を加える必要がなくなります。
この違いは非常に重要です。 DRYの原則は、コードの重複を避けるだけでなく、懸念事項の分離と適切なコードの再利用を促進することを目的としています。
実例:距離の変換
物事を具体的にするために、デレクはC#で簡単な例を提供しています。 彼は2つの方法を書いています:
シップディスタンス
- トールディスタンス
それぞれマイル単位で距離を計算し、次にそれをキロメートルに変換します。 これは古典的なコードの複製です。
Derekは、複数の場所に同じコードの一部を持つ代わりに、変換ロジックをプライベートメソッド - MilesToKilometers()-に抽出する方法を示しています。
彼は、典型的なコンソールアプリの構造を用いてこれを説明している。 public int age、string username、string passwordなどのロジックをテストしたり、新しいユーザー入力シナリオを実験したりするときに、多くの開発者が使用するような構造です。
DRY vs. オーバーカップリング
ロジックを再利用可能なメソッドや別のクラスに抽象化することは理想的に聞こえるが、デレクは注意を促している。 特にアプリケーション全体でDRYを使いすぎると、危険なレベルのカップリングにつながる可能性があります。
例えば、複数のプロジェクトで使用される共有ユーティリティに変換ロジックを配置し、後でその丸め動作や小数精度を変更した場合、その変更は予期せず多くの分野に影響を与える可能性があります。 デレクは2:31でこう言っている:
クライアントは小数点以下2桁を期待していますか? ゼロに変えたらどうなりますか?
これは、システムの多くの部分で再利用されるロジックという横断的な問題であり、早期集中化や明確な境界線のない集中化のリスクを示しています。
ここでのデレクのアドバイスは、単一責任の原則と依存関係の逆転の原則、つまりコードの適応性とモジュール性を維持するために重要な2つのSOLIDの原則と呼応している。
間違った DRY によるコードの肥大化
DRYの誤用によるもう1つの問題は、コードの肥大化です。すべてを抽象化しようとすると、肥大化したユーティリティクラスや過度に汎用的なメソッドが生まれます。 Derekは、ロジックを過剰に乾燥させると、特に大規模なシステムでは、ある領域のバグ修正が依存関係を共有するために他の領域を壊してしまう可能性があり、役に立つどころか害をもたらす可能性があると警告しています。
デレクによれば、重要なのは、コードを共有しないタイミングを知ることであり、特にそれが緊密に結合したモジュールになる場合である。 DRYはルールではありません; これはガイドラインであり、文脈に合わせて使用する必要があります。
DRY をエンティティに適用:複雑さのレシピ
デレクは、開発者にありがちな傾向として、トラック、注文、ドライバー、出荷といったエンティティを中心にシステムを構成することを挙げています。 異なるメソッド間で同じクラスやオブジェクトを再利用することは魅力的ですが、これはしばしば概念の繰り返しや不要なカップリングにつながります。
彼は、データ構造だけでなく、ビジネス機能がアーキテクチャの原動力になるべきだと主張している。 例えば、"注文を発送する"ことと"トレーラーのフックを外す"ことは、たとえ同じエンティティであっても、異なる問題です。
4:45、デレクはこう説明する:
システム内の単一のエンティティが複数の概念を表す必要はありません。
同じ名前のエンティティ(Vehicle、Trailer)は、異なるワークフローにおいて異なる責任を表す可能性があります。 これらのツールを互換的に使用すると混乱が生じ、無関係なビジネスロジックが緊密に結合されます。
DRYとビジネス機能
これを解決するために、デレクは垂直スライス・アーキテクチャ(Vertical Slice Architecture:VSA)、つまりレイヤーの代わりにビジネス機能を中心にアプリケーションを構成するパターンを紹介しています。 それぞれの "スライス "には、リクエストからデータベースまで、特定のアクションやユースケースに必要なすべてがカプセル化され、自己完結しています。
彼は、DRYコードはスライス内、つまり1つの場所内では良いが、スライス間でDRYを適用すると依存関係がもつれる可能性があることを強調している。 6:44で、彼はこう付け加えた:
結合を減らし、結束を高めることです。 そのための1つの方法は、"境界内で概念を繰り返さないこと "です。
このような境界を重視した考え方により、柔軟性が生まれます。 あるスライスには完全なドメインモデルがあり、別のスライスには軽量のデータモデルがあるだけかもしれません。 The Pragmatic Programmerの哲学に沿った実用的なアプローチです。
最終的な考え
デレクは、DRYを法律ではなく、ツールとしてとらえ直すことで締めくくります。 7:00にこう言っている:
どのように適用するかを理解することです。 それを多用する場合は、より多くのカップリングを持つ可能性があります。"
そのため、検証ロジックや接続文字列を抽出したり、反復的なコードを別のメソッドに変換したりする前に、そうすることでコードベース全体が実際に保守しやすくなるのか、それとも単に変更しにくくなるだけなのかを検討してください。
結論
Derek Comartin氏によるC#におけるDRY原則の内訳は、一見単純なルールがニュアンスなしに適用されると、いかに逆効果になるかを示しています。 コード例を見ながら、実践的なシナリオを議論し、ソフトウェア設計の原則を強調することで、再利用性とモジュール性の間に必要なバランスを明らかにする。
開発プロセスを大幅に強化するために、覚えておいてください:
DRYを使用して、明確な境界内で冗長なコードをリファクタリングします。
ビジネス上の目的が異なるエンティティをDRY化しないこと。
ロジックを一元化する場合は、特に複数の場所やプロジェクトにまたがる場合は、文脈を尊重してください。
- ユニットテストと、依存性注入が共有コードにどのように影響するかを考慮してください。
これらのレッスンを適用することで、より効率的でモジュール化された保守性の高いC#コードを書くことができ、コードベースが重複ロジックや依存関係のもつれたネズミの巣になるのを防ぐことができます。
デレク・マーティン氏の詳細については、ビデオをCodeOpinionのYouTubeチャンネルでご覧ください。

