68

オブジェクト指向設計でSOLID原則を順守していないことについて私が耳にする最も頻繁な議論の 1 つは、YAGNIです(ただし、議論者はそれをそう呼ばないことがよくあります)。

「機能 X と機能 Y の両方を同じクラスに入れても問題ありません。わざわざ新しいクラス (つまり、複雑さ) を追加する理由は非常に単純です。」

「はい、すべてのビジネス ロジックを直接 GUI コードに入れることができます。はるかに簡単かつ迅速です。これは常に唯一の GUI であり、重要な新しい要件が発生する可能性はほとんどありません。」

「万が一、新しい要件が発生してコードが乱雑になった場合でも、新しい要件に合わせてリファクタリングできます。そのため、『後で…が必要になったら』という議論は重要ではありません。」

そのような慣行に対するあなたの最も説得力のある議論は何ですか? 特にソフトウェア開発の経験があまりない人にとって、これが費用のかかる慣行であることをどのように実際に示すことができますか。

4

10 に答える 10

52

設計とは、トレードオフの管理とバランスです。 YAGNI と SOLID は矛盾していません。前者はいつ機能を追加するかを示し、後者はどのように機能を追加するかを示しますが、どちらも設計プロセスを導きます。以下の、あなたの特定の引用のそれぞれに対する私の回答は、YAGNI と SOLID の両方の原則を使用しています。

  1. 再利用可能なコンポーネントを構築することは、使い捨てのコンポーネントを構築することよりも 3 倍困難です。
  2. 再利用可能なコンポーネントは、再利用ライブラリに受け入れられるほど一般的になる前に、3 つの異なるアプリケーションで試してみる必要があります。

  — Robert Glass の3 つのルールFacts and Fallacies of Software Engineering

再利用可能なコンポーネントへのリファクタリングには、最初に複数の場所で同じ目的を見つけてから移動するという重要な要素があります。このコンテキストでは、YAGNI は、汎用または再利用可能な機能 (クラスと関数) を追加する代わりに、重複の可能性を心配することなく、必要に応じてその目的をインライン化することによって適用されます。

初期設計において、YAGNI が適用されない場合を示す最善の方法は、具体的な要件を特定することです。言い換えれば、コードを書く前にリファクタリングを行い、複製が単に可能であるだけでなく、すでに存在していることを示します。これにより、余分な労力が正当化されます。


はい、すべてのビジネス ロジックを直接 GUI コードに入れることができます。はるかに簡単かつ迅速です。これは常に唯一の GUI であり、重要な新しい要件が発生する可能性はほとんどありません。

それは本当に唯一のユーザー インターフェイスですか? バックグラウンド バッチ モードの予定はありますか? ウェブインターフェースはありますか?

テスト計画はどのようなものですか? GUI を使用せずにバックエンド機能をテストしますか? 通常、外部コード (プラットフォーム ジェネリック GUI コントロールなど) をテストするのではなく、代わりにプロジェクトに集中したいので、GUI を簡単にテストするにはどうすればよいでしょうか。

機能 X と機能 Y の両方を同じクラスに入れても問題ありません。なぜわざわざ新しいクラスを追加するのか (つまり、複雑さ) は非常に単純です。

避けるべきよくある間違いを指摘できますか? 極端に単純な例の数の 2 乗 ( x * xvs squared(x)) など、単純なものもありますが、特にプロジェクトやチームのメンバーが犯した具体的な間違いを指摘できれば、クラスまたは関数は、将来それを回避します。

万が一、新しい要件が発生してコードが乱雑になった場合でも、新しい要件に合わせてリファクタリングできます。したがって、「後で必要になったらどうするか」という議論はカウントされません。

ここで問題になるのは、「可能性が低い」という仮定です。可能性が低いことに同意しますか?もしそうなら、あなたはその人と同意見です。そうでない場合、あなたのデザインのアイデアはこの人のものと一致しません。その不一致を解決することで問題が解決するか、少なくとも次に進むべき場所が示されます。:)

于 2010-10-13T16:46:30.807 に答える
9

YAGNI について、37signals ( https://gettingreal.37signals.com/ch05_Half_Not_Half_Assed.php )からこのフレーズを借りるために、「半分、中途半端ではない」という観点から考えるのが好きです。最も重要なことに集中できるように、スコープを制限することです。ずさんになる言い訳にはなりません。

GUI のビジネス ロジックは、中途半端に感じます。あなたのシステムが些細なものでない限り、ビジネス ロジックと GUI が個別に何回も変更されていないとしたら、私は驚かれることでしょう。したがって、SRP (SOLID の「S」) に従ってリファクタリングする必要があります。YAGNI は、既に必要なため、適用されません。

YAGNI と不必要な複雑さについての議論は、仮の将来の要件に対応するために今日余分な作業を行っている場合に完全に当てはまります。これらの「後で必要になったら...」というシナリオが実現しない場合、実際の変更の邪魔になる抽象化によるメンテナンス コストの増加に悩まされます。この場合、スコープを制限することで設計を簡素化することについて話しています。

于 2014-09-15T01:58:21.030 に答える
7

レンガの壁で議論しているようですね。私はYAGNIの大ファンですが、同時に、私のコードは常に少なくとも2つの場所(アプリケーションとテスト)で使用されることを期待しています。そのため、UIコードのビジネスロジックなどは機能しません。そのような状況では、UIコードとは別にビジネスロジックをテストすることはできません。

しかし、あなたが説明している回答から、その人はより良い仕事をすることに単に興味がないように思えます。その時点では、原則は彼らを助けるつもりはありません。彼らは可能な限り最小限のことをしたいだけです。私は、YAGNIが彼らの行動を推進しているのではなく、むしろ怠惰であり、あなただけが怠惰を打ち負かすことはないと言っています(脅迫的なマネージャーまたは失業を除いて、ほとんど何もできません)。

于 2010-10-13T12:45:20.883 に答える
2

私の経験では、それは常に判断の呼びかけです。はい、実装の細部をすべて気にする必要はありません。メソッドを既存のクラスに貼り付けることは、醜い解決策ではありますが、許容できる場合もあります。

後でリファクタリングできるのは事実です。重要な点は、実際にリファクタリングを行うことです。したがって、本当の問題は、時折の設計上の妥協ではなく、問題があることが明らかになったときにリファクタリングを延期することだと思います。実際にそれをやり遂げるのは難しい部分です(人生の多くのことと同じように...)。

あなたの個人的なポイントについて:

機能 X と機能 Y の両方を同じクラスに入れても問題ありません。なぜわざわざ新しいクラスを追加するのか (つまり、複雑さ) は非常に単純です。

すべてを 1 つのクラスにまとめると、より複雑になることを指摘しておきます(メソッド間の関係がより親密になり、理解しにくくなるためです)。多数の小さなクラスを持つことは複雑ではありません。リストが長くなりすぎていると感じたら、それらをパッケージにまとめてください。そうすれば問題ありません :-)。個人的には、クラスを 2 つまたは 3 つのクラスに分割するだけで、それ以上の変更を加えることなく、読みやすさが大幅に向上することがわかりました。

少人数のクラスを恐れないでください。

はい、すべてのビジネス ロジックを直接 GUI コードに入れることができます。はるかに簡単かつ迅速です。これは常に唯一の GUI であり、重要な新しい要件が発生する可能性はほとんどありません。

誰かが「重要な新しい要件が来る可能性は非常に低い」と言うことができれば. 真顔で、その人は本当に、本当にリアリティチェックが必要だと思います。無愛想だけど優しい…

万が一、新しい要件が発生してコードが乱雑になった場合でも、新しい要件に合わせてリファクタリングできます。したがって、「後で...が必要になったらどうするか」という引数はカウントされません

これにはある程度のメリットがありますが、後で実際にリファクタリングを行う場合に限られます。だからそれを受け入れて、彼らの約束を守ってください:-)。

于 2010-10-13T10:22:16.830 に答える
2

SOLID の原則により、ソフトウェアは変化に適応することができます。要件と技術的な変更 (新しいコンポーネントなど) の両方において、あなたの主張の 2 つは不変の要件に対するものです。

  • 「重要な新しい要件が発生する可能性はほとんどありません。」
  • 「万が一、新たな要件が発生した場合」

これは本当に真実でしょうか?

開発にかかるさまざまな費用に関しては、経験に勝るものはありません。多くの開業医にとって、お粗末で維持するのが難しい方法で物事を行うことが、彼らにとって問題になったことは一度もないと思います(ねえ、仕事の安全)。製品を長期的に使用すると、これらの費用が明確になると思いますが、事前に何かを行うのは他人の仕事です。

ここには他にもいくつかの素晴らしい答えがあります。

于 2010-10-13T19:08:33.153 に答える
2

これらの原則を正しく適用することは、多くの場合、あまり明白ではなく、経験に大きく依存します。自分でやらないとなかなか手に入りません。すべてのプログラマーは、間違ったことをした場合の結果を経験しているはずですが、もちろん、それは常に「私のものではない」プロジェクトであるべきです。

問題が何であるかを彼らに説明します。彼らが耳を傾けず、あなたが彼らに耳を傾ける立場にない場合は、彼らに間違いをさせてください. 問題を解決しなければならないことが頻繁にある場合は、履歴書を磨く必要があります。

于 2010-10-13T08:51:25.853 に答える
2

品質単体テスト、つまり統合テストではなく単体テストには、SOLID に準拠したコードが必要です。必ずしも100%ではなく、実際にはめったにそうではありませんが、あなたの例では、2つの機能を1つのクラスに詰め込むと、単体テストが難しくなり、単一責任の原則が破られ、チームの初心者によるコードメンテナンスがはるかに難しくなります(理解するのがはるかに難しいため) .

単体テスト (コード カバレッジが良好であると仮定) を使用すると、機能 1 を安全かつ確実にリファクタリングできます。機能 2 を壊すことはありませんが、単体テストを使用せず、同じクラスの機能を使用します (単純に例で怠惰にするため)。リファクタリングは良くても危険であり、良くても悲惨です。

結論:KISの原則に従うか(シンプルに保つ)、知識のある人はKISSの原則に従う(愚かなキス). グローバルな答えはありませんが、他のコーダーが将来コードを読んだり維持したりする必要があるかどうか、および各シナリオでの単体テストの利点を常に考慮してください。

于 2016-07-29T22:59:11.173 に答える
2

理解しやすく、柔軟で、修正と改善が可能なことは、常に必要になるものです。実際、YAGNI は、新しい機能が必要であると証明されたときに、戻ってきて、比較的簡単に新しい機能を追加できると想定しています。なぜなら、クラス内の無関係な機能 (そのクラスの YAGNI!) にぶつけたり、ビジネス ロジックを UI ロジックにプッシュしたりするようなクレイジーなことをする人は誰もいないからです。 .

今はおかしなことに思えることが、過去には合理的だった場合もあります。UI とビジネスの境界線、または別のクラスにあるはずのさまざまな責任のセットの間の境界線が明確でなかったり、移動したりすることさえあります。2時間の中でどうしても3時間の作業が必要な時があります。人々が正しい電話をかけない場合があります。これらの理由により、この点に関して時折の中断が発生しますが、それらは YAGNI 原則の使用を妨げますが、その原因にはなりません。

于 2010-10-14T09:21:23.823 に答える
1

tldr;

SOLID は、SRP に関するコードの将来の変更を (少なくともある程度は) 理解していると想定しています。それは予測能力について楽観的であると言えます。一方、YAGNI は、ほとんどの場合、将来の変化の方向性がわからないことを想定しており、予測能力について悲観的です。

したがって、SOLID/SRP では、変更の理由が 1 つになるように、コードのクラスを作成するよう求められます。たとえば、GUI の小さな変更や ServiceCall の変更などです。

YAGNI は、(このシナリオでそれを強制的に適用したい場合)、何が変更されるかわからないため、GUI の変更により GUI+ServiceCall の変更が発生する場合 (同様に、GUI+SeviceCall の変更を引き起こすバックエンドの変更) と述べています。 、すべてのコードを単一のクラスに入れるだけです。

長い答え:

「アジャイル ソフトウェア開発、原則、パターン、および実践」という本を読む

SOLID/SRP に関する短い抜粋を掲載します。「[...]2 つの責任が異なる時期に変更されるような方法でアプリケーションが変更されていない場合、それらを分離する必要はありません。実際、それらを分離します。不必要な複雑さのにおいがするでしょう。

ここに因果関係があります。変化の軸は、変化が起こった場合にのみ変化の軸になります。症状がない場合に SRP やその他の原則を適用するのは賢明ではありません。」

于 2014-09-04T06:28:14.953 に答える