The
first part introduces the concept of
Red Architecture - an approach that simplifies the interaction between components in complex systems, and is intended primarily for client applications. For a complete understanding of the current article, you need to get acquainted with this concept
here .

In the footsteps of recent comments on the
first part, we consider a complete example demonstrating the use of Red Architecture for solving a non-trivial task.
')
We have a client application - a table editor, it displays a sheet of a table. The user’s screen is so large that it holds 1,000,000,000 (one billion) table cells. Everything is complicated by the fact that our spreadsheet editor is connected to the cloud so that the table can be edited together, so changes to any of one billion cells “somewhere in the cloud” should be immediately reflected to our user.The Red Architecture pattern allows you to implement this function simply and with high performance.
First of all, we need to slightly improve the class vThe variant, when each of a billion cells checks each received event for compliance with itself, is not appropriate. A billion handler function calls + a billion guid comparisons each time a single cell changes - this is too much even for high-end user devices.
Consider solving this problem.
Now the keys (identifying logical chains) in class
v are not enumeration elements, but strings. For brevity and easy perception,
we will write in pseudocode :
class v {
We declare the key, which in fact is a format string, for what? The point is that in any case the cell should be identified in a certain way on the table sheet. We assume that cell update information coming from the cloud contains data identifying the cell (otherwise, how do we find it in the sheet to update?), Such as the name of the sheet (List1) and the address of the cell (D9). We also assume that each cell displayed on the user's screen also “knows” the path to itself, namely the same sheet name and address (otherwise, it will inform the system that the changes occurred in it, and not in what is another cell?).
Next, we need to add another argument to the
h () method. Now handlers do not subscribe to all keys that are in the system, but to a specific key, which is passed by the first argument:
class v {
To store handlers, we use a private HashMap collection containing one-to-many pairs — one key to which one or more processors can subscribe; and in the
Add () method that “sends” events to subscribers, we use only handler functions subscribed to this key. For a container with a potential billion items, it is worthwhile to find an implementation suitable for this amount of data, so we use HashMap, a collection that implicitly converts string keys to numeric hash values. In the case of a billion elements, HashMap will allow us to find the desired element by binary search in no more than 30 numbers comparison operations. Such a task, even on low-performance equipment, will be performed almost instantly.
That's all! On this change, the “infrastructure” of Red Architecutre, namely class v, is completed. And now we can begin to consider the logic of receiving and displaying the cell update.
First we need to register a cell for receiving the update. The cell registration code is presented in the
OnAppear () method:
class TableCellView {
When a cell appears on the screen in the
OnAppear () method, we “register” it to receive events with the unique key
thisCellUpdateKey , which is formed in the object's constructor and is derived from the format string
v.OnCellUpdate , and which allows later to transfer data to this particular cell, without calling the function handlers in other cells.
And in the
OnEvent () handler method, we check the key for matching the current cell (in fact, in the case of
OnCellUpdate this check is not necessary, but since we can process more than one key in the handler, it is still desirable) and in the case of matching the received key to the key the current cell update the displayed data
this.CellContent = data.Content;Now consider the logic of receiving and transmitting data to a cell.Suppose information about cell update comes to us from the “cloud” through a socket. In this case, the logic of receiving and transmitting data in the cell may look as follows:
class SomeObjectWorkingWithSocket { void socket.OnData(data) { if(data.Action == SocketActions.UpdateCell) { string cellKey = string.Format( v.OnCellUpdate, data.List, data.Address); v.Add(cellKey, data);
Thus, we are just one call (not counting the logic inside the class v, which does not belong to any particular logical chain) transferred data from the place of their receipt - to the place of their use - in one specific cell out of a billion. In the entire logical chain there are only a few lines of code, and one
OnCellUpdate key, which contains all the code associated with this function.
Imagine that a new developer comes to our team, the first task for him is to animate a cell update in some way, or, for example, when updating a cell, display not only new data, but also the date / time of the change.
To understand how hard it will be for him, let's try to answer a few questions:
- How long will it take to find the code that I need to patch to solve this problem? - All the related code will be found instantly, the main thing is to tell the developer to search by the v.OnCellUpdate code.
- How much time will such a task take from a new person in our case? - If it is possible to manage the already existing API for solving display and animation issues, then 1-2 days will definitely be enough.
- How many chances does a new developer have to do something wrong? - A little: the code is simple, it's easy to understand it.
Schematically, the data transfer chain for the v.OnCellUpdate key looks as follows

This could be finished, but ... The task came to us so that we not only displayed, but also cached the incoming data. Do we have to change something in the already written or, worse, rewrite everything? Not! In
Red Architecture, objects are completely unrelated. The task came to us - to add a function, exactly in this form, this task will be reflected in the code - we will add code that caches data without any changes to what is already written. Namely:
class db { handler void OnEvent(string key, object data) { if(key == v.OnUpdateCell)
All the logic associated with the cell update, be it mapping or caching, is still simple and is identified in the code by the key v.OnUpdateCell.
You have read the second part, the first part
here . In
3 parts we solve the problems of multithreading.