差分実行はどのように機能しますか?


83

Stack Overflowでこれについていくつか言及しましたが、ウィキペディア(関連するページは削除されました)とMFC動的ダイアログのデモを見つめても何もわかりませんでした。誰かがこれを説明できますか?根本的に異なる概念を学ぶのはいいですね。


答えに基づいて:私はそれについてより良い感じを得ていると思います。初めてソースコードを注意深く見ていなかったと思います。この時点で、実行の差異についてはさまざまな感情があります。一方では、特定のタスクをかなり簡単にすることができます。一方、それを起動して実行する(つまり、選択した言語で設定する)のは簡単ではありません(私がそれをよりよく理解していればそうなると確信しています)...私はそれのためのツールボックスを推測しますが一度作成するだけで、必要に応じて拡張できます。それを本当に理解するためには、おそらく別の言語で実装してみる必要があると思います。


3
ブライアンに関心をお寄せいただきありがとうございます。私にとって、単純なものががっかりしているように見えるのは興味深いことです。私にとって、最も美しいものは単純です。気を付けて。
Mike Dunlavey 2009年

1
重要なものが欠けていると思います。今、「これは簡単だ」と思っています。本当に理解できたら、「これは簡単です。本当に素晴らしくて便利です」と思っていると思います。
ブライアン

6
... MVCを提示している人は、それが最高だと今でも見ています。もう一度やらなくてはならないのではなく、引退したいと思います。
Mike Dunlavey 2009年

1
...「元に戻す」の場合、データをシリアル化/逆シリアル化し、2つのXORであるファイルをスピンオフします。これはほとんどゼロであるため、簡単に圧縮できます。以前のデータを回復するためにそれを使用してください。ここで、任意のデータ構造に一般化します。
Mike Dunlavey 2009

1
@MikeDunlaveyさん、ワークロードに追加したくありませんが、それを見逃した場合、SourceForgeは疑わしいビジネス慣行で恵みを失いました。Github.comは、クールな子供たちが最近ぶら下がっている場所です。彼らはでW7のための本当に素晴らしいWindowsクライアントを持ってdesktop.github.com
教授ファルケン

回答:


95

ジー、ブライアン、もっと早くあなたの質問を見ていたらよかったのに。それはほとんど私の「発明」であるため(良くも悪くも)、私は助けることができるかもしれません。

挿入:私ができる最短の説明は、通常の実行がボールを空中に投げてキャッチするようなものである場合、差動実行はジャグリングのようなものであるということです。

@windfinderの説明は私のものとは異なり、それで問題ありません。このテクニックは頭を包み込むのは簡単ではなく、うまくいく説明を見つけるのに約20年(オフとオン)かかりました。ここで別のショットを与えましょう:

  • それは何ですか?

私たちは皆、コンピューターがプログラムをステップスルーし、入力データに基づいて条件分岐を取り、物事を行うという単純な考えを理解しています。(単純な構造化goto-less、return-lessコードのみを扱っていると仮定します。)そのコードには、ステートメントのシーケンス、基本的な構造化条件、単純なループ、およびサブルーチン呼び出しが含まれています。(今のところ、値を返す関数については忘れてください。)

ここで、2台のコンピューターが同じコードを互いにロックステップで実行し、メモを比較できると想像してみてください。コンピューター1は入力データAで実行され、コンピューター2は入力データBで実行されます。これらは段階的に並んで実行されます。IF(test).... ENDIFのような条件文に到達し、テストが真であるかどうかについて意見の相違がある場合、偽の場合にテストを言う人はENDIFにスキップし、待機します。追いつくためにその姉妹。(これがコードが構造化されている理由であり、姉妹が最終的にENDIFに到達することがわかっています。)

2台のコンピューターは相互に通信できるため、メモを比較し、2セットの入力データと実行履歴がどのように異なるかを詳細に説明できます。

もちろん、差分実行(DE)では、1台のコンピューターで実行され、2台のコンピューターをシミュレートします。

ここで、入力データのセットが1つしかないが、それが時間1から時間2にどのように変化したかを確認したいとします。実行しているプログラムがシリアライザー/デシリアライザーであるとします。実行すると、現在のデータをシリアル化(書き込み)し、過去のデータ(最後にこれを行ったときに書き込まれた)を逆シリアル化(読み取り)します。これで、前回のデータと今回のデータの違いを簡単に確認できます。

書き込みを行っているファイルと読み取りを行っている古いファイルを合わせて、キューまたはFIFO(先入れ先出し)を構成しますが、これはそれほど深い概念ではありません。

  • それは何のために良いですか?

グラフィックプロジェクトに取り組んでいるときに思いついたのは、ユーザーが「シンボル」と呼ばれる小さなディスプレイプロセッサルーチンを作成して、パイプ、タンク、バルブなどの図を描くために、より大きなルーチンに組み立てることができるということでした。ダイアグラム全体を再描画せずに段階的に更新できるという意味で、ダイアグラムを「動的」にしたかったのです。(ハードウェアは今日の基準では低速でした。)たとえば、棒グラフの棒を描画するルーチンは、古い高さを記憶し、それ自体を段階的に更新できることに気付きました。

これはOOPのようですね。ただし、「オブジェクト」を「作成」するのではなく、ダイアグラムプロシージャの実行シーケンスの予測可能性を利用できます。バーの高さをシーケンシャルバイトストリームで書き込むことができます。次に、イメージを更新するために、次の更新パスの準備ができるように、新しいパラメーターを書き込む間、古いパラメーターを順次読み取るモードでプロシージャを実行することができます。

これはばかげているように思われ、プロシージャに条件が含まれるとすぐに壊れるように見えます。これは、新しいストリームと古いストリームが同期しなくなるためです。しかし、条件付きテストのブール値もシリアル化すると、同期を取り戻すことができることに気づきました。簡単なルール(「消去モードルール」)が守られていれば、自分自身を納得させ、これが常に機能することを証明するのにしばらく時間がかかりました。

最終的な結果として、ユーザーは、表示がどれほど複雑または構造的に可変であっても、動的に更新する方法を心配することなく、これらの「動的シンボル」を設計してより大きな図に組み立てることができます。

当時、私は視覚的なオブジェクト間の干渉を心配しなければならなかったので、1つを消去しても他のオブジェクトが損傷することはありませんでした。ただし、現在はWindowsコントロールでこの手法を使用しており、レンダリングの問題はWindowsに任せています。

それで、それは何を達成しますか?これは、コントロールをペイントするプロシージャを作成することでダイアログを作成できることを意味し、実際にコントロールオブジェクトを記憶したり、段階的に更新したり、条件に応じて表示/非表示/移動したりすることを心配する必要はありません。その結果、ダイアログのソースコードは、約1桁小さく、単純になります。動的なレイアウト、コントロールの数の変更、コントロールの配列やグリッドの設定などは簡単です。さらに、編集フィールドなどのコントロールは、編集中のアプリケーションデータに簡単にバインドでき、常に正しいことが証明され、そのイベントを処理する必要はありません。アプリケーション文字列変数の編集フィールドに入力するのは、1行の編集です。

  • なぜ理解しにくいのですか?

私が説明するのが最も難しいと思ったのは、ソフトウェアについて別の考え方をする必要があるということです。プログラマーはソフトウェアのオブジェクトアクションビューにしっかりと固執しているので、オブジェクトとは何か、クラスとは何か、ディスプレイを「構築」する方法、イベントを処理する方法を知りたいので、チェリーが必要です。それからそれらを爆破する爆弾。私が伝えようとしているのは、本当に重要なのはあなた何を言う必要があるかということです。ドメイン固有言語(DSL)を構築していると想像してみてください。ここで、「ここで変数A、そこに変数B、そこに変数Cを編集したい」と言うだけで、魔法のように処理されます。 。たとえば、Win32には、ダイアログを定義するためのこの「リソース言語」があります。それが十分に進んでいないことを除いて、それは完全に良いDSLです。メインの手続き型言語に「存在」したり、イベントを処理したり、ループ/条件/サブルーチンを含んだりすることはありません。しかし、それは良い意味であり、DynamicDialogsは仕事を終わらせようとします。

したがって、異なる考え方は次のとおりです。プログラムを作成するには、まず適切なDSLを見つけて(または発明して)、その中にできるだけ多くのプログラムをコーディングします。ましょう、それが唯一の実装のために存在するすべてのオブジェクトとアクションを扱います。

差分実行を本当に理解して使用したい場合は、つまずく可能性のあるトリッキーな問題がいくつかあります。私はかつて、これらのトリッキーなビットを処理できるLispマクロでコーディングしましたが、「通常の」言語では、落とし穴を回避するためにプログラマーの訓練が必要です。

大変ご迷惑をおかけして申し訳ありません。意味がわからない場合は、ご指摘いただければ幸いです。修正を試みることができます。

追加:

JavaのSwing、TextInputDemoと呼ばれるプログラム例があります。これは静的なダイアログであり、270行かかります(50の状態のリストはカウントされません)。動的ダイアログ(MFC)では、約60行です。

#define NSTATE (sizeof(states)/sizeof(states[0]))
CString sStreet;
CString sCity;
int iState;
CString sZip;
CString sWholeAddress;

void SetAddress(){
    CString sTemp = states[iState];
    int len = sTemp.GetLength();
    sWholeAddress.Format("%s\r\n%s %s %s", sStreet, sCity, sTemp.Mid(len-3, 2), sZip);
}

void ClearAddress(){
    sWholeAddress = sStreet = sCity = sZip = "";
}

void CDDDemoDlg::deContentsTextInputDemo(){
    int gy0 = P(gy);
    P(www = Width()*2/3);
    deStartHorizontal();
    deStatic(100, 20, "Street Address:");
    deEdit(www - 100, 20, &sStreet);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "City:");
    deEdit(www - 100, 20, &sCity);
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "State:");
    deStatic(www - 100 - 20 - 20, 20, states[iState]);
    if (deButton(20, 20, "<")){
        iState = (iState+NSTATE - 1) % NSTATE;
        DD_THROW;
    }
    if (deButton(20, 20, ">")){
        iState = (iState+NSTATE + 1) % NSTATE;
        DD_THROW;
    }
    deEndHorizontal(20);
    deStartHorizontal();
    deStatic(100, 20, "Zip:");
    deEdit(www - 100, 20, &sZip);
    deEndHorizontal(20);
    deStartHorizontal();
    P(gx += 100);
    if (deButton((www-100)/2, 20, "Set Address")){
        SetAddress();
        DD_THROW;
    }
    if (deButton((www-100)/2, 20, "Clear Address")){
        ClearAddress();
        DD_THROW;
    }
    deEndHorizontal(20);
    P((gx = www, gy = gy0));
    deStatic(P(Width() - gx), 20*5, (sWholeAddress != "" ? sWholeAddress : "No address set."));
}

追加:

これは、約40行のコードで入院患者の配列を編集するためのサンプルコードです。1〜6行目は「データベース」を定義しています。10〜23行目は、UIの全体的な内容を定義しています。30〜48行目は、1人の患者の記録を編集するためのコントロールを定義しています。プログラムの形式は、ディスプレイを一度作成するだけであるかのように、時間内にイベントをほとんど通知しないことに注意してください。次に、サブジェクトが追加または削除されたり、その他の構造上の変更が行われた場合、DEによって増分更新が代わりに行われることを除いて、最初から再作成されたかのように、サブジェクトが単純に再実行されます。利点は、UIの増分更新を実行するために、プログラマーが注意を払ったりコードを記述したりする必要がなく、正しいことが保証されることです。この再実行はパフォーマンスの問題に見えるかもしれませんが、そうではありません。

1  class Patient {public:
2    String name;
3    double age;
4    bool smoker; // smoker only relevant if age >= 50
5  };
6  vector< Patient* > patients;

10 void deContents(){ int i;
11   // First, have a label
12   deLabel(200, 20, “Patient name, age, smoker:”);
13   // For each patient, have a row of controls
14   FOR(i=0, i<patients.Count(), i++)
15     deEditOnePatient( P( patients[i] ) );
16   END
17   // Have a button to add a patient
18   if (deButton(50, 20, “Add”)){
19     // When the button is clicked add the patient
20     patients.Add(new Patient);
21     DD_THROW;
22   }
23 }

30 void deEditOnePatient(Patient* p){
31   // Determine field widths
32   int w = (Width()-50)/3;
33   // Controls are laid out horizontally
34   deStartHorizontal();
35     // Have a button to remove this patient
36     if (deButton(50, 20, “Remove”)){
37       patients.Remove(p);
37       DD_THROW;
39     }
40     // Edit fields for name and age
41     deEdit(w, 20, P(&p->name));
42     deEdit(w, 20, P(&p->age));
43     // If age >= 50 have a checkbox for smoker boolean
44     IF(p->age >= 50)
45       deCheckBox(w, 20, “Smoker?”, P(&p->smoker));
46     END
47   deEndHorizontal(20);
48 }

追加:ブライアンは良い質問をしました、そして私は答えがここの本文に属していると思いました:

@Mike:「if(deButton(50、20、“ Add”)){」ステートメントが実際に何をしているのかわかりません。deButton関数は何をしますか?また、FOR / ENDループは、ある種のマクロなどを使用していますか?–ブライアン。

@Brian:はい、FOR / ENDおよびIFステートメントはマクロです。SourceForgeプロジェクトには完全な実装があります。deButtonはボタンコントロールを維持します。ユーザー入力アクションが発生すると、コードは「制御イベント」モードで実行されます。このモードでは、deButtonが押されたことを検出し、TRUEを返すことで押されたことを示します。したがって、「if(deButton(...)){...アクションコード...}は、クロージャを作成したり、イベントハンドラを記述したりすることなく、アクションコードをボタンにアタッチする方法です。DD_THROWはアクションがアプリケーションデータを変更した可能性があるため、アクションが実行されたときにパスを終了する方法。したがって、ルーチンを介して「制御イベント」パスを続行することは無効です。これをイベントハンドラーの作成と比較すると、それらを作成する手間が省けます。そしてそれはあなたがいくつものコントロールを持つことを可能にします。

追加:申し訳ありませんが、「維持する」という言葉の意味を説明する必要があります。プロシージャが最初に実行されると(SHOWモードで)、deButtonはボタンコントロールを作成し、そのIDをFIFOに記憶します。後続のパス(UPDATEモード)で、deButtonはFIFOからIDを取得し、必要に応じて変更して、FIFOに戻します。ERASEモードでは、FIFOから読み取り、破棄し、元に戻さないため、「ガベージコレクション」が行われます。したがって、deButton呼び出しは、コントロールの存続期間全体を管理し、アプリケーションデータとの一致を維持します。これが、コントロールを「維持する」と私が言う理由です。

4番目のモードはEVENT(またはCONTROL)です。ユーザーが文字を入力するかボタンをクリックすると、そのイベントがキャッチされて記録され、次にdeContentsプロシージャがEVENTモードで実行されます。deButtonはFIFOからボタンコントロールのIDを取得し、これがクリックされたコントロールであるかどうかを尋ねます。そうであった場合は、TRUEを返すため、アクションコードを実行できます。そうでない場合は、FALSEを返します。一方、deEdit(..., &myStringVar)イベントがそのイベントを対象としていたかどうかを検出し、その場合はそれを編集コントロールに渡し、編集コントロールの内容をmyStringVarにコピーします。これと通常のUPDATE処理の間では、myStringVarは常に編集コントロールの内容と等しくなります。それが「バインディング」が行われる方法です。同じ考え方が、スクロールバー、リストボックス、コンボボックス、アプリケーションデータを編集できるあらゆる種類のコントロールにも当てはまります。

これが私のウィキペディア編集へのリンクです:http//en.wikipedia.org/wiki/UserMikeDunlavey / Difex_Article


4
答えに悩まされて申し訳ありませんが、私がこれを正しく理解していれば、基本的に計算をプロセッサに近づけ、出力ハードウェアから遠ざけています。これは、オブジェクトと変数をプログラミングすることで、同じ出力を実現するための最良のマシンコードに非常に簡単に変換できるという考えに多くの株式を投資しているため、信じられないほどの洞察です。コンパイル時にコードを最適化することはできますが、時間に依存するアクションを最適化することはできません。時間依存を拒否し、プリミティブに作業を行わせます!
sova 2010年

2
@Joey:FIFOで実行される制御構造のアイデア、およびジョブキューで実行される並列コルーチンについてお話ししましたが、そこには多くの共通点があります。
Mike Dunlavey 2010

2
差分実行は、react.jsライブラリで使用されるアプローチにどれほど近いのだろうか。
ブライアン

2
@Brian:情報のスキミングから、react.jsはdiff関数を使用して増分更新をブラウザーに送信します。diff関数が実際に差分実行と同じくらい機能するかどうかはわかりません。同様に、任意の変更を処理でき、バインディングを簡素化すると主張しています。それが同じ程度に行われたかどうかはわかりません。とにかく、私はそれが正しい軌道に乗っていると思います。ここにカップルのビデオ。
Mike Dunlavey 2014年

2
@ MikeDunlavey、OpenGL / IMGUIと、モデル、モデルビュー、ビューレイヤーでのリアクティブプログラミングを組み合わせてツールを作成します。私は今、古いスタイルに戻ることは決してありません。あなたのビデオのリンクをありがとう。
cthutu 2018

13

差分実行は、外部イベントに基づいてコードのフローを変更するための戦略です。これは通常、変更を記録するために何らかのデータ構造を操作することによって行われます。これは主にグラフィカルユーザーインターフェイスで使用されますが、変更を既存の「状態」にマージするシリアル化などにも使用されます。

基本的なフローは次のとおりです。

Start loop:
for each element in the datastructure: 
    if element has changed from oldDatastructure:
        copy element from datastructure to oldDatastructure
        execute corresponding subroutine (display the new button in your GUI, for example)
End loop:
Allow the states of the datastructure to change (such as having the user do some input in the GUI)

これの利点はいくつかあります。1つは、変更の実行と、サポートデータの実際の操作を分離することです。これは、複数のプロセッサに適しています。2つ目は、プログラムの変更を伝達する低帯域幅の方法を提供することです。


12

モニターがどのように機能するかを考えてください。

60Hzで更新されます-1秒間に60回。ちらつきちらつきちらつき60回ですが、目が遅くてよくわかりませ。モニターには、出力バッファーにあるものがすべて表示されます。何をしても、このデータを1/60秒ごとにドラッグするだけです。

では、画像がそれほど頻繁に変更されるべきではないのに、なぜプログラムで1秒間に60回バッファ全体を更新する必要があるのでしょうか。画像の1ピクセルのみを変更した場合、バッファ全体を書き換える必要がありますか?


これは基本的な考え方を抽象化したものです。画面に表示する情報に基づいて出力バッファーを変更する必要があります。CPU時間とバッファー書き込み時間をできるだけ節約したいので、次の画面プルのために変更する必要のないバッファーの部分を編集しません。

モニターは、コンピューターおよびロジック(プログラム)から分離されています。画面を更新する速度に関係なく、出力バッファから読み取ります。コンピューターの同期と再描画を不必要に停止する必要があります。これは、さまざまな方法で実行できるバッファーの操作方法を変更することで解決できます。彼の手法は、遅延しているFIFOキューを実装します。これは、バッファに送信したものを保持します。遅延FIFOキューはピクセルデータを保持せず、「形状プリミティブ」を保持します(アプリケーションではピクセルである可能性がありますが、線、長方形、単なる形状であるため描画しやすいものでもかまいません。不要なデータはありません。許可)。

それで、あなたはスクリーンから物を描いたり消したりしたいですか?問題ない。FIFOキューの内容に基づいて、現時点でモニターがどのように見えるかがわかります。目的の出力(新しいプリミティブを消去または描画するため)をFIFOキューと比較し、変更/更新が必要な値のみを変更します。これは、DifferentialEvaluationという名前を付けるステップです。

私がこれに感謝する2つの異なる方法

1つ目: Mike Dunlaveyは、条件文拡張を使用します。FIFOキューには、多くの情報(「前の状態」、またはモニターまたは時間ベースのポーリングデバイス上の現在のもの)が含まれています。これに追加する必要があるのは、次に画面に表示する状態だけです。

FIFOキューにプリミティブを保持できるすべてのスロットに条件付きビットが追加されます。

0 means erase
1 means draw

ただし、以前の状態があります。

Was 0, now 0: don't do anything;
Was 0, now 1: add it to the buffer (draw it);
Was 1, now 1: don't do anything;
Was 1, now 0: erase it from the buffer (erase it from the screen);

これはエレガントです。何かを更新するときに、画面に描画するプリミティブを知るだけでよいからです。この比較により、プリミティブを消去するか、バッファに追加/保持するかがわかります。

2番目: これはほんの一例であり、マイクが実際に得ているのは、すべてのプロジェクトの設計の基本となるものだと思います。最も計算量の多い操作をcomputerbrain-foodとして記述することにより、設計の(計算)複雑さを軽減します。またはあなたが得ることができる限り近く。デバイスの自然なタイミングを尊重します。

画面全体を描画するための再描画方法は非常にコストがかかり、この洞察が非常に価値のある他のアプリケーションがあります。

画面上でオブジェクトを「移動」することはありません。コンピュータモニターのようなもののコードを設計するときに「移動」の物理的動作を模倣しようとすると、「移動」はコストのかかる操作です。代わりに、オブジェクトは基本的にモニターで点滅するだけです。オブジェクトが移動するたびに、新しいプリミティブのセットになり、古いプリミティブのセットがちらつきます。

モニターがバッファーからプルするたびに、次のようなエントリがあります。

Draw bit    primitive_description
0           Rect(0,0,5,5);
1           Circ(0,0,2);
1           Line(0,1,2,5);

オブジェクトが画面(または時間に敏感なポーリングデバイス)と相互作用することはありません。自分だけに固有の変更を表示するためだけに画面全体を更新するように貪欲に要求する場合、オブジェクトよりもインテリジェントに処理できます。

プログラムが生成できるすべての可能なグラフィカルプリミティブのリストがあり、各プリミティブを一連の条件ステートメントに結び付けているとします。

if (iWantGreenCircle && iWantBigCircle && iWantOutlineOnMyCircle) ...

もちろん、これは抽象化であり、実際には、オン/オフになっている特定のプリミティブを表す条件のセットは大きくなる可能性があります(おそらく、すべてtrueと評価される必要がある数百のフラグ)。

プログラムを実行すると、これらすべての条件を評価できるのと基本的に同じ速度で画面に描画できます。(最悪の場合:条件ステートメントの最大セットを評価するのにかかる時間。)

これで、プログラム内のどの状態でも、すべての条件を評価して、画面に出力することができます(形状プリミティブとそれに依存するifステートメントを知っています。)

これは、グラフィックを多用するゲームを購入するようなものです。HDDにインストールしてプロセッサで実行する代わりに、ゲーム全体を保持し、入力(マウス、キーボード)を受け取り、出力(モニター)を受け取る新しいボードを購入します。信じられないほど凝縮された条件付き評価(条件付きの最も基本的な形式は回路基板上の論理ゲートであるため)。これは当然、非常に応答性が高くなりますが、小さな設計変更を行うとボード全体の設計が変更されるため、バグの修正はほとんどサポートされません(「設計」は回路基板の性質からこれまでのところ削除されているため) )。内部でデータを表現する方法の柔軟性と明確さを犠牲にして、コンピューターで「思考」を行わなくなったため、大幅な「応答性」が得られました。 入力に基づく回路基板用。

私が理解しているように、教訓は、システムの各部分(必ずしもコンピューターとモニターだけでなく)にうまくできることを与えるように労働を分割することです。「コンピューター思考」は、オブジェクトのような概念の観点から行うことができます...コンピューターの頭脳は喜んでこれをすべて考え抜いてくれますが、コンピューターに考えさせることができれば、タスクを大幅に簡素化できます。 data_updateおよびconditional_evalsの条件。概念のコードへの人間による抽象化は理想的であり、内部プログラムの描画メソッドの場合は少し過度に理想的です。結果(正しい色の値を持つピクセルの配列)だけが必要で、簡単にできるマシンがある場合 1/60秒ごとに大きな配列を吐き出し、コンピューターの頭脳から花のような思考をできるだけ排除して、本当に欲しいものに集中できるようにします。グラフィカルな更新を(高速の)入力と同期させ、モニターの自然な動作。

これは他のアプリケーションにどのようにマッピングされますか? 他の例も聞きたいのですが、きっとたくさんあると思います。情報の状態へのリアルタイムの「ウィンドウ」(可変状態またはデータベースのようなもの...モニターはディスプレイバッファーへの単なるウィンドウ)を提供するものはすべて、これらの洞察から恩恵を受けることができると思います。


2
++ご理解いただきありがとうございます。私にとっては、当初は低速のデバイス(9600ボーのリモートテキスト端末を考えてください)でプログラム記述の表示を行う試みでした。基本的には、自動差分を実行し、最小限の更新を送信します。それから私はなぜこれをブルートフォースでコーディングしないのかということに迫られました。答え:コードの表面の形が単純なペイントのようである場合、それは短く、ほとんどバグがないため、開発時間のほんの一部で実行されます。(それがDSLの利点だと私は思います。)
Mike Dunlavey 2010年

...解放された開発作業は、より洗練された動的なディスプレイに再投資することができ、ユーザーは応答性と満足感を得ることができます。そのため、開発者の負担に見合うUIの価値が高まります。
Mike Dunlavey 2010年

...例:約10年前のこのアプリ:pharsight.com/products/prod_pts_using_dme.php
Mike Dunlavey 2010年

1
これは私に理解させました...あなたがコンピュータゲームについて話したとき。実際、多くのゲームは、マイクがユーザーインターフェイスを行う方法のようにコーディングされています。フレームごとに循環する更新リスト。
ファルケン教授2015

あなたが言ったことのいくつかに関連しているように見える例は、キー/ボタンが押されているのか、それとも離されたばかりなのかを検出することです。ボタンが押されているかどうかは簡単にわかります。これは、低レベルAPIからの真/偽の値です。キーが押されているかどうかを知るには、以前の状態を知る必要があります。0-> 1の場合は、押されたばかりです。1-> 1の場合は押し続け、1-> 0の場合は、リリースしたばかりです。
Joshua Hedges 2017

3

この概念は、古典的なデジタル電子機器のステートマシンと非常に似ていると思います。特に、以前の出力を覚えているもの。

次の出力が(YOUR CODE HERE)に従って現在の入力と前の出力に依存するマシン。この現在の入力は、前の出力+(USER、INTERACT HERE)に他なりません。

そのようなマシンで表面を埋めると、ユーザーがインタラクティブになり、同時に変更可能なデータのレイヤーを表します。しかし、この段階では、ユーザーの操作を基になるデータに反映するだけで、まだ馬鹿げています。

次に、(YOUR CODE HERE)に従って、表面上のマシンを相互接続し、メモを共有させます。これで、インテリジェントになりました。インタラクティブなコンピューティングシステムになります。

したがって、上記のモデルの2つの場所でロジックを提供する必要があります。残りは機械の設計自体によって処理されます。それはそれについて何が良いかです。


1
これが起こったとき、私はハードウェアモデルを念頭に置いていたのを覚えているようです。
Mike Dunlavey 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.