web-dev-qa-db-ja.com

次のSOLIDは、技術スタックの上にフレームワークを作成することにつながりますか?

私はSOLIDが好きで、開発時にはそれを使用して適用するように最善を尽くしています。 SOLIDアプローチは、コードを「フレームワーク」コードに変換します。つまり、他の開発者が使用するフレームワークまたはライブラリを作成する場合に設計するコードです。

私は通常、プログラミングの2つのモードを実践しました-要件とKISS(典型的なプログラミング)を介して要求されるものを正確に作成するか、または非常に一般的で再利用可能なロジック、サービスなどを作成して、他の開発者が必要とする柔軟性(フレームワークプログラミング)。

ユーザーが本当にアプリケーションにxとyのことを実行させたいだけの場合、SOLIDに従い、抽象化のエントリポイント全体を追加することは、知らない場合でも意味がありますか?それが最初から有効な問題であるかどうかこれらの抽象化のエントリポイントを追加した場合、ユーザーの要件を本当に満たしていますか、または既存のフレームワークと技術スタックの上にフレームワークを作成して将来の追加を容易にしますか?どちらの場合に、顧客または開発者の利益に貢献していますか?

これは、Javaエンタープライズの世界では一般的と思われるものです。J2EEまたはSpringの上に独自のフレームワークを設計しているように感じられるため、開発者にとってより優れたUXになります。ユーザーのためにUXに焦点を当てていますか?

70
Igneous01

あなたの観察は正しいです、SOLID原則は、再利用可能なライブラリまたはフレームワークコードを念頭に置いて作成されたIMHOです。理にかなっているかどうかを尋ねずに、それらすべてを盲目的にたどるだけの場合、リスクがあります。おそらく必要以上に多くの努力をシステムに過度に一般化して投資します。

これはトレードオフであり、いつ一般化するか、いつ一般化しないかについて適切な決定を行うにはある程度の経験が必要です。これに対する可能なアプローチは、YAGNIの原則に固執することです-コードを作成しないSOLID "念のために"-または、あなたの言葉を使用する:しないでください

他の開発者に柔軟性を提供may必要

代わりに、他の開発者に柔軟性を提供してください実際に必要必要に応じてすぐにですが、それ以前ではありません。

したがって、コード内に関数またはクラスが1つある場合は、それが再利用できるかどうか確信が持てない場合は、すぐにフレームワークに配置しないでください。再利用の実際のケースがあり、refactorが「そのケースに十分なソリッド」になるまで待ちます。実際の再利用のケースで本当に必要な場合は、(OCPに従って)より多くの構成可能性、または(DIPを使用して)抽象化のエントリポイントをこのようなクラスに実装しないでください。再利用の次の要件が実際にあるときに、次の柔軟性を追加します。

もちろん、この方法では、既存の機能するコードベースで常にある程度のリファクタリングが必要になります。ここで自動テストが重要なのはそのためです。したがって、コードをSOLIDユニットテスト可能にするために最初から十分な権利を作ることは時間の無駄ではなく、そうすることはYAGNIと矛盾しません。自動テストは "コードの再利用」、問題となっているコードはテストからだけでなく実稼働コードからも使用されるためです。ただし、テストを実行するために実際に必要な柔軟性を追加するだけで、それ以上ではありません。

これは実際には古い知恵です。用語の前のSOLIDが人気になったため、re使用可能なコードを書く前に誰かが私にsableコードを書くべきだと言ってきました。そして、私はまだこれが良い推薦だと思います。

83
Doc Brown

私の経験から、アプリを作成する場合、3つの選択肢があります。

  1. 要件を満たすためだけにコードを記述し、
  2. 現在の要件を満たすだけでなく、将来の要件を予測する一般的なコードを記述します。
  3. 現在の要件を満たすだけで、他のニーズを満たすために後で簡単に変更できるコードを記述します。

最初のケースでは、ユニットテストが欠けている密結合コードになってしまうのが一般的です。確かにそれは書くのは速いですが、テストするのは難しいです。そして、要件が変更されたときに後で変更することは、まさに王室の苦痛です。

2番目のケースでは、将来のニーズを予測するために膨大な時間が費やされます。そして、予想される将来の要件が実現することは決してありません。これはあなたが説明しているシナリオのようです。ほとんどの場合、これは労力の無駄であり、予期しない要件が発生した場合でも、変更が困難な不必要に複雑なコードが発生します。

最後のケースは、私の見解で狙うべきケースです。 TDDまたは同様の手法を使用してコードをテストし、ゆるやかに結合されたコードを作成します。変更は簡単ですが、作成は迅速です。そして、これを行うことで、SOLIDの原則:小さなクラスと関数、インターフェースと注入された依存関係の多くを自然に守ることができます。そして、Liskov先生は一般に、単一の責任が彼女の代替原則に反することはめったにない。

SOLIDのここで実際に適用されない唯一の側面は、オープン/クローズの原則です。ライブラリとフレームワークの場合、これは重要です。自己完結型アプリの場合、それほどではありません。本当に"[〜#〜] slid [〜#〜]"に続くコードを記述する場合:書き込み(および読み取り)が簡単で、テストが簡単で、保守が容易です。

49
David Arno

あなたが持っている視点は、個人的な経験によって歪められる可能性があります。これは個別に正しい事実の滑りやすい勾配ですが、一見正しいように見えても、結果として得られる推論は正しくありません。

  • フレームワークの範囲は、小規模なプロジェクトよりも大きくなります。
  • 大規模なコードベースでは、悪い習慣を扱うことは非常に困難です。
  • フレームワークを(平均して)構築するには、小規模なプロジェクトを構築するよりも熟練した開発者が必要です。
  • 優れた開発者は、グッドプラクティス(SOLID)にさらに従います。
  • その結果、フレームワークは優れた実践およびの必要性が高くなり、優れた実践に精通した開発者によって構築される傾向があります。

これは、フレームワークや小さなライブラリとやり取りする場合、やり取りする優れた実践コードは、より大きなフレームワークでより一般的に見つかることを意味します。

この誤りは非常に一般的です。たとえば、私が治療を受けたすべての医師は傲慢でした。したがって、私はすべての医師が傲慢だと結論付けています。これらの誤りは、常に個人的な経験に基づいて毛布を推論することに悩まされています。

あなたのケースでは、小さなライブラリではなく、大きなフレームワークで主に優れた実践を経験した可能性があります。あなたの個人的な観察は間違っていませんが、それは逸話的な証拠であり、普遍的に適用できるわけではありません。


プログラミングの2つのモード-要件とKISS(通常のプログラミング))を介して要求されるものを正確に作成するか、他の開発者が必要とする柔軟性を提供する非常に汎用的で再利用可能なロジック、サービスなどを作成する(フレームワークプログラミング)

ここでこれをいくらか確認しています。フレームワークとは何かを考えてください。アプリケーションではありません。これは、他の人があらゆる種類のアプリケーションを作成するために使用できる一般化された「テンプレート」です。論理的には、誰もが使用できるように、フレームワークはより抽象化されたロジックで構築されています。

フレームワークビルダーは、後続のアプリケーションの要件がわからないため、ショートカットを取ることができません。フレームワークを構築すると、本質的にそれらのインセンティブが高まり、コードを他の人が使用できるようになります。

ただし、アプリケーションビルダーは、製品の提供に重点を置いているため、論理的な効率を犠牲にすることができます。彼らの主な目標は、コードの動作ではなく、ユーザーのエクスペリエンスです。

フレームワークの場合、エンドユーザーはコードを操作する別の開発者です。コードの品質はエンドユーザーにとって重要です。
アプリケーションの場合、エンドユーザーは開発者ではないため、コードを操作することはありません。あなたのコードの品質は彼らにとって重要ではありません。

これがまさに、開発チームのアーキテクトがしばしば良い実践の執行者として行動する理由です。これらは、製品の提供から削除された1つのステップです。つまり、アプリケーション自体の提供に焦点を合わせるのではなく、コードを客観的に見る傾向があります。


これらの抽象化のエントリポイントを追加する場合、ユーザーの要件を本当に満たしていますか、それとも既存のフレームワークと技術スタックの上にフレームワークを作成して将来の追加を容易にしますか?どちらの場合に、顧客または開発者の利益に貢献していますか?

これは興味深い点であり、それが(私の経験では)人々が依然として良い習慣を避けることを正当化しようとする主な理由です。

以下のポイントを要約すると:スキップの良い習慣は、(現在知られている)要件が不変であり、コードベースに変更/追加がない場合にのみ正当化できます。ネタバレ注意:そんなことはめったにありません
たとえば、特定のファイルを処理するための5分間のコンソールアプリケーションを作成するとき、私は良い習慣を使いません。今日はアプリケーションを使用するだけなので、将来更新する必要はありません(別のアプリケーションが必要になった場合は、別のアプリケーションを作成する方が簡単です)。

アプリケーションを4週間で簡単にビルドでき、6週間で適切にビルドできるとしましょう。一見したところ、見事に構築する方が良いようです。顧客はアプリケーションをすばやく入手でき、会社は開発者の賃金に費やす時間を短縮する必要があります。勝ち、勝ちますか?

ただし、これは前もって考えずに行われた決定です。コードベースの品質のため、お粗末にビルドされたものに大きな変更を加えるには2週間かかりますが、適切にビルドされたものに同じ変更を加えるには1週間かかります。将来的には、これらの変更の多くが発生する可能性があります。

さらに、が予期せずに変更される傾向がありますは、手際よく構築されたコードベースで最初に考えたよりも多くの作業を必要とするため、開発時間を2週間ではなく3週間に押し上げる可能性があります。

そして、バグを探すのに時間を浪費する傾向もあります。これは、時間の制約や、最終製品が期待どおりに機能するという想定の下で不注意に作業するために、それを実装する意欲がないためにログが無視されたプロジェクトでよく見られます。

メジャーアップデートである必要さえありません。私の現在の雇用主では、迅速かつダーティに構築されたいくつかのプロジェクトを見てきました。要件の誤解により最小のバグ/変更を行う必要がある場合、モジュールごとにモジュールをリファクタリングする必要があるという連鎖反応につながります。これらのプロジェクトのいくつかは、最初のバージョンをリリースする前に、崩壊してしまい(維持不可能な混乱を残して)しまいました。

ショートカットの決定(迅速でダーティーなプログラミング)は、要件が正確であり、変更する必要がないことを確実に保証できる場合にのみ有益です。私の経験では、決してそうではありませんそれが真実であるプロジェクトに出くわしませんでした。

良い習慣に余分な時間を投資することは、将来に投資することです。既存のコードベースが優れたプラクティスに基づいて構築されている場合、将来のバグや変更は非常に簡単になります。たった2つか3つの変更がなされた後でそれはすでに配当を支払っているでしょう。

8
Flater

SOLIDはどのようにして単純なコードをフレームワークコードに変換しますか?私は SOLIDのスタンではありません ですが、ここで何を意味するのかは明確ではありません。

  • KISSは[〜#〜] s [〜#〜]単一の責任原則の本質です。
  • [〜#〜] o [〜#〜]ペン/閉じた原理には何もありません(少なくとも私が理解しているように、- を参照してくださいJon Skeet )これは、1つのことをうまく行うコードの記述に反します。 (実際には、コードをより厳密に集中するほど、「閉じた」部分が重要になります。)
  • [〜#〜] l [〜#〜]iskov代入原理では、クラスをサブクラス化する必要があるとは言われていません。 youクラスをサブクラス化する場合、サブクラスはスーパークラスの規約を満たす必要があると述べています。これは、OOのデザインにぴったりです。 (そして、サブクラスがない場合、それは適用されません。)
  • KISSは、[〜#〜] i [〜#〜]インターフェース分離原則の本質でもあります。
  • [〜#〜] d [〜#〜]依存性反転の原理は、リモートで適用されているのを見ることができる唯一のものですが、私はそれが広く誤解されていると思います誇張された。すべてをGuiceまたはSpringで注入する必要があるという意味ではありません。これは、実装の詳細に依存せずに、必要に応じて抽象化する必要があることを意味します。

私はSOLIDという言葉で自分が考えていないことを認めます。なぜなら、私は Gang of Four および Josh Bloch プログラミングの学校ではなく、ボブ・マーティン学校。しかし、「SOLID」=「テクノロジースタックにレイヤーを追加する」と考えるのは間違いだと思います。


追伸「開発者にとってより良いUX」のメリットを売り切れないようにしてください。コードはその寿命のほとんどをメンテナンスに費やしています。 開発者はあなたです

7
David Moles