web-dev-qa-db-ja.com

抽象化が多すぎると悪いのでしょうか?

プログラマーとしての私は、与えられたドメインモデルとビジネスロジックに優れた抽象化を提供することが目標だと感じています。しかし、この抽象化はどこで止めるべきでしょうか? 抽象化の間のトレードオフとそのすべての利点(柔軟性、変更の容易さなど)の作り方およびコードの理解の容易さとすべての利点。

私は過度に抽象化されたコードを書く傾向があり、それがどれほど優れているかわかりません。私はしばしばそれをある種のマイクロフレームワークのように書く傾向があり、それは2つの部分で構成されています。

  1. マイクロフレームワークに接続されたマイクロモジュール:これらのモジュールは、理解、開発、および単一ユニットとしての維持が容易です。このコードは基本的に、要件に記載されている実際の機能を実行するコードを表します。
  2. 接続コード;今ここに私は問題が立っていると信じています。このコードは、非常に抽象化されている場合があり、最初は理解しにくいため、複雑になる傾向があります。これは、それが純粋な抽象化であり、実際のベースであり、ビジネスロジックが提示されたコードで実行されているために発生します1。この理由から、このコードはテスト後に変更されることは想定されていません。

これはプログラミングの良いアプローチですか?それは、変更コードが多くのモジュールで非常に断片化されており、非常に理解しやすく、非変更コードが抽象化POVから非常に複雑であることを示していますか?すべてのコードが均一に複雑である(つまり、コード1がより複雑で相互リンクされ、コード2がより単純である)ため、コードを見る誰もが妥当な時間でそれを理解できるが、変更が高価であるか、上記のソリューションが優れている場合「コードの変更」は理解、デバッグ、変更が非常に簡単で、「コードのリンク」は少し難しいです。

注:これはコードの読みやすさに関するものではありません! 1と2のコードはどちらも読み取り可能ですが、2のコードにはより複雑な抽象化が付属しており、コード1には単純な抽象化が付属しています。

49
m3th0dman

TC++ PL4の最初の言葉:

コンピューターサイエンスのすべての問題は、間接参照のレイヤーが多すぎるという問題を除いて、別のレベルの間接参照で解決できます。– David J. Wheeler

(David Wheelerが私の論文顧問でした。重要な最後の行のない引用は、「コンピュータサイエンスの第一法則」と呼ばれることもあります。)

84
Bjarne

はい、間違いなく。事は、抽象化は完璧ではないということです。抽象化が上位に位置するレイヤーの詳細はすべて理由があるため、多くのことを簡素化できますが、その複雑さがいつの時点でも必要なければ、おそらくそもそもそこにはないでしょう。つまり、ある時点で すべての抽象化が何らかの方法でリークすることになります。

そして、そこが本当の問題です。抽象化が失敗した場合、記述したコードと実際に何が起こっているかの間の層が多ければ多いほど、問題の原因を突き止めて修正するのが難しくなります。そして、レイヤーが多いほど、それを追跡するために知る必要があります。

32
Mason Wheeler

そのとおり。

私がプログラミングを説明するのに使用したい類推はテーラーのそれです。スーツを作るとき、良いテーラーは常に全体的な形や構造を変えることなく、衣服内の重要な場所に少量の生地を残して、衣服を出し入れできるようにします。

グッドテーラーは、たまたま3本目の腕を伸ばしたり、妊娠したりした場合に備えて、各縫い目に一連の布を残さないでください。間違った場所にある材料が多すぎると、具合が悪くなり、衣服の着用が悪くなります。余分な布地は、通常の使用の邪魔になります。生地がほとんどないため、衣服が裂けやすく、着用者の体格の小さな変化に対応するように変更できず、衣服の着座方法に影響を与えます。

おそらくいつの日か、私たちのグッドテーラーは、とてもタイトなドレスを作って、その摩耗を縫い合わせる必要があります。そして、おそらく私たちのGood Tailorは、スタイルとフィット感が快適さと拡張性に次ぐマタニティウェアを作るように求められています。しかし、これらの特別な仕事のいずれかを行う前に、優れたテーラーは、それらの目標を達成するために行われている妥協点をすべての人に認識させるのに十分賢明でしょう。

時々これらの妥協策は正しいルートであり、人々はその結果を受け入れようとしています。ただし、ほとんどの場合、休暇を最も多くカウントするアプローチは、知覚されるメリットを上回ります。

つまり、これを抽象化に関連付けることです。抽象化のレイヤーが多すぎる可能性があるのと同じように、少なすぎる可能性もあります。プログラマーの真の芸術は、私たちの仕立て屋の友人のように、最も重要な場所に少し離れることです。

トピックに戻ります。

コードの問題は通常、抽象化ではなく、依存関係です。あなたが指摘したように、それらの間の暗黙の依存関係があるので、問題である離散オブジェクトを接続するそのコード。ある時点でthings間の通信は具体的である必要がありますが、その時点がどこであるかを判断するには、通常、推測が必要です。

「マイクロ」とは、通常、オブジェクトレイアウトを過度に細分化したことを示しており、おそらくTypeDataの同義語として使用しています。物事が少ないということは、それらの間の通信に必要な依存関係も少ないことを意味します。

このため、私はシステム間の非同期メッセージングの大ファンです。結局、相互ではなくmessageに依存する2つのシステムになります。通信システム間の緊密な結合を緩和します。その時点で、システム間の依存関係が必要な場合は、適切な場所に依存しているビットがあるかどうかを検討する必要があります。そして、あなたがそうしないことがよくあります。

最後に、複雑なコードは複雑になります。多くの場合、それを回避する方法はありません。ただし、依存関係の少ないコードは、さまざまな外部状態に依存するコードよりもはるかに理解しやすくなります。

18
Matt D

私たちの目標は、与えられたドメインモデルとビジネスロジックに優れた抽象化を提供することだと感じています。

私は別の見方をしています。私たちの目標はビジネス上の問題を解決することです。抽象化は、ソリューションを編成するためのテクニックにすぎません。別の答えは、洋服を仕立てるテーラーのアナロジーを使用しています。私が考えたい別の類推があります。スケルトンです。コードはスケルトンのようなものであり、抽象化はボーン間のジョイントです。ジョイントがない場合は、まったく動かず、役に立たない単一のボーンで巻き上げられます。しかし、関節が多すぎると、それだけでは耐えられないずさんなゼリーの山ができてしまいます。トリックは、適切なバランスを見つけることです-動きを可能にするのに十分な関節ですが、実際に定義された形状や構造はありません。

13
Jordan Lev

これまで言及されていないことの1つは KISSの原則[〜#〜] yagni [〜#〜] です:単純で愚かです。あなたはそれを必要としないでしょう。

時々、抽象化には非常に良い理由があります:

  • あなたはすでにそれらを使用しており、複雑さを低く保つためにそれらを既に必要としています-多分将来のいつかではなく、実際にはすでに。
  • あなたはライブラリ/プラグインシステムで何かを書いていて、ユーザーのために破壊的な変更を防ぎたいと思っています。

そうでない場合は、抽象化を削除できます。

1
Martin Thoma