赤いアーキテクチャ-複雑で複雑なシステムの赤いヘルプボタン-パート2(10億個のセルがある例)

最初の部分では、 Red Architectureの概念を紹介します。これは、複雑なシステム内のコンポーネント間の相互作用を単純化するアプローチであり、主にクライアントアプリケーションを対象としています。 現在の記事を完全に理解するには、 ここでこの概念を理解する必要があります







最初の部分への最近のコメントの追跡に従って、重要でないタスクを解決するためのRed Architectureの使用を示す完成した例を検討します。



クライアントアプリケーションがあります-テーブルエディター、テーブルシートが表示されます。 ユーザーの画面は非常に大きいため、1,000,000,000(10億)のテーブルセルが含まれています。 表の共同編集の可能性のためにスプレッドシートエディタがクラウドに接続されているという事実により、すべてが複雑になります。そのため、「クラウド内のどこか」の10億個のセルの変更はすぐにユーザーに表示されます。



Red Architectureパターンを使用すると、この機能を簡単かつ高性能で実装できます。



まず、クラスvを少し改良する必要があります



10億個のセルのそれぞれが、受信した各イベントを自分自身とのコンプライアンスをチェックするオプションは適切ではありません。 ハンドラー関数への10億回の呼び出し+ 1つのセルが変更されるたびに10億回のGUIDの比較-これは、ハイエンドユーザーデバイスには多すぎます。



この問題の解決策を検討してください。



これで、クラスvのキー(論理チェーンを識別する)は列挙要素ではなく、文字列になります。 簡潔さと簡単な認識のために、疑似コードで記述します:



class v { // value got from this format string will look like OnCellUpdateForList_List1_Cell_D9 public const string KeyOnCellUpdate = “OnCellUpdateForList_%s_Cell_%s”; }
      
      





実際にフォーマット文字列であるキーを宣言しますか? 実際には、どのような場合でも、セルは表形式シートで何らかの方法で識別される必要があります。 「クラウドから」来たセル更新情報には、シート名(List1)やセルアドレス(D9)など、セルを識別するデータが含まれていると仮定します(そうでなければ、更新するシートでそれを見つける方法は?)。 また、ユーザーの画面に表示される各セルは、それ自体へのパス、つまり同じシート名とそのアドレスを「知っている」と仮定します(そうでない場合、システムに変更が発生したことを通知します。他に何か?)。



次に、 h()メソッドに別の引数を追加する必要があります。 現在、ハンドラーはシステム内のすべてのキーではなく、最初の引数として渡される特定のキーをサブスクライブします。



 class v { // for instance, OnCellUpdateForList_List1_Cell_D9 public const string KeyOnCellUpdate = “OnCellUpdateForList_%s_Cell_%s”; private var handlers = new HashMap<String, List<HandlerMethod> >(); void h(string Key, HandlerMethod h) { handlers[Key] += h; } void Add(string Key, data d) { for_each(handler in handlers[Key]) { handler(Key, d); } } }
      
      





ハンドラーを格納するには、1対多のペアを含むHashMap型のプライベートコレクションを使用します。1つ以上のハンドラーがサブスクライブできる1つのキー。 そして、サブスクライバーによってイベントを「ディスパッチ」するAdd()メソッドでは、このキーにサブスクライブされたハンドラー関数のみを使用します。 潜在的な10億個の要素を持つコンテナの場合、そのようなデータボリュームに適した実装を見つけることは価値があるため、文字列キーを暗黙的に数値ハッシュ値に変換するコレクションであるHashMapを使用します。 10億個の要素の場合、HashMapを使用すると、30を超えない数の比較操作で、バイナリ検索によって目的の要素を見つけることができます。 このようなタスクは、性能の低い機器でもほぼ瞬時に実行されます。



以上です! ここで、Red Architecutreの「インフラストラクチャ」、つまりクラスvの変更が終わりました。 そして、セルの更新を受信して​​表示するロジックを検討し始めることができます。



最初に、更新を受け取るためにセルを登録する必要があります。 セル登録コードは、 OnAppear()メソッドで提供されます。



 class TableCellView { // List and Address are components of identifier for this cell in system (ie GUID consisting of two strings) private const string List; private const string Address; handler void OnEvent(string key, object data) { string thisCellUpdateKey = string.Format( /* format string */ v.OnCellUpdate, /* arguments for format string */ this.List, this.Address); if(key == thisCellUpdateKey) // update content of this cell this.CellContent = data.Content; } // constructor TableCellView(string list, string address) { this.List = list; this.Address = address; } // cell appears on user's screen - register it for receiving events void OnAppear() { string thisCellUpdateKey = string.Format( /* format string */ v.OnCellUpdate, /* arguments for format string */ this.List, this.Address); v.Add(thisCellUpdateKey, OnEvent); } // don't forget to "switch off" the cell from receiving events when cell goes out of user's screen void OnDisappear() { string thisCellUpdateKey = string.Format( /* format string */ v.OnCellUpdate, /* arguments for format string */ this.List, this.Address); vm(thisCellUpdateKey, OnEvent); } }
      
      





OnAppear()メソッドで画面にセルが表示されると、オブジェクトのコンストラクターで生成され、後でこのセルにデータを転送できる形式キー文字列v.OnCellUpdateから派生した一意のキーthisCellUpdateKeyでイベントを受け取るために「登録」します。他のセルで関数ハンドラーを呼び出さずに。



OnEvent()ハンドラーメソッドでは、現在のセルに一致するキーをチェックします(実際、 OnCellUpdateの場合、このチェックは必要ありませんが、ハンドラーで複数のキーを処理できるため、それでも望ましいです)。現在のセルは表示データを更新しますthis.CellContent = data.Content;



次に、セルへのデータの送受信のロジックを検討します



セルの更新に関する情報が、ソケットを介して「クラウド」から送られてきたとします。 この場合、セルへのデータの送受信のロジックは次のようになります。



 class SomeObjectWorkingWithSocket { void socket.OnData(data) { if(data.Action == SocketActions.UpdateCell) { string cellKey = string.Format( /* format string */ v.OnCellUpdate, /* arguments for format string */ data.List, data.Address); v.Add(cellKey, data); // This call for objects which process updates for any of the cells, for instance, caching data objects v.Add(v.OnCellUpdate, data); } } }
      
      





したがって、1回の呼び出し(特定の論理チェーンに適用されないクラスv内のロジックはカウントしません)で、データを受信場所から使用場所に10億の特定のセルに転送しました。 論理チェーン全体には、数行のコードと、この関数に関連付けられているすべてのコードを含む1つのOnCellUpdateキーがあります。



新しい開発者が私たちのチームに来て、彼の最初のタスクが何らかの方法でセルの更新をアニメートすることを想像してください、または、例えば、セルを更新するとき、新しいデータだけでなく、変更の日付/時刻も表示します。

彼にとってどれほど難しいかを理解するために、いくつかの質問に答えてみます。





概略的に、v.OnCellUpdateキーのデータチェーンは次のとおりです。







これは終了する可能性がありますが...タスクが表示されただけでなく、受信したデータをキャッシュするようになりました。 すでに書かれているものを変更する必要がありますか、さらに悪いことに、すべてを書き換える必要がありますか? いや! Red Architectureでは、オブジェクトは互いに完全に無関係です。 タスクが来ました-関数を追加するには、この形式でこのタスクがコードに反映されます-既に書き込まれた内容を変更せずにデータをキャッシュするコードを追加します。 すなわち:



 class db { handler void OnEvent(string key, object data) { if(key == v.OnUpdateCell) // cache updates in db db.Cells.update("content = data.content WHERE list = data.List AND address = data.Address"); } // constructor db() { vh(v.OnUpdateCell, OnEvent); } // destructor ~db() { vm(v.OnUdateCell, OnEvent); } }
      
      





セルの更新に関連付けられたすべてのロジックは、マッピングまたはキャッシュに関係なく、依然としてシンプルであり、v.OnUpdateCellキーによってコード内で識別されます。



2番目の部分、最初の部分をここで読みます3つのパートで、マルチスレッドの問題を解決します。



All Articles