The Object Network

An Object Property Notification Network

The Object Network is a network of chunks of updating data called "NetObjects".

NetObjects can be linked up into a global mesh through their URLs or UIDs.

A NetObject can observe another NetObject that it links to, and be notified when that one changes.

It can then update its own state, which may in turn notify that state on to any observing peers.

Non-Techie? Read on here.

Quick intro to NetObjects for techies

The NetObject programming model can be used throughout your system. You can create a couple of NetObjects like this:

  const purchase_obj=net_object_new({  |  const total_obj=net_object_new({
    "UID": "123-123",                  |    "UID": "789-789",
    "is": "purchase",                  |    "is": "totaller",
    "price": 1.25,                     |    "purchase": "123-123",
    "quantity": 1                      |  }, total_cb);
  }, purchase_cb);                     |

The second object links to the first object through the 'purchase' property. The 'link' is just the purchase object's UID, not a direct in-memory link.

There are callbacks for each type of object. This callback is called at various points in the lifecycle to allow the object to set its state. It's called on creation, for example. Inside the callback, you can access the properties of the object:

  function total_cb(total_obj){
    const purchase_uid=net_object_get(total_obj, 'purchase');  // "123-123"
  }

Further - and here is the core concept of NetObjects - you can equally well directly access the properties of a linked object:

  function total_cb(total_obj){
    const price   =net_object_get(total_obj, 'purchase.price');        // 1.25
    const quantity=net_object_get(total_obj, 'purchase.quantity');     // 1
    ;              net_object_set(total_obj, 'total', price*quantity); // 1.25
  }

Here, you are "looking right through" the purchase UID link into the target object in a single step.

Doing this also sets up an observation - you get a callback when the target is changed:

  :
    net_object_set(purchase_obj, 'quantity', 3);
  :

This change triggers the callbacks for this and any other observers, allowing them to update in turn. Hence, the total object will always maintain its dependency on the purchase object:

  function total_cb(total_obj){
    const price   =net_object_get(total_obj, 'purchase.price');        // 1.25
    const quantity=net_object_get(total_obj, 'purchase.quantity');     // 3
    ;              net_object_set(total_obj, 'total', price*quantity); // 3.75
  }

And you can even do this across machines, with URLs encoding the links:

   { "UID": "123-123",             { "UID": "789-789",
     "is": "purchase",               "is": "totaller",
     "price": 1.25,         =>       "purchase": "http://purchases/123-123.json",
     "quantity": 3                   "total": 3.75
   }                               }

That's basically it - NetObjects link to each other and observe each other's state.

You can program all the static and dynamic aspects of your system this way.

Why that's such a powerful programming model

This simple mechanism, when used as your base programming model, has many powerful consequences.

Easy to program: all interactions, whether local or remote, can be programmed the same way, in the style of a spreadsheet. This is a high-level programming model which allows you to forget about network interactions, cacheing and cache updates, proxying, data persistence, threading, locking, etc., all of which are all handled under the NetObject interface. Instead, you focus on writing pure application logic, user interfaces, data models, adaptors to other systems and other non-net I/O. You construct the inter-object links and write simple local data dependencies that 'internally animate' the NetObjects. The system's global behaviour then emerges without central control. There are no application boundaries in this approach - just small, self-animated NetObjects that can be mashed up and re-mashed.

Great visibility, interoperability, mashability: if you use NetObjects everywhere, you end up with a 'data fabric' of linked up NetObjects. A single path string can describe a journey through this data fabric, jumping links and servers as it goes. If you access them via HTTP and JSON using JSONView in a browser, you can then just jump around your data estate from server to server, exploring how everything interlinks. A Javascript client using WebSockets would further be able to watch those NetObjects live, as they update. Such a client could render the NetObject mesh onwards from one NetObject as nested sub-blocks, which may be opened or expanded to see more, then jumped in to, etc. Such interlinked and interdependent data will encourage the evolution to stable or common data types. This will then permit many applications to be mashed up out of collections of linked-up data rendered by a generic javascript client that is programmed to understand and allow interaction with those common types. And if a type still isn't recognised by this client, it's just a NetObject dependency mapping away from a type that is.

Fast: NetObjects are naturally distributed amongst peer hosts to form a fine-grained mesh. Such an architecture makes it easy to scale up through distributed and parallel processing and fine-grained cacheing and network optimisation. Each NetObject is inherently self-animated and wrap all the threading and locking code, making massively parallel execution as simple as adding more hosts or processors. This also maps nicely to a microservice approach. And small chunks of data distributed to caches and having their changes pushed can make more efficient use of the network than larger chunks being sent repeatedly in hand-coded messages or being polled for changes. You can also benefit from the classic efficiency characteristics of P2P architectures by taking cache copies from nearer neighbours. Startup time is reduced if a NetObject can get going with the last known cached state of its dependencies. This fine-grained tuning of small NetObjects with different cache lifetimes allows you to build more efficient web pages with a mix and mash of static and dynamic elements.

Robust: NetObjects are highly tolerant of their peers unavailability - small patches of the data fabric can drop out through network or host failure without affecting the rest; everything is done on the basis of the best knowledge of the current peer state - accessed through the latest local cache. NetObjects are autonomous and interact directly, peer-to-peer, so a single individual NetObject can fail while all its peers carry on, or be upgraded without stopping a whole application, since there are no application boundaries.

NetObjects compared with your favourite trendy tech

Dynamic web pages: compose static and dynamic NetObjects into sections of a page rendered both server- and client-side.

Interactive web pages: there's a NetObject representing the user and their actions/forms which have a two-way inter-dependency with server state.

Declarative web pages: many applications can be composed from a mesh of NetObjects of common, stable types, driving a generic Javascript.

Mobile: a generic NetObject browser app can render NetObjects like a browser renders HTML, etc, but allows an experience that's closer to native.

Reactive: objects are interdependent, with automatic dependency handling.

Functional: you write your dependency-satisying callback as a pure transition function from old state to new state.

REST: NetObjects have URLs and are completely RESTful. They add a 'GET' that can continue to return updates to clients and their caches.

Microservices: NetObjects naturally partition into collections that can be hosted together, and, being autonomous, are easy to re-partition.

P2P: NetObjects themselves work P2P so their hosts do too; there are no clients or servers in a NetObject architecture.

CQRS: you create write-side 'intentions' through NetObjects that map to CQRS's commands. The read-side NetObjects then depend on them.

Information-Centric Networking: NetObjects have the same goal of a higher level abstraction for the low-level substrate of data for all applications.

IoT: you can build a physical fabric of interactive and interacting NetObjects representing Things.

AR/VR: NetObjects create a global landscape of linked up interactive data, including users, which is actually an immersive cyberspace.

Notes on the NetObject programming model

Read more

Read more here.

Duncan Cragg, 2015

Contact me and/or subscribe to my blog and/or follow me on Twitter.