Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mash / Link Architecture #2

Open
rescribet opened this issue Oct 7, 2019 · 2 comments
Open

Mash / Link Architecture #2

rescribet opened this issue Oct 7, 2019 · 2 comments

Comments

@rescribet
Copy link
Collaborator

rescribet commented Oct 7, 2019

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
Copy link

megoth commented Oct 7, 2019

Is there any text on this?

@rescribet
Copy link
Collaborator Author

rescribet commented Oct 7, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants