📜 ⬆️ ⬇️

Universal data container

In the past 5 years, I have, for the most part, been dealing with Magento-based applications, which are based on ideas of maximum flexibility, extensibility and adaptability. The popularity of Magento in e-commerce and the number of third-party extensions to it indicate that this platform and the ideas implemented in it are more successful than vice versa. The basis of a large number of objects in Magento is the concept of a universal data container ( Varien_Object in Magento 1 and \ Magento \ Framework \ DataObject in Magento 2). I find in such universal containers certain parallels with such phenomena asWell, in the end - with Harvard computer architecture , developed by Howard Aiken in the 1930s.

What is a "universal data container"?

This is a common associative array, a map (map) in which some data correspond to each key, including other associative arrays. The container thus contains a data tree with one entry point and no closed contours (a highly desirable condition). Something like:
$customer = ['Id' => 21, 'Name' => 'Janis Zarinsh']; $order = ['Id' => 32, 'Amount' => 43.32, 'Currency' => 'EUR']; $data = []; $data['Customer'] = $customer; $data['SaleOrder'] = $order; 
Any "leaf" of a tree or part of a tree (subtree) is addressed "by" - listing all the keys on the way to the goal:
  $orderId = $data['SaleOrder']['Id']; 
In PHP using magic methods you can do the same thing like this:
  $customer = new DataObject(['Id' => 21, 'Name' => 'Janis Zarinsh']); $order = new DataObject(['Id' => 32, 'Amount' => 43.32]); $order->setCurrency('EUR'); $data = new DataObject(); $data->setCustomer($customer); $data->setSaleOrder($order); 
Addressing in a more familiar form (as the path to the file in * nix):
  $orderId = $data->getData('/SaleOrder/Id'); 
What do we have as a result? Container for transferring any data. A description of PHP by a developer of objects similar to POJOs in Java is reduced to annotating their accessors (get / set methods) so that you can use auto-completion in the IDE. You can do the same thing through the @property annotation, it will be even slightly shorter (although it will require another implementation of DataObject, via get, set), but it’s more convenient for me like this:
 /** * @method array getBaseCalcData() * @method void setBaseCalcData(array $data) * @method array getDependentCalcData() * @method void setDependentCalcData(array $data) */ class GetForDependentCalc extends DataObject {} 
As the author of this object, I determined the properties that I use for my own purposes. A universal container will transfer the data I use from one data handler to another (for example, from one of my services to another of my services) and absolutely will not mind if other data will be added to it (for example, by any extension written completely). another developer). Moreover, you can "teach" a universal container to automatically convert the data stored in it into a format, for example, JSON, and transfer this data from the server side to the browser. Together with my data, the container also converts the data prepared by third-party extension of my code on the server side and used by third-party extension of my code on the client side. In some way, a universal data container contradicts the object-oriented paradigm, separating in the application pure data objects and objects handlers. But this is, rather, not a contradiction, but a boundary case of the use of OOP — like a POJO. A universal data container can coexist with OOP as well as RDBMS - after all, after all, RDBMS is also a kind of “universal data container”. Theoretically, any database can be placed in an associative array (if we are talking about data, and not about handlers, a trigger / procedure / function).

"Why do we need all this tuning in the zoo?"

Extensibility

Magento, in addition to its main purpose as a platform for creating online stores, is also an environment for creating extensions of its basic functionality. There are a great many plug-ins to Magento - simple and complex, free and commercial (some of which are very expensive). And the universal data container is the basic concept in its architecture. Truth in Magento, it is mainly used as the core for building most of the rest of the system’s components (parent class), and is not “purely data”. Nevertheless, Magento owes its extensibility not to the last to him. Such an approach can be useful in any platforms that imply openness to the creation of extensions for them by third-party developers.

"Far Space"

What combines any application is that they all process the data. As a rule, data is stored in the database, retrieved from it and placed back by a layer of business logic, transformed to be presented in a user-friendly form at the UI level, and there they are received from the user and transformed into a form suitable for processing and subsequent storage. Sometimes, and in web applications, almost always, data is transferred from one "universe" (server layer of business logic, for example, in PHP) to another "universe" (client presentation layer in JavaScript). And on this journey, as a rule, only data is sent - in the form of JSON / XML / ... All the functionality remains in place, it is simply not applicable in the "other universe". A universal data container of the "universe A" (PHP) can convert its data into transcode (for example, JSON) and send them to the "universe B" (JavaScript), or convert to another transcode (for example, XML) and send data to the "universe C" (for example, SOAP-service in Java). Or "B" can first convert and send data to "C", then get a response from "C", process and send to "A", and "A", if necessary, can turn to "C" itself. The most important thing is that the universal container of each "universe" can parse and generate a transcode (JSON / XML / YAML / ...), adapting to its runtime environment not only the data that the developer of the application itself ("A") put into it, but also additional data that the service ("C") or client ("B") developers attached to the "parcel".

Flexible pipelining

Functions allow you to specify a set of arguments, but the result is usually returned as the only one:
 function tooManyArgs($arg1, $arg2, $arg3) {} 
If you limit the number of input arguments to the processor function to one single argument (as well as the result of the function’s operation):
 function oneArgOnly($data) {} 
then you can get very interesting consequences in the form of chains of processor functions, where the output of some functions are input data for others. An example of the practical application of this approach is the promise in JavaScript:
 httpGet(...) .then(...) .then(...) .then(...) 
In PHP, a handler pipeline could look something like this:
 function proc5(DataObject $arg) { $result = new DataObject(); $customer = $arg->getData('/Customer'); $order = $arg->getData('/SaleOrder'); // ... $result->setData('/Transaction', $trans); return $result; } function proc6(DataObject $arg) { $result = new DataObject(); $transaction = $arg->getData('/Transaction'); // ... $result->setData('/Balance', $balance); return $result; } $res5 = proc5($data); $res6 = proc6($res1); $amount = $res6->getData('/Balance/Amount'); 
It is possible from a set of similar processor functions at a descriptive level to build a data processing flow:
 <workflow> <step id="5"> <handler id="proc5"> <input> <map as="/Customer"> <handler>proc3</handler> <result/> </map> <map as="/SaleOrder"> <handler>proc4</handler> <result/> </map> </input> </handler> </step> <step id="6"> <handler id="proc6"> <input> <map as="/Transaction"> <handler>proc5</handler> <result/> </map> </input> </handler> </step> </workflow> 
and change it depending on the data being processed:
 <workflow> <step id="7"> <case> <condition if="qt"> <left output="proc5">/Balance/Amount</left> <right>0</right> </condition> <then> <handler id="proc7">...</handler> </then> <else> <handler id="proc8">...</handler> </else> </case> </step> </workflow> 
This technique will be, as they say, "a hundred years at lunch," but it has its niche .

Total

From my point of view, Mr. Howard Aiken’s “Harvard Approach” on the separation of code and data can be the basis for a sufficient number of interesting software development solutions. "Will seek!" (c) S. S. Gorbunkov

')

Source: https://habr.com/ru/post/273261/


All Articles