Skip to content

Object-oriented platform for building scalable internet applications with isomorphic web objects and evolving data schemas.

Notifications You must be signed in to change notification settings

mwojnars/schemat

Repository files navigation

Schemat

[... WORK IN PROGRESS ...]

Schemat is an object-oriented platform for building scalable internet applications composed of isomorphic web objects that live "on the web" rather than on a single machine. Web objects can be seamlessly transferred over the network and executed in any local environment (on a client, server, or data node). Network communication is done transparently, between remote instances of the same web object, and without the programmer writing any custom networking code - so the network becomes a truly consistent, unified, distributed execution environment for web objects.

Schemat comes with an internal, NoSQL-like, distributed, schema-aware, object-oriented data store that supports index creation, live schema evolution, object & schema versioning, and more. Web objects are grouped into categories that define their schemas and behavior, and they may derive properties from other objects via prototype-based inheritance.

By introducing isomorphic, network-aware web objects, Schemat extends the traditional object model across the entire distributed application stack -- from database, to server, to client -- in a way that unifies all these local environments. Web object can fully encapsulate a particular web functionality and combine its data model, logic, and presentation in a single, network-native entity. This contrasts with traditional network-agnostic objects which are limited to implementing a part of any given functionality, specifically related to a single isolated environment: either the client, or the server, or the database, but not all three at once.

Schemat is the first software platform that elevates Object-Oriented Programming (OOP) to the network level and brings full expression of the OOP paradigm to the web. Schemat is written in Javascript and Node.js.

Features

Web objects have many useful features that make them suitable for building complex internet applications:

  • The web object has a unique ID that serves as its global identifier across all execution environments (client, server, database), and is assigned when the object is inserted to the database. Optionally, a web object may have a human-readable, plain-text name.

  • Web object has persistent properties (aka attributes or fields) that are automatically serialized and saved in the internal data store. They can take on values of various types, including primitives (strings, numbers, booleans), compound (arrays, maps, records), custom types, JavaScript objects, or references to other web objects. Properties may have default values, or be imputed with imputation functions declared in the property schema.

  • Web object may contain multiple values for a given property, i.e., the same property name can be repeated a number of times in the object, creating a repeated property or multivalued property. Schemat provides a special "plural" syntax (.name$) for accessing an array of all values of a repeated property.

  • Web object may belong to a category that defines its valid properties and their schema, and performs automatic validation of the object's content upon insertion and modification. Categories themselves are web objects (!), so they can be stored in the database, and accessed and modified in the same way as any other web object. The concept of categories can be viewed as a web-level equivalent of OOP classes.

  • Web object may have a corresponding JavaScript class that defines its local methods whenever the object gets instantiated as a local JavaScript object. When the web object is loaded from the database, its corresponding JavaScript class gets attached to it via prototype mechanism, providing local behavior for it. [*remember that JavaScript is a prototypal language, so attaching a class to an object is a matter of setting the object's prototype property with Object.setPrototypeOf(), and this can be done at any point during the object's lifecycle, even after the object has been already instantiated - something not possible in other languages. This trick is needed for lazy loading as described later.]

  • Web object may inherit properties from other web object(s). Typically, inheritance is applied to category objects which are allowed to inherit properties (e.g., schema definitions), from each other. This is a web-level equivalent of JavaScript's prototype-based inheritance, with the important extension that multiple parents can be specified for a given object (multiple inheritance applied to prototypes). Note that Schemat's inheritance is implemented at the level of web objects and does not employ JavaScript's own inheritance mechanism - only in this way it is possible to implement multiple inheritance, which is natively missing in JavaScript.

  • Web object is serializable and transferable. It can be automatically serialized to JSON for storage in the database, transmitted to/from client or between different nodes in a cluster. Importantly, the serialization supports:

    • nested values (arrays and dictionaries in the form of POJO objects) [*POJO stands for Plain Old JavaScript Object.],
    • sub-objects of custom JS classes (the subobject is recreated with a proper class after deserialization),
    • references to other web objects (the reference is replaced with the target object's ID during serialization, and is resolved back into a "stub" when the object is deserialized).
  • Web objects are lazily loaded. If an object references another one, and the target object is not needed immediately, it is instantiated as an empty stub that only remembers its database ID, but is able to load its full content upon explicit request (.load()). The same target object (stub) can be referenced from multiple places, and when it gets loaded, it is loaded once for all referencing objects. The stub object retains its identity when loaded (no replacement with a new instance), meaning all existing references remain valid - there's no need to update references throughout the object graph. This approach enables efficient lazy loading of large networks of interconnected objects while maintaining memory efficiency.

  • When used only for reading, local instances of web objects are created immutable and are cached in the local Registry. In this way, they can be shared and reused across multiple web requests, even those that are served concurrently. The Time-To-Live (TTL) is configured separately for each category.

  • Immutable web objects maintain a property cache, which contains the values of their properties and getters. The calculation of a property is only done once, and the result is reused in all subsequent web requests until the object is evicted from the Registry.

  • Web objects can be versioned. If requested so in the category definition, a version number is assigned to the object upon its creation, to be subsequently incremented with each modification. Optionally, past revisions can be retained, which enables rollbacks to previous versions and inspection of the history of changes.

  • Category objects can be versioned, too, and may retain their older revisions with past schema versions. This allows for gradual schema evolution: schema migrations are applied to objects in a delayed (lazy) and selective manner, without massive rewrites that might cause application downtimes. Whenever requested, an object can migrate its content forward or backward to the newer or older schema version.

  • Web object can be exposed at a particular URL and be accessed from the internet. The URL structure is formed by nesting container objects, in a similar way as files are organized in directories on a local filesystem. The important difference is that Schemat's URL space contains not just static files, but fully-operational objects, which can be interacted with via their URL endpoints. Another difference is that some containers may employ dynamic addressing schemes (the "name" part can be mapped dynamically to/from an object ID), which allows for an unbounded number of objects to be exposed at a given URL prefix.

  • Web object may accept web requests on a number of endpoints and implement handler methods that send responses of any kind: a web page, a serialized object, a file, etc. The endpoint name is appended to the object's URL after double colon (::) to form a complete address (https://...path/to/object::endpoint). If endpoint name is omitted, the request is forwarded to the object's default endpoint (typically ::view). Endpoints in Schemat are web counterparts of regular OOP methods.

  • In a special case, web object may generate an active page as its web response, which is an HTML page with Schemat's startup code embedded in it. This allows client-side code to interact with Schemat directly in the browser: load and modify web objects, save property updates and execute their methods - all in the same way as would be done on a server machine. Typically, the active page may contain a front-end component (like a React.js component) that (re-)renders the page while using some Schemat objects as building blocks, or may display HTML forms whose user-provided data is then reflected in the object's properties.

  • By default, every web object supports the special endpoint ::inspect, which generates a web UI for inspecting this object's content and manually modifying its properties.

  • Web objects of selected categories expose another special endpoint, ::admin, that provides a higher-level administrative interface for performing category-specific actions, like browsing the URL structure of a Site, adding indexes in a Database etc. Like regular methods and properties, the implementation of endpoints may be overridden in subcategories and child objects, so, for instance, the default administrative UI can be replaced with a custom one.

  • Instead of serving pages, the web object may expose a service on a particular endpoint, which is a special type of web handler that has its client-side counterpart automatically generated by Schemat. The server-side and client-side code both use the same method name, and Schemat takes care of binding the proper implementation depending on the current environment (server or client). The call looks like a local method execution, and is redirected to the server-side instance of the same web object. This is Schemat's realization of the remote procedure call (RPC), with the important difference that the call is always related to a particular web object, and it can be executed on the client and server alike, providing isomorphism of the application code.

  • With a few exceptions for system objects, web objects are isomorphic and can be instantiated and executed in every environment: on a client, or a server, without any changes in the code or import statements (the code is isomorphic). This is an important feature that bridges the gap between server- and client-side parts of the application, and allows for a unified development model. For example, isomorphism allows the same React code to be rendered on the server (Server-Side Rendering, or SSR) and in the browser (Client-Side Rendering, or CSR); or, the same validation procedures to be executed on the server when inserting data into the database, and on the client where the data is edited in a web form and the user must be informed about mistakes before the form gets submitted.

About

Object-oriented platform for building scalable internet applications with isomorphic web objects and evolving data schemas.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages