ontola / mash

Generic RDF data browser that can be connected to Solid pods
https://ontola-mash.herokuapp.com
3 stars 1 forks source link

Mash / Link Architecture #2

Open rescribet opened 5 years ago

rescribet commented 5 years ago

Mash block diagram

See also https://github.com/ontola/mash/tree/architecture/docs

Application

An application is expected to bring its own bootstrapping code. This generally contains a way to get the app to the browser (e.g. a html file and JS entrypoint) and all the tooling needed to build the app (node modules, webpack config).

When using link-redux, the entrypoint follows a standard pattern of setting up objects needed by the app (e.g. intl, helmet, stlyling) and mounting via ReactDOM.render.

This is also when the LinkedRenderStore is set up and configured for usage.

The mash and argu are examples of such applications.

Package

Packages are javascript bundles which can be distributed via various means. When a package is loaded into memory, it can search for window.LRS which exposes the registerModule method. This method accepts a ModuleDescription which most importantly contains an array of views and an array of middlewares.

The code to register packages lives in mash.

Views, View APIs

Views are objects with associated metadata about when they should render. When using link-redux, a view object is a 'React Component', though the LinkedRenderStore is written as a generic one.

All the methods which link-redux provides are declarative, meaning that only information on what should be done is given. This too gives additional freedom to make large changes to the system without breaking existing views. E.g. mounting the LinkedResourceContainer React component with a subject prop will automatically load the resource and mount the appropriate view.

Though it would be possible for application or package code to call the underlying JS functions directly, views lookups should never be done there, but instead by left to the view frameworks (e.g. link-redux). This has a smaller API surface, making future upgrades to lookup logic easier (e.g. adding tags or roles).

Nitty gritty on view registration

Calling registerAll on a LinkedRenderStore instance with an array of ComponentRegistration objects will make them available for rendering (e.g. via resourceComponent etc, though in practice link-redux will manage that for the user).

To make generating the ComponentRegistration objects easier, the static method registerRenderer and the link-redux register function have been added, but they all boil down to generating an array of ComponentRegistration objects which can be indexed by the ComponentStore.

Middleware

Though everything could be done in a view, or even declaratively (especially with a server executing the logic), link provides middleware where common logic can be abstracted to.

Tiny example: solid middleware Medium example: Bookmarks manager

The middleware consists of two parts; the middleware stack and the action creators.

The stack

The middleware stack works like a normal middleware stack, where the event is passed at the top and cascades down each layer until a function resolves to a value. Events are started when calling exec on the LinkedRenderStore, with the first argument being a NamedNode of the action to be executed, and a possible second argument for carrying information which can't be (properly) serialized into an IRI or resource.

Each middleware will catch events which they know how to process and execute some logic which (usually) changes state, after which the application will update.

The action creators

Views can execute any action they want by constructing the appropriate resource and requesting the LinkedRenderStore to execute it, but this can become somewhat tiresome. That's why each middleware can provide convenience functions to help views setup and execute those actions.

For example, the createBookmark action creator takes three arguments (the bookmark list resource, the page to bookmark, and a title). Since this is an easy action (without server logic as well), it serializes the intended action to a single IRI which describes the intended action in full. It then calls the store to dispatch the action.

When the next cycle is ready, the action will be sent through the middleware stack until it hits the create handler in the bookmarks middleware. The middleware calculates a linked delta and asks the system to apply the changes locally, after which it saves the local representation to the pod and resolves the promise with the IRI of the created bookmark.

Ontology

Link-lib contains its own rule based inference engine, the Schema.

Note that even though ontological statements are just data, the LinkedRenderStore exposes a separate method for adding data that should be used to reason with. This was done for performance reasons, mainly to prevent unnecessary view-lookup cache clears when loading a resource. Though this might be enabled by default in a future update.

Sub stores

The layers below the LinkedRenderStore implement most of the logic for the above. The wrapper around rdflib.js, RDFStore tracks changes in the data and is able to process linked-deltas.

megoth commented 5 years ago

Is there any text on this?

rescribet commented 5 years ago

There is issue #1, but the link-lib and link-redux readmes contain most of the architecture text. This is an overview diagram with the most important functions. I can write up an accompanying text tomorrow

@megoth I've added a description

On Mon, Oct 7, 2019, 17:53 Arne Hassel notifications@github.com wrote:

Is there any text on this?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ontola/mash/issues/2?email_source=notifications&email_token=AAJQZU7W7DKHYT7GXTPAZ4TQNNLQ3A5CNFSM4I6CVPOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEAQ3R7A#issuecomment-539080956, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJQZU2LNYGET2FVLCOCOVTQNNLQ3ANCNFSM4I6CVPOA .