DRY vsコードカップリングについてのガイダンスを探しています。コードを複製するのは好きではありません。また、無関係なモジュール間のコードカップリングも好きではありません。そのため、同じものが見つかったら、重複するコードをリファクタリングします。複製が導入されてから1年後にコードが重複しますが、現実世界がはるかに予測不可能である状況をますます経験し、コードをリファクタリングした後、コードを再度フォークする必要がある状況が発生します。
たとえば、ガソリン車、ガソリンSUV、電気自動車、電気SUVを処理するコードがある場合、重複するコードを「ガソリン」階層と「電気」階層にリファクタリングし、どちらも「車両」階層から降りるとします。ここまでは順調ですね。それから、私の会社はハイブリッドカーとハイブリッドセミを導入します-それは私の元の階層自体へのコア変更を必要とするでしょう。多分それはガソリンと電気階層の間の「構成」を必要とするでしょう。
上記のすべての製品に共通する変更の実装にかかる時間が長くなるため、コードの重複は明らかに悪いものです。しかし、共通コードをリファクタリングすると、製品固有のバリエーションを導入するのが同様に難しくなり、バグを修正するためにコード行を見つける必要がある場合、多くの「クラスジャンプ」が発生します。上位レベルの親クラスで1つの変更を行うと、すべての子孫でトリガートリガーの回帰バグ。
DRYと不要なコードのカップリングの最適なバランスをとるにはどうすればよいですか?
重複したコードを「ガソリン」階層と「電気」階層にリファクタリングしたとします。どちらも「車両」階層から降りています。ここまでは順調ですね。
それから、私の会社はハイブリッドカーとハイブリッドセミを導入します-それは私の元の階層自体にコア変更を必要とするでしょう。多分それはガソリンと電気階層の間の「構成」を必要とするでしょう
これが、継承よりも構成に移行する主な理由の1つだと思います。
継承によって、説明したような概念の変更がある場合、大規模な再構築が必要になります。
再構築が「大きすぎる/難しい」場合、人々はそれを避けるために重複したコードを書きます。
コードを継承チェーンの上に移動して複製をリモート化するのではなく、コードをヘルパークラスまたはサービスに移動し、必要に応じてそのクラスをコンポジションの一部として挿入できます。
結果のデザインがOOP=であるかどうかは、議論の余地があります
あなたが正しい、DRY原則に従うと、他の無関係なモジュール間のカップリングが増加する可能性があります。特に、より大きなソフトウェアシステムでは、これはDRYに従わない状況につながる可能性がありますより良い代替品になることができます。
残念ながら、あなたの例はこれを実証するにはあまり適していません-ここで説明されている問題は、 違う 継承の次善の使用法。ただし、上記で説明した内容では、共通コードを共通基本クラスにリファクタリングするか、ヘルパークラス(構成)にリファクタリングするかは問題ではありません。どちらの場合も、共通のコードをライブラリLに入れて、以前は関係のなかった2つのプログラムAとBからそのライブラリを参照することを強いられる可能性があります。
AとBは以前はまったく関係がなかったと仮定します。これらは個別にバージョン管理、リリース、および展開できます。ただし、共有コードLに共通コードを挿入すると、Aの新しい要件によってLが変更され、Bが変更される可能性があります。そのため、追加のテストが必要になり、おそらくBの新しいリリースとデプロイサイクルが必要になります。
DRYの原則を放棄するつもりがない場合、どうすればこの状況に対処できますか?さて、これに取り組むためのいくつかのよく知られた戦術があります:
A、B、Lを同じ製品の一部として保持し、高度な自動化を備えた1つの共通バージョン番号、共通のビルド、リリース、およびデプロイプロセスを使用する
または、マイナーバージョン番号(互換性のない変更なし)とメジャーバージョン番号(互換性のない変更が含まれている可能性があります)を備えたLを単独で製品にして、AとBがそれぞれにLの異なるバージョン行を参照できるようにします。
LをSOLIDにして、下位互換性に注意してください。Lのモジュールを変更せずに再利用できるほど(OCP)、破壊的な変更が発生する可能性が低くなります。また、「 SOLID」は、その目標のサポートを支援しています。
特にLだけでなく、AとBにも自動テストを使用します。
Lに入力する内容に注意してください。システム内の1つの場所にのみ存在する必要があるビジネスロジックは、良い候補です。単に「似ている」だけで、将来的に異なる可能性があるものは、悪い候補です。
AとBが異なる無関係なチームによって開発、保守、および進化する場合、DRYの原則はそれほど重要ではなくなります-DRYは保守性と発展性についてですが、しかし、2つの異なるチームが個別のメンテナンス作業を提供できるようにすると、少し再利用できるため、製品を結合するよりも効果的な場合があります。
結局、それはトレードオフです。大規模なシステムでDRYの原則に従う場合は、堅牢で再利用可能なコンポーネントを作成するために、通常は予想以上に多くの労力を費やす必要があります。判断が信頼できる場合は、それだけの価値があります。
DRYはさらにもう1つの構造的ルールです。それはあなたがそれを極端にすると、それを無視するのと同じくらい悪いことを意味します。ここに、構造的な考え方から抜け出すためのメタファーがあります。
双子が大好きです。クローンを殺します。
キーボード入力を避けるためにやみくもにコピーアンドペーストすると、無意識にクローンが作成されます。確かに彼らはあなたが望むことをしますが、今その行動を変えることはとても高価なので、彼らはあなたを圧迫します。
異なる責任のために同じコードで同じ動作を再現すると、今では同じ必要性がありますが、異なる変更が適用される可能性があります。
DNA(コード)を好きなだけスキャンできます。クローンとツインは、それらを見るだけで見分けがつきません。あなたが必要なのは、彼らが住んでいるコンテキストを理解することです。なぜ彼らが生まれたのか。彼らの究極の運命は何である可能性が高いでしょうか。
ABC社で働いているとします。 A、B、Cの3人の企業幹部が運営しています。彼ら全員がソフトウェア製品を作ってほしいと思っていますが、それぞれに独自の部門があります。彼らは皆、あなたに小さなことから始めて欲しいと思っています。とりあえず簡単なメッセージを出力してください。 「Hello World」と書いてください。
それを嫌い、そこに会社名を入れてほしい。
Bはそれを気に入っており、そのままにして会社名をスプラッシュ画面に追加してほしいと思っています。
Cは計算機を欲しがっており、メッセージはあなたが始めるための単なる方法であると考えました。
あなたが確信していることの1つは、これらの人たちはこのプロジェクトが何であるかについて非常に異なる考えを持っていることです。時々彼らは同意するでしょう。時には彼らはあなたを別の方向に引き寄せようとしています。
そのコードが独立して変化する機能を作成しているためにコードを複製すると、ツインが作成されます。タイピングが面倒でコピーアンドペーストが簡単なため、コードを複製すると、邪悪なクローンが作成されます。
A、B、およびCは、コードが提供する必要のある異なるマスターです。 1行のコードで複数のマスターに長く対応することはできません。