web-dev-qa-db-ja.com

漏れのある抽象化の意味?

「漏洩抽象化」という用語は何を意味しますか? (例を挙げて説明してください。私はしばしば単なる理論を理解するのに苦労します。)

81
Geonne

これが meatspace の例です。

自動車にはドライバーの抽象化があります。最も純粋な形で、ハンドル、アクセル、ブレーキがあります。この抽象化は、ボンネットの下にあるものに関する多くの詳細を隠します:エンジン、カム、タイミングベルト、sparkプラグ、ラジエーターなど)。

この抽象化の優れた点は、ユーザーを再トレーニングすることなく、実装の部分を改善された部分に置き換えることができることです。たとえば、ディストリビュータキャップを電子点火に置き換え、固定カムを可変カムに置き換えたとします。これらの変更によりパフォーマンスが向上しますが、ユーザーは引き続きホイールを操作し、ペダルを使用して開始と停止を行います。

それは実際にはかなり注目に値します... 16歳または80歳は、内部でどのように機能するかについてあまり知らなくても、この複雑な機械を操作できます。

しかし、リークがあります。伝送は小さな漏れです。オートマチックトランスミッションでは、ギアが切り替わるときに一時的にパワーが失われるのを感じることができますが、CVTではスムーズなトルクを感じることができます。

より大きな漏れもあります。エンジンの回転が速すぎると、損傷する可能性があります。エンジンブロックの温度が低すぎると、車が始動しないか、パフォーマンスが低下する可能性があります。また、ラジオ、ヘッドライト、およびACを同時にクランクすると、燃費が低下するのがわかります。

93
Mark E. Haase

それは単に、抽象化が実装の詳細の一部を公開すること、または抽象化を使用するときに実装の詳細に注意する必要があることを意味します。この用語は Joel Spolsky によるもので、2002年頃です。詳細については、ウィキペディア article を参照してください。

古典的な例は、リモートファイルをローカルとして扱うことができるネットワークライブラリです。この抽象化を使用する開発者は、ネットワークの問題が原因で、ローカルファイルとは異なる方法でこれが失敗する可能性があることに注意する必要があります。次に、ネットワークライブラリが提供する抽象化以外のエラーを具体的に処理するコードを開発する必要があります。

45
tvanfosson

ウィキペディアには かなり良い定義 があります

リークのある抽象化とは、複雑さを軽減(または非表示)することを目的とした、実装されている抽象化を指します。

つまり、ソフトウェアの場合は、プログラムの制限や副作用を介して機能の実装の詳細を観察できるときです。

簡単な例は、C#/ VB.Netクロージャーと、ref/outパラメーターをキャプチャできないことです。それらをキャプチャできない理由は、リフティングプロセスがどのように発生するかの実装の詳細によるものです。これにはもっと良い方法があると言っているのではありません。

12
JaredPar

.NET開発者がよく知っている例を次に示します。ASP.NETのPageクラスは、HTTP操作の詳細、特にフォームデータの管理を隠そうとします。そのため、開発者は投稿された値を処理する必要がありません(フォームの値をサーバーコントロールに自動的にマップします)。

しかし、最も基本的な使用シナリオを超えて歩き回ると、Page抽象化がリークし始め、クラスの実装の詳細を理解しない限り、ページの操作が困難になります。

一般的な例の1つは、ページにコントロールを動的に追加することです。動的に追加されたコントロールの値は、適切なタイミングで追加しない限り、マップされません。適切なコントロールへの値。あなたがそれを学ばなければならないとき、抽象化はリークされたを持っています。

11
Jeff Sternal

まあ、ある意味では、それは純粋に理論的なものですが、重要ではありません。

抽象化を使用して、物事をより理解しやすくします。いくつかの言語の文字列クラスを操作して、個別のアイテムである文字の順序付けられたセットを処理しているという事実を隠すことができます。数字を扱っているという事実を隠すために、順序付けられた文字のセットを扱っています。 1と0を扱っているという事実を隠すために、数値を扱っています。

漏れやすい抽象化は、非表示にする詳細を非表示にしないものです。 Javaまたは.NETの5文字の文字列でstring.Lengthを呼び出すと、それらの言語が文字を呼び出す実装の詳細が実際にはUTF-16データポイントであるため、5から10までの任意の答えを得ることができます。文字の1または.5を表すことができます。抽象化が漏れています。ただし、リークしないことは、長さを見つけるには(実際の長さを格納するために)より多くのストレージ領域が必要になるか、またはO(1)からO(n)に変更されることを意味します実際の長さは何ですか)。私が本当の答えを気にかけている場合(多くの場合、あなたは実際にはそうではありません)、本当に何が起こっているのかについての知識に取り組む必要があります。

メソッドやプロパティが内部の仕組みにアクセスできるようなケースでは、より多くの議論の余地のあるケースが発生します。それらが抽象リークであるか、より低いレベルの抽象に移動するための明確に定義された方法であるかは、人々が同意しない問題になることがあります。

7
Jon Hanna

RPCを使用して例を示すつもりです。

RPCの理想的な世界では、リモートプロシージャコールはローカルプロシージャコールのように見える必要があります(つまり、話は続きます)。プログラマがSomeObject.someFunction()を呼び出したときに、SomeObject(または単にsomeFunction)がローカルに格納されて実行されているかどうかがわからないように、完全に透過的である必要があります。リモートで保存および実行されます。これにより、プログラミングが簡単になるという理論があります。

ローカルの関数呼び出しを行う場合(世界で最も遅いインタープリター型言語を使用している場合でも)と以下の間に大きな違いがあるため、現実は異なります。

  • プロキシオブジェクトを介した呼び出し
  • パラメータをシリアル化する
  • ネットワーク接続を確立する(まだ確立されていない場合)
  • データをリモートプロキシに送信する
  • リモートプロキシにデータを復元させ、ユーザーに代わってリモート関数を呼び出す
  • 戻り値をシリアル化する
  • 戻り値をローカルプロキシに送信する
  • シリアル化されたデータの再組み立て
  • リモート関数から応答を返す

時間だけでも、それは約3桁(またはそれ以上)の大きさの差です。これらの3桁以上の桁数は、RPCを実際の関数呼び出しとして誤って処理したときに、明らかに明らかにプロシージャコールリークの抽象化を行うパフォーマンスに大きな違いをもたらします。さらに、実際の関数呼び出しでは、コードに深刻な問題がない限り、実装のバグ以外に障害点はほとんどありません。 RPC呼び出しには、通常のローカル呼び出しで予想される以上の失敗のケースとして次々と発生する可能性のある次の問題があります。

  • ローカルプロキシをインスタンス化できない可能性があります
  • リモートプロキシをインスタンス化できない可能性があります
  • プロキシが接続できない可能性があります
  • 送信したパラメータによって、完全な状態にならないか、まったく機能しない場合があります
  • リモートが送信する戻り値は、それをそのままにすることも、まったくしないこともあります

そのため、「ローカル関数呼び出しとまったく同じ」RPC呼び出しには、ローカル関数呼び出しを実行するときに対処する必要のない余分な障害状態の全体的な負荷があります。抽象化は、さらに困難になっています。

結局のところ、RPCはすべてのレベルでふるいのようにリークするため、抽象化は適切ではありません。成功した場合と失敗した場合の両方です。

Django ORM多対多の例 の例:

サンプルAPIの使用法では、Publicationオブジェクトを多対多属性に追加する前に、ベースArticleオブジェクトa1を.save()する必要があることに注意してください。また、多対多の属性を更新すると、基になるデータベースにすぐに保存されますが、単一の属性を更新すると、.save()が呼び出されるまでデータベースに反映されません。

抽象化は、オブジェクトグラフで作業していることです。単一値属性と複数値属性は単なる属性です。しかし、リレーショナルデータベースに裏打ちされたデータストアとしての実装はリークします... RDBSの整合性システムがオブジェクトインターフェースの薄いベニアを通して現れるためです。

3
hash1baby

抽象化とは何ですか?

まず、「抽象化」とは何かを理解するのが最善でしょうか。

抽象化は、世界を簡素化する方法です。これは、実際にフードの下で、またはカーテンの後ろで何が起こっているかについて心配する必要がないことを意味します。それは何かがばか証拠であることを意味します。わかりました、それはどういう意味ですか?これは例によって最もよく示されます。

抽象化の例:737/747の飛行の複雑さは「抽象化」されています

ボーイングの旅客機を例にとってみましょう。これらの飛行機は非常に複雑な機械です。ジェットエンジン、酸素システム、電気システム、着陸装置システムなどがありますが、パイロットはジェットエンジンの複雑さについて心配する必要はありません。その日、パイロットは飛行機を操縦するためのホイールと操縦桿だけを心配します。左に行くには左に、右に行くには右に、引き上げて高度を取得し、押し下げて降下します。それは十分に簡単です……実際に私は嘘をつきました:ステアリングホイールを制御することはもう少し複雑です。理想的な世界では、それだけが彼が心配する必要があることです。しかし、これは現実の世界では当てはまりません。飛行機の動作や実装の詳細についての理解がまったくないまま、猿のように飛行機を操縦すると、墜落して乗っている全員を殺してしまう可能性があります。

漏れやすい抽象化

実際には、パイロットは多くの重要なことを心配する必要があります-すべてが抽象化されているわけではありません。パイロットは、風速、推力、迎角、燃料、高度、気象問題、降下角、パイロットは正しい方向に進んでいます。飛行機は今そこにあります。コンピューターはこれらのタスクでパイロットを助けることができますが、すべてが自動化/簡略化されているわけではありません。

例えばパイロットがコラムを強く引き上げすぎると、飛行機は従いますが、パイロットは飛行機を失速させる危険があります。飛行機を失速させると、飛行機が地面に墜落する前に制御を取り戻すのは非常に困難です。

言い換えれば、パイロットが他のことを何も知らずに単にハンドルを制御するだけでは十分ではありません…………彼女は飛行機の根本的なリスクと限界について知っている必要があります彼が飛行機を飛ばす前に.......彼女は飛行機がどのように機能するか、飛行機がどのように飛ぶかを知らなければなりません。彼は実装の詳細 .....知っている必要があります。彼女は、強く引っ張るとストールにつながることを知っている必要があります。着陸が急すぎれば、飛行機は破壊されます。

それらは抽象化されていません。多くのものが抽象化されていますが、すべてではありません。パイロットはステアリングコラムについて、そしておそらく他の1つまたは2つのことについて心配するだけで済みます。抽象化は「漏れやすい」です。

......コードでも同じです。基礎となる実装の詳細がわからない場合は、多くの場合、自分自身が隅々まで作業します。

これがコーディングの例です:

ORMは、データベースクエリの処理における多くの手間を抽象化しますが、次のようなことをしたことがある場合:

User.all.each do |user|
   puts user.name # let's print each user's name
end

その後、数百万人以上のユーザーがいる場合、それがアプリを強制終了する良い方法であることがわかります。すべてが抽象化されているわけではありません。 2,500人のユーザーとUser.allを呼び出すと、メモリ使用量が急増し、問題が発生することを知っておく必要があります。いくつかの根本的な詳細を知る必要があります。抽象化には漏れがあります。

1
BKSpurgeon

スケールと実行によって導かれるある時点でであるという事実は、抽象化フレームワークがそのように動作する理由を理解するために、抽象化フレームワークの実装の詳細を理解する必要があります。

たとえば、次のSQLクエリを考えてみます。

SELECT id, first_name, last_name, age, subject FROM student_details;

そしてその代替:

SELECT * FROM student_details;

現在、これらは論理的に同等のソリューションのように見えますが、最初のソリューションのパフォーマンスは、個々の列名の仕様により優れています。

これは些細な例ですが、最終的にはJoel Spolskyの引用に戻ります。

重要な抽象化はすべて、ある程度、漏れやすいものです。

ある時点で、操作で特定の規模に達したときに、DB(SQL)の動作を最適化する必要があります。それを行うには、リレーショナルデータベースの動作を知っている必要があります。最初は抽象化されていましたが、漏れやすいです。あなたはある時点でそれを学ぶ必要があります。

0
Johnny