web-dev-qa-db-ja.com

「すべて修正」のデザインパターンとは何ですか?

この linuxdevcenter.comのStephen Figginsによる2003年の記事 では、Bram CohenのBitTorrentは「Fix Everything」設計パターンを使用するものとして説明されています。

どちらもBitTorrentを把握するのは難しくなりますが、研究に値する一般的ではないアプローチは、コーエンのべき等の使用です。プロセスを2回以上適用すると、それ以上変更が生じない場合、プロセスはべき等です。コーエン氏は、「Fix Everything」と呼ばれるデザインパターンを使用していると述べています。 「発生したイベントに注意し、この非常にべき等な方法で記述されたすべてを修正する関数を呼び出し、起こっている可能性のあるものをすべてクリーンアップし、すべてをゼロから再計算します。」べき等は、いくつかの困難な計算を容易にしますが、少し複雑になります。コールが変更されるとすれば、それが明確であるとは限りません。事前に知っておく必要はありません。安全のために、関数を自由に呼び出すことができます。

これは一見するとかなりいいですね。

ただし、べき等の「すべてを修正」関数を呼び出すと、システムの堅牢性が向上しますが、効率が低下し、包含システムが台無しになる可能性があります(慎重に計画して実行するプロセスを好む場合があります)。

今まで使ったことがあるとは言えません。私は彼のアプリケーションのソースをオンラインで見つけることもできません(しかし、それに基づいていると主張する this one を見つけました)。また、この記事の外でそれへの参照を見つけることはできません(そして、私のgoogle-fuはかなり良いと思います)が、- "Idempotent Capability" on SOApatterns.org のエントリは見つかりませんでした。

このアイデアは別の名前でよく知られていますか?

「すべて修正」のデザインパターンとは何ですか。その長所と短所は何ですか?

74
Aaron Hall

かなり複雑なHTMLページがあるとします。1つのドロップダウンで何かを選択すると、別のコントロールが表示されるか、3番目のコントロールの値が変化する可能性があります。これに取り組むには2つの方法があります。

  1. コントロールごとに、そのコントロールのイベントに応答し、必要に応じて他のコントロールを更新する個別のハンドラーを作成します。

  2. ページ上のすべてのコントロールの状態を調べ、fixes everythingとなる単一のハンドラーを記述します。

2番目の呼び出しは "べき等"です。これは何度でも呼び出すことができ、コントロールが常に適切に配置されるためです。一方、通話が失われたり繰り返されたりすると、最初の通話で問題が発生する可能性があります。ハンドラの1つがトグルを実行する場合。

2番目の呼び出しのロジックはもう少しあいまいですが、ハンドラーを1つ記述するだけで済みます。

また、常に両方のソリューションを使用して、必要に応じて「すべてを修正する」関数を「安全のために」呼び出すことができます。

2番目のアプローチは、状態がさまざまなソースから取得できる場合に特に便利です。ユーザー入力とサーバーからのレンダリング。 ASP.NETでは、ページをレンダリングするたびに修正機能を実行するだけなので、この手法はポストバックの概念と非常にうまく機能します。

イベントが失われたり繰り返されたり、さまざまなソースから状態を取得することについて説明したので、このアプローチがBitTorrentのような問題空間にどのようにうまく対応するかは明らかだと思います。

短所?まあ明らかな欠点は、常にすべてを調べるのは効率が悪いため、パフォーマンスに影響があることです。しかし、BitTorrentのようなソリューションは、スケールアップではなくスケールアウトするように最適化されているので、そのようなことには適しています。解決しようとしている問題によっては、適切でない場合があります。

100
John Wu

私が読んだように、これは実際にはまったく正統的または新しいアイデアではないので、この記事は少し時代遅れだと思います。このアイデアは、実際には単なる単純なオブザーバー実装である場合、別個のパターンとして提示されます。その時のことを振り返ってみると、相互に依存しているデータを持つさまざまなパネルがいくつかある、やや複雑なインターフェースの背後にあるロジックに取り組んだことを覚えています。ユーザーは値を変更したり、最適化ルーチンを実行したりすることができ、それらのアクションに基づいて、UIがリッスンし、必要に応じて更新するイベントが生成されました。特定のパネルが必要なときに更新されないという開発中の問題がいくつかありました。修正(設計内にとどまる)は、他のイベントからイベントを生成することでした。最終的には、すべてが正常に機能するまでに、ほとんどすべての変更によってすべてのパネルが更新されました。特定のパネルを更新する必要がある場合に分離しようとする複雑さは、まったく役に立ちませんでした。とにかくそれは問題ではありませんでした。これは事実上、時期尚早の最適化でした。すべてを1つのイベントにまとめてすべてを更新することで、時間と労力を大幅に節約できただろう。

「すべてを修正」またはすべてを更新する方法で設計された無数のシステムがあります。行を追加/更新し、DBを再クエリするすべてのCRUDインターフェイスを考えてみてください。これはエキゾチックなアプローチではなく、明らかに非賢明なソリューションです。 2003年にはそれが「パターンフィーバー」の高さだったことを理解する必要があります。私が言うことができることから、人々は新しいパターンに名前を付けることが名声と富への道になると思っていました。誤解しないでください。パターンの概念は、抽象でソリューションを説明するのに非常に役立つものだと思います。 Rails少し外れました。パターンの概念全般について多くの皮肉を作ったので残念です。これについて話すのはこの文脈でのみ意味があります。 「非正統的」なソリューションです。これはORMまたはDIコンテナの正統性に似ています。これらのツールが存在するずっと前にソフトウェアを構築していて、多くの場合それらのツールが過剰であっても、それらを使用しないことは非正統的であると見なされています。

したがって、「すべてを修正」に戻ります。簡単な例は、平均の計算です。単純な解決策は、数値を合計し、値のカーディナリティーで除算することです。番号を追加または変更する場合は、最初からやり直すだけです。あなたは合計と数の数を追跡することができ、誰かが数を加えるとき、あなたは数を増やしてそれを合計に加えます。これで、すべての番号を再度追加することはありません。範囲を参照する数式を使用してExcelで作業し、その範囲内の単一の値を変更したことがある場合、「すべてを修正」パターンの例があります。つまり、その範囲を参照する数式は、その値は関連性がありました(たとえばsumif()のようなものを使用)。

これは、これが特定のコンテキストにおいて賢明な選択ではないということではありません。意地悪な例で、更新をサポートする必要があるとしましょう。今、私は何とか古い値を知って、デルタによって合計を変えるだけである必要があります。分散環境または並行環境でこれを実行することを検討するまで、これはそれほど難しいことではありません。これで、あらゆる種類の厄介なタイミングの問題を処理する必要があり、主要なボトルネックが発生して、再計算よりも速度が大幅に低下することになります。

ここでの結論は、「すべてを修正する」または「すべてを更新する」というアプローチの方がはるかに簡単に正しいことです。より洗練されたアプローチを機能させることができますが、それははるかに複雑であるため、欠陥が発生する可能性が高くなります。さらに、多くのコンテキストでは、「すべてを更新する」アプローチの方が効率的です。たとえば、シングルスレッドアプローチの場合、コピーオンライトアプローチは一般的に低速ですが、同時実行性が高い場合、ロックを回避できるため、パフォーマンスが向上します。他の場合では、効率的な方法で変更をまとめてバッチ処理できます。したがって、ほとんどの問題では、それができないという特定の理由がない限り、すべてを更新するアプローチから始めて、必要に応じてより複雑なことを行うことを心配する必要があります。回帰テストが可能な実際の実装は、たとえ遅くても、それ自体価値があります。

15
JimmyJames

それが「設計パターン」であるかどうかはわかりませんが、Puppet、Chef、またはPowershell DSCの脈絡で、このタイプの動作を最終状態構成または望ましい状態構成として分類します。 。

これらのソリューションは通常、質問が説明するビジネスロジックレベルではなく、システム管理レベルで動作しますが、実質的に同じパラダイムであり、そのようなツールは本質的に宣言型ですが、手続き型コードやスクリプトにも同じ原則を適用できます。

4
Dan1701

私は主にユーザーインターフェイス内でこれを使用しました。いいのは、一度書くと、最も単純なものから最も難しいものまですべてを等しくうまく処理できることです(たとえば、ユーザーが画面を回転した場合、またはラップトップ/デスクトップでユーザーがウィンドウのサイズを変更した場合、実質的にすべてが変更されます) )。

効率を心配する理由はあまりありません。ユーザーインターフェイスでは、移動したアイテムの再描画などの費用がかかります。各項目がどこに行くか、そしてそれがどれほど大きいかを計算することは、通常非常に高速です。確認する必要があるのは、アイテムが属する場所に正確にとどまる必要があることがわかった場合は常に、移動するコードが実行されないことです。本当の変化はあなたがとにかくしなければならなかったすべてのものです。

1
gnasher729

リアクティブプログラミングの原則のように聞こえます。 「すべてを修正」は、現在の「コア」状態を調べ、影響を受ける他のすべての「計算された状態」を伝播します。この導出を最適化すると、高効率に到達する可能性があります。単純に行うと、パフォーマンスは最適ではない場合がありますが、それでも十分高速である可能性があります。

0
orip