web-dev-qa-db-ja.com

重複するコードを受け入れることができる例外的なケースはありますか?

3つのAPIを構築する必要があるソフトウェアプロジェクトに取り組んでいます。 1つはhomeバンキングチャネル用、もう1つはagencyチャネル用、およびmobileチャネルの3番目。

エージェンシーAPIは、すべての機能を備えているため、最も完全なものです。次に、少し小さいHome API、次にモバイルAPIです。

ここのアーキテクトは共通のレイヤー(すべてのAPIで共有されるクロスチャネルEJBサービス)を作成しました。ただし、APIは異なります。

今のところ、API間に大きな違いはありません。大きなチームはエージェンシーチャネルから始まり、現在はホームチャネルに適合させています。私たちは、特にホームアプリにオブジェクトを追加しています。それ以外の場合、コードはAPI間で95%似ています。 APIは Spring MVC の上に構築されており、(コントローラー、モデル、一部のユーティリティ)を備えています。

基本的に、コントローラーはBOとChannelObjectのマッピング(適切な場所ではないようです)、およびいくつかの追加のユーティリティとシリアライザーを実行しています。現時点ではすべてが重複しています。重複の理由は、APIを独立させたいということです。 「もし明日、代理店やモバイルとは異なる行動を家庭で望むなら、私たちは苦労しません!!」

重複するコードを受け入れる必要がある場合はありますか?

57

重複は正しいことである可能性がありますが、この理由のためではありません。

「コードベース内のこれら3つの場所が現在同じでも同じように動作するようにしたい」と言っても、大規模な複製の理由にはなりません。この概念はeveryシステムに適用でき、anyの重複を正当化するために使用できますが、これは明らかに合理的ではありません。

複製は、他の理由で削除すると全体的にコストがかかる場合にのみ許容する必要があります(現在、適切なものとは考えられませんが、存在する可能性があるため、プログラミングにおける事実上すべてが法律というよりはトレードオフです。

あなたがやっていることのために、適切な解決策は例えばかもしれません。現時点で複製されている動作を戦略または動作をクラスとしてモデル化するその他のパタ​​ーンに抽出し、同じクラスの3つのインスタンスを使用します。このようにして、doが3つの場所のいずれかで動作を変更したい場合、新しい戦略を作成して1つの場所でインスタンス化するだけで済みます。そうすれば、いくつかのクラスを追加するだけで、残りのコードベースはほとんど完全に変更する必要がありません。

70
Kilian Foth

Rubyエコシステムの著名なソフトウェアエンジニアであり作家でもあるSandi Metzは、素晴らしい ブログ投稿talk があり、彼女はこのことについて語っています。複製と抽象化の関係彼女は次の結論に達しました

複製は間違った抽象化よりはるかに安価です

そして私は完全に彼女に同意します。この引用について、もう少し詳しく説明しましょう。正しい抽象化を見つけるのが非常に難しい場合があります。このような場合、重複を減らすために、any抽象化を使用するのは魅力的です。しかし、後で、抽象化がすべてのケースに当てはまるわけではないことに気付くかもしれません。ただし、すべてを再度変更して別のルートに進むにはコストがかかります(はるかに優れた説明については、彼女の講演をご覧ください!)。

ですから、私にとっては、特に何が起こるか確信が持てず、要件が変わる可能性が高い場合に、複製を受け入れることが正しい決定である例外的なケースがあります。あなたの投稿から、私は現在多くの重複があると思いますが、あなたの同僚は、これは変更される可能性があり、両方のアプリケーションを互いに結合しないようにすることを提案します。私の意見では、これは有効な議論であり、一般的に無視することはできません。

87
larsbe

人々が"if tomorrow"という言葉でデザインについて推論を始める場合、これは特に私にとって大きな警告サインです。特に、議論が追加の作業と労力を含む決定を正当化するために使用される場合、これが報われるかどうかは誰にもわかりません。これは、反対の決定よりも変更や復帰が困難です。

コードを複製すると、短期間だけ労力が削減されますが、コードの複製された行数に比例して、保守の労力がほぼ即座に増加します。また、コードが複製されると、これが間違った決定であることが判明した場合、複製を削除することが難しくなります。一方、コードを複製しない場合でも、=に固執していることが判明した場合は、後で複製を導入することは簡単です。 DRYは間違った決定でした。

大規模な組織では、DRYの原則よりも異なるチームの独立性を優先するほうが有利な場合があります。APIの95%の共通部分を抽出して重複を削除すると、2つの新しいコンポーネントが独立した2つのチームのカップリングでは、これは最も賢明な決定ではない可能性があります。一方、リソースが限られていて、両方のAPIを維持しているチームが1つだけの場合は、自分の利益にならないと確信しています。二重の労力をかけ、不要なコードの重複を避けます。

さらに、「ホーム」と「代理店」のAPIが完全に異なるアプリケーションで排他的に使用されている場合、または「ホーム」コンテキストでも使用できるこれらのAPIの上にコンポーネントビルドを作成しようとすると、違いが生じることに注意してください。 「代理店」の場合と同様です。この状況では、APIの共通部分を完全に同一にすると(共通部分が重複していない場合にのみ保証できます)、そのようなコンポーネントの開発がおそらくはるかに容易になります。

したがって、本当に異なるサブチームがあり、それぞれが各APIを担当し、それぞれが異なるスケジュールとリソースを使用していることが判明した場合は、コードを複製しますが、「念のため」ではありません。

34
Doc Brown

カップリングを防止するための複製。 2つの大きなシステムがあり、それらに同じライブラリを使用するように強制するとします。両方のシステムのリリースサイクルを結合している可能性があります。これは悪くないかもしれませんが、1つのシステムが変更を導入する必要があるとしましょう。他は変更を分析する必要があり、影響を受ける可能性があります。時々それは物事を壊すかもしれません。両方の当事者が変更を調整できたとしても、マネージャー、テスト、依存関係、小規模な自律チームの終焉など、多くの会議になる可能性があります。

つまり、自律性と独立性を得るために、複製されたコードの代償を払っています。

13
Borjab