Components 2020 aka ECS
I have just realized there is an “Entity component system” architecture in full swing these days. I very often use gaming development as proof something works or does not work in reality.
To me, ECS is very encouraging proof that the best application architectures are constantly repeating the same overarching theme: Components. Often independently of each other.
Then I remembered I did this Java Script component-based idea 10 years ago, Interesting. Read on.
[2010 JAN 17]
Is there anything like a “pure object run-time environment”? (For some reason we use the acronym “OO” when we mean that.) Since “primordial” OO, we have come to understand that OO run-time should consists (basically) of objects which are sending messages to each other. And nothing else.
Objects + Messages = OO
The “small” side issue is that since then, no one has yet come up with a consistent and universal definition of these. Therefore we still have no general consensus on what is the “object” and what is the “message”. Also, we have realized there is an infinite number of infinite levels on which this “fuzzy” architecture indeed exists and repeats itself. Like a Mandelbrot pattern of the software universe. Objects and messages, objects and messages, objects and messages … ad infinitum.
Back to reality. I can actually not remember seeing anywhere, “clean-cut” run time environment, which implements this simple architecture? The run-time environment where there are only objects and messages. Something like this :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// there is only one way of creating objects // "name" is the only mandatory key-value var person = create_object('{ "name" : "person", "ssid" : "jzxc.0234" }') ; // each object has only one method : answer ( message, callback ) // that takes the message and a callback for asynchronously returning the result person.answer("what is your name?", callback ) ; // callback has only one argument : data function callback ( data ) { // here we use the data returned // perhaps calling another object var page = create_object("page") ; page.answer( "alert " + data ) ; // no callback used, it is an optional argument } |
No methods, no properties. Just messages. And a micro mechanism for receiving (aka “taking”) a message. In case you thought of SmallTalk run-time, this is (at least for me) much cleaner than that obviously.
Now, should we try to “dig deeper” perhaps? I can explain that I will implement this in a JavaScript (as YAL: Yet Another Language ). “Grammar” sketch is this :
1 2 3 4 5 6 |
// run time definition message := JSON string callback := javascript function with a single argument public object := an object with two methods "answer" and "remember" method answer := "answer" ( message, callback ) method remember := "remember" ( JSON string, javascript object ) |
Method remember
is used for object implementations. This is an environment which on the global level uses the above-defined abstractions. Bellow that (enclosures) there is standard JavaScript. There is no communication between closures, besides through a mechanism described. Now, let us see how do we define implementations.
1 2 3 4 5 6 7 8 |
// all normal javascript is hidden in closures // for example ( function () { var myObject = {} ; // object.remember ( "my_object", myObject ) ; // after this myObject is available in runtime environment as named })() ; |
The implementation is made of normal, but all “hidden” JavaScript objects and this “message-based” global-space environment. Calls to the “answer” method are only asynchronous. There are no synchronous calls.
It seems this way, I have actually described a component (global-space) layer inside JavaScript programs. Which is (remember Mandelbrot) the same architectural pattern, found one level above, and the level above it, in the SOA universe. So why do I not redefine all of this as a micro-component JavaScript mechanism?
Not catchy enough
And since “micro-component” is not catchy enough I shall call my micro component: “moment“. (perhaps: micro + component = moment ? ). Ok here we go, then.
Of course, I shall use a JavaScript code to define this. ( this should make it more clear ). I shall also use this opportunity to rename “answer” to “react”. Which is a name, that I think better describes the purpose of the function: ask the object to “re-act” on the message you are sending.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// (c) 2010 by dbj@dbj.org // micro + component = moment // Micro Components application architecture // Moment constructor requires its name and // an object which is moment going to use to "answer" Moment = function ( name, object) { // the only method of the Moment public interface react : function ( json_string, callback ) { // json structure depends on the contract // after which above object argument is implemented // callback is optional // this method is asynchronous } } // eof Moment // next is global mechanism interface // re-create previously remembered methods Moment.recreate = function ( json_string ) { /* implementation */} ; // remember a new Moment Moment.remember = function ( json_string, object ) {/ implementation */} ; |
Implementations required above are not defined here. This is just an application architecture sketch.
Important to understand is that in here, standard JavaScript code is not allowed in the global space. Only inside callbacks, and inside closures. In this scenario, global-space should contain only Moments of exchanging messages. And callbacks inside which application logic gets implemented with standard code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// Moment mechanism usage // First the implementation in a "normal" JavaScript // "dictionary" sample // it is a requirement *not* to have anything global // all is hidden in this closure (function() { var dictionary = { "set": function(k, v) { return this["" + k] = v; }, "get": function(k) { return this["" + k]; } }; // now assign it to its Moment, so we can use it Moment.remember( // json // "name" is mandatory key '{ "name" : "dictionary"}', // the component dictionary); } )(); // eof closure // On the global level we can have only Moments // "name" is mandatory key // compose a json to re create the object we need var dict = Moment.recreate('{"name":"dictionary"}'); // dict is a "moment" and thus // has only one function "react" // messages are json strings dict.react('{"name":"set", "arg" : ["person","Bill"] }') // notice that above call has no optional callback argument // "name" is mandatory key, it is a name of function or property // other keyl's are optional. they can be arguments // here as a call with callback added dict.react('{"name":"get", "arg" : ["person"] }', function(data) { // inside a callback we can have "standard" JavaScript result.innerHTML="<h4>"+data+"</h4>"; } ); |
Remember how we started
searching for a pure “runtime” environment. This prototype is more of a “global-space in javascript applications” but still valid.
It is easy to imagine JavaScript pre-compiler which will enforce these rules and global space Moments.
Work in progress…