[〜#〜] solid [〜#〜] オブジェクト指向設計の原則を守らないと私がよく耳にする議論の1つは [〜#〜] yagni [〜 #〜] (arguerはそれをしばしばそれとは呼びませんが):
「機能Xと機能Yの両方を同じクラスに入れても問題ありません。新しいクラス(つまり複雑さ)を追加する必要があるのはとても簡単です。」
「はい、すべてのビジネスロジックを直接GUIコードに直接入れることができるので、はるかに簡単で迅速です。これが常に唯一のGUIであり、重要な新しい要件が発生する可能性はほとんどありません。インチ」
「万が一新しい要件が発生した場合でも、コードが乱雑になりすぎた場合でも、新しい要件に合わせてリファクタリングできます。したがって、「後で必要になった場合...」の引数は考慮されません。」
そのような実践に対して最も説得力のある議論は何でしょうか?これは、特にソフトウェア開発の経験があまりない人にとって、これが費用のかかる習慣であることを本当に表示するにはどうすればよいですか。
デザインはトレードオフの管理とバランスです。YAGNIとSOLIDは矛盾しません:前者はいつ機能を追加するか、後者は方法、と言いますが、どちらも設計プロセスをガイドします。特定の引用は、YAGNIとSOLIDの両方の原則を使用しています。
- 再利用可能なコンポーネントの構築は、使い捨てコンポーネントの3倍の困難です。
- 再利用可能なコンポーネントは、再利用ライブラリに受け入れるのに十分一般的なものになる前に、3つの異なるアプリケーションで試してみる必要があります。
— Robert Glass ' Rules of Three 、ソフトウェアエンジニアリングの事実と誤り
再利用可能なコンポーネントへのリファクタリングには、最初に複数の場所で同じ目的を見つけ、、次にそれを移動するという重要な要素があります。このコンテキストでは、YAGNIは、汎用または再利用可能な機能(クラスおよび関数)を追加するのではなく、重複の可能性を心配することなく、必要に応じて目的をインライン化することによって適用されます。
最初の設計で、YAGNIが適用されない場合を示す最善の方法は、具体的な要件を特定することです。言い換えれば、コードを書く前に何らかのリファクタリングを実行して、複製が可能であるだけでなく、すでに存在していることを示します。これは追加の労力を正当化します。
はい、すべてのビジネスロジックをGUIコードに直接配置できるので、はるかに簡単で迅速です。これは常に唯一のGUIであり、重要な新しい要件が発生する可能性はほとんどありません。
それは本当に唯一のユーザーインターフェースですか?バックグラウンドバッチモードは計画されていますか? Webインターフェースはありますか?
テスト計画は何ですか?GUIなしでバックエンド機能をテストしますか? GUIをテストしやすいものにする理由は、通常、外部のコード(プラットフォームジェネリックGUIコントロールなど)をテストするのではなく、プロジェクトに集中するためです。
機能Xと機能Yの両方を同じクラスに入れても問題ありません。新しいクラス(つまり、複雑さ)を追加する必要がないのは非常に簡単です。
回避する必要がある一般的な間違いを指摘できますか?非常に単純な例として数値(_x * x
_対squared(x)
)を二乗するなど、いくつかのことは非常に単純ですが、誰かが犯した具体的な間違い、特にプロジェクトやチームのメンバーは、共通のクラスまたは関数が将来どのようにそれを回避するかを示すことができます。
新しい要件がありそうもないケースで、コードが乱雑になりすぎた場合でも、新しい要件に合わせてリファクタリングできます。そのため、「後で必要になった場合...」の引数は考慮されません。
ここでの問題は、「可能性が低い」という仮定です。それがありそうもないことに同意しますか?もしそうなら、あなたはこの人に同意しています。そうでない場合、デザインのアイデアはこの人の考えと一致しません。この不一致を解決すると問題が解決するか、少なくとも次にどこに進むべきかが示されます。 :)
レンガの壁で論争しているようですね。私はYAGNIの大ファンですが、同時に、コードがalwaysがアプリケーションとテストの少なくとも2つの場所で使用されることも期待しています。そのため、UIコードのビジネスロジックなどが機能しません。この状況では、UIコードとは別にビジネスロジックをテストすることはできません。
しかし、あなたが説明している回答から、その人はより良い仕事をすることに単に興味がないように思えます。その時点では、彼らを助ける原則はありません。彼らは可能な限り最小限にしたいだけです。私は、YAGNIが彼らの行動を推進しているのではなく、怠惰であるとまで言っています。
37signals( https://gettingreal.37signals.com/ch05_Half_Not_Half_Assed.php )からフレーズを借りるために、私はYAGNIを「半分を意味するのではなく、半分を意味する」という観点から考えたいと思います。最も重要なことをうまく行うことに集中できるように、スコープを制限することです。ずさんな言い訳にはなりません。
GUIのビジネスロジックは、私には戸惑っています。システムがささいなものでない限り、ビジネスロジックとGUIが数回以上独立して変更されていなければ、私は驚くでしょう。したがって、SRP(SOLIDの「S」)に従って、リファクタリングする必要があります。YAGNIは、すでに必要なので適用されません。
YAGNIと不必要な複雑さについての議論は、仮説的な将来の要件に対応するために今日追加の作業を行っている場合に絶対的に当てはまります。これらの「後で必要になった場合...」シナリオが実現しない場合、抽象化によるメンテナンスコストの増大に悩まされ、その結果、実際の変更が妨げられます。この場合、私たちはスコープを制限することによって設計を簡素化することについて話している-片思いでいるのではなく半分を行う。
答えはありません、またはむしろ、あなたもあなたの対話者も好まないかもしれない答えがあります:YAGNIとSOLIDはどちらも間違ったアプローチである可能性があります。
SOLID =経験の浅いチーム、または厳しい配信目標を持つチームと一緒に行こうとすると、かなりの費用がかかり、過度に設計された一連のコードが作成されることになります... SOLID、ただ過剰に設計された(別名、現実世界へようこそ)。
YAGNIに長期間のプロジェクトを行って、後である程度までしか機能しないことを願っています(別名、現実世界へようこそ)。 YAGNIは、概念実証とデモンストレーターに優れており、市場/契約を獲得してから、より確かなものに投資することができます。
異なる時点で両方が必要です。
品質の単体テスト、つまり統合テストではなく単体テストには、SOLIDに準拠したコードが必要です。必ずしも100%とは限りませんが、実際にはそうではありませんが、この例では、2つの機能を1つのクラスに詰め込むと、単体テストが難しくなり、単一責任の原則が破られ、チーム初心者によるコードの保守がはるかに難しくなります(理解するのがはるかに困難になるため)。 。
(適切なコードカバレッジを前提とする)単体テストを使用すると、機能1を安全にリファクタリングして機能2を壊すことはありませんが、単体テストを使用せず、同じクラスの機能を使用できます(例では単に怠惰になります)。リファクタリングは、せいぜい危険であり、せいぜい悲惨です。
SOLIDの原則により、ソフトウェアを変更に適応させることができます。要件と技術的な変更(新しいコンポーネントなど)の両方において、要件の2つは不変の要件に対するものです。
これは本当に本当だろうか?
開発のさまざまな費用に関しては、経験に勝るものはありません。多くの開業医にとって、お粗末で、維持が難しい方法で物事を行うことは、彼らにとって問題を引き起こしたことはありません(ちょっと!仕事のセキュリティ)。製品の長期的に見て、これらの費用は明らかになると思いますが、事前に何かをすることは他の誰かの仕事です。
ここには他にもいくつかの素晴らしい答えがあります。
理解しやすく、柔軟で、修正や改善が可能なのは、常にあなたが必要とするものですある。実際、YAGNIは、必要に応じて新しい機能を比較的簡単に追加できると想定しています。これは、クラスに無関係な機能をバンギングする(そのクラスのYAGNI)か、ビジネスロジックをUIロジックにプッシュするようなものは誰もいないためです。 。
今では狂ったように見えることが過去において合理的であった場合があります-時には、UI対ビジネスの境界線、または異なるクラスにあるべき異なる責任のセット間の境界線がそれほど明確でなく、または移動さえしません。 2時間のうちに3時間の作業が絶対に必要な場合があります。人々が正しい電話をかけないことが時々あります。これらの理由により、この点で時折中断が発生しますが、彼らはYAGNI原則の使用の邪魔になり、その原因ではありません。
これらの原則の正しい適用は、多くの場合、それほど明白ではなく、経験に大きく依存します。自分で行わなかった場合、これは入手が困難です。すべてのプログラマーは、それを間違って行うことの結果の経験を持っているはずですが、もちろん、それは常に「私の」プロジェクトではないはずです。
彼らに何が問題なのかを説明します。彼らが耳を傾けず、あなたが彼らに耳を傾ける立場にない場合は、彼らに間違いを犯させてください。頻繁に問題を修正しなければならない場合は、履歴書を磨いてください。
私の経験では、それは常に判断の呼びかけです。はい、実装の細部すべてについて心配する必要はありません。メソッドを既存のクラスに組み込むことは、醜い解決策ですが、許容できる場合があります。
後でリファクタリングできるのは本当です。重要な点は、実際にはリファクタリングを実行するです。したがって、本当の問題は時折発生する設計の妥協ではなく、問題があることが明らかになったときにリファクタリングを延期することではないと私は信じています。実際にそれを経験することは難しい部分です(人生の多くのものと同じように...)。
個々のポイントについて:
機能Xと機能Yの両方を同じクラスに入れても問題ありません。新しいクラス(つまり、複雑さ)を追加する必要がないのは非常に簡単です。
1つのクラスにすべてを含めることはより複雑であることを指摘します(メソッド間の関係はより親密で、理解が難しいため)。多くの小さなクラスを持つことは複雑ではありません。リストが長くなっていると感じた場合は、パッケージに整理するだけで大丈夫です:-)。個人的には、クラスを2つまたは3つのクラスに分割するだけで、変更を加えなくても読みやすさが大幅に向上することがわかりました。
少人数のクラスを恐れないでください。噛まないようにしてください;-)。
はい、すべてのビジネスロジックをGUIコードに直接配置できるので、はるかに簡単で迅速です。これは常に唯一のGUIであり、重要な新しい要件が発生する可能性はほとんどありません。
誰かが「重要な新しい要件が来ることはほとんどあり得ない」と言うことができるなら。まっすぐな顔で、その人は本当に本当には現実のチェックが必要だと思います。率直に言って、穏やかに...
万が一新しい要件が発生した場合でも、コードが乱雑になりすぎても、新しい要件に合わせてリファクタリングできます。したがって、「後で必要になった場合...」引数はカウントされません
これにはいくつかのメリットがありますが、実際に後でリファクタリングを行う場合に限られます。だからそれを受け入れて、約束を守ってください:-)。
tldr;
SOLIDは、読者が(少なくとも多少は)SRPに関するコードの将来の変更を理解していると想定しています。それは予測する能力について楽観的であると言います。一方、YAGNIは、ほとんどの場合、将来の変化の方向が分からないことを想定しています。これは、予測する能力について悲観的です。
したがって、SOLID/SRPは、変更の単一の理由を持つようにコードのクラスを形成するように要求することになります。例えば。小さなGUIの変更またはServiceCallの変更。
YAGNIは(このシナリオで強制的に適用する場合)、何が変更されるかわからないため、およびGUIの変更によってGUI + ServiceCallが変更される場合(同様に、バックエンドの変更によりGUI + SeviceCallが変更される) 、そのすべてのコードを単一のクラスに配置します。
長い答え:
「アジャイルソフトウェア開発、原則、パターン、および実践」を読む
SOLID/SRPについての短い抜粋を引用します。「アプリケーションが2つの責任を異なるタイミングで変化させるような方法で変化しない場合、それらを分離する必要はありません。実際、それらを分離する必要はありません。不必要な複雑さのにおいがします。
ここには冠詞があります。変更軸は、変更が発生した場合にのみ変更軸になります。症状がない場合は、SRP、またはその他の原則を適用することは賢明ではありません。」