What is Solvent-LastMile?
LastMile lets business application developers leverage components and code snippets created by other developers to quickly
compose applications. In other words LastMile helps business application developers solve the application "last-mile" problem, ie how
to quickly create something useful on top of a robust technology stack without getting bugged down in
LastMile is a product meant to allow developers to quickly build business applications. Such applications
typically don't have complicated architecture, just a quick way to glue a set of functionality together.
Note that LastMile is built on top of the ConfigNode product, which it self is built on top of the
Solvent WebApps product platform.
the LastMile documentation only covers topics specific to LastMile. Users should
consult the ConfigNode and Solvent WebApps product documentations for how to use the platform as a whole.
Have ideas, suggests or thoughts? post to the LastMile GitHub repo.
Component Composition Language.
At the heart of LastMile is the notion of a component composition language. This is simply a schema (JSON)
that describes how a given component can be integrated into an application, ie how to compose applications
using the component.
Another way to think of it is that a composition language is a developer workflow definition, ie it specifies
how an application can be created with a component or set of components.
It is a simple yet powerful concept because it allows the developer who knows the component best, to provide
direct guidiance on how to use a component.
Custom Developer Workflow.
A compsition language can be thought of as a specific workflow design for creating an application.
While the underlaying frameworks (Vue/React/Angular..etc), have precise and rigid workflows,
LastMile allows composition language designs to put different spins on how one should use these
frameworks to create applications.
Think of LastMile as a platform that lets a composition
language designer to redefine the target framework (Vue/React/Angular..etc) without requiring the developer
of the given language to rigidly follow the rules of the target framework, yet the resulting code
will conform to the rules of the target framework.
A component developer decides how they wish to design the language for composing their components,
there are no hard-and-fast rules for doing this. Every component set will have a different language that describes
its possible compositions based on what the component does and how it works.
What a composition language should try to do is capture both the workflow and the resulting code artifacts
to produce a given result.
The expectation is that over time, best practices will emerge from the community of component developers and users
for how best to design composition languages.
With a schema based composition language, a developer can turn any combination of code snippets into primitives for compositions
including actual components such as Vue/React/Angular/WebComponents...etc. Any set of code snippets that can
be combined into solid functionality, can be thought of as composition primitives.
For instance a site such as bootsnipp host code snippets, such snippet can serve as primitives for
In order to develop a composition language, a component or snippet developer needs to think
thoroughly about how users will ultimately want to integrate the component. The more comprehensive this analysis is, the
more robust the resulting composition language is likely to be.
In essence as a component or snippet developer, you basically have to think of as many integration scenarious
as possible, and then implement those scenarious with your composition primitives.
This approach is a step or two above an API developer who merely needs to create a robust interface and let
the implementor worry about how they will implement the API. With composition language design,
the component developer needs to go much further into the implementation process. One could
call this forward integration, analogous to a similar process in supply chains.
It means more work for the component developer since they
have to do comprehensive use-case analysis in order to develop a set of composition scenarios, however, the benefit
is a significant productivity boost for every other application developer who wishes to use the component thus making the component much more valuable.
When a component user/developer creates a composition via the aide of a composition language,
the resulting composition would need to be compiled into some resultant code artifact.
Just as there are no hard-and-fast rules for creating composition languages, there are no such rules
for creating compilers. The behaviour of a compiler would be entirely based on the language of course
and it is up to the component developer to implement the compiler.
A compiler can be implemented either as client side logic, maybe via a loader that processes JSON or
it can be server side.
The most crude compiler would be a simple object traversal algorithm that extracts markup from an
object graph and concatenate it to be outputed as HTML.
The more sophisticated the composition language, the more sophisticated the compilation process would be.
Here's a very crude example of the previous composition being compiled into an actual VueJS application.
An apps compilation can be done at request time or it can be integrated as part of a standard
build process, it is up to implementors to decide.
Rapid Application Development Kits.
All the topics discussed so far boil down to a mechnism for Rapid Application Development (RAD).
In this section we'll discuss the idea of RAD Kits, ie the packaging of a schema, its compiler
and other artifacts (code or otherwise) so it can be used for rapid application development
on the LastMile platform.
A RAD Kit is a package made up of the following elements.
- Composition Language
- Composition Language Compiler
- Supporting artificats (code & static assets)
As with the idea of a composition language, there are no hard-n-fast rules for designing RAD Kits,
however based on work that has been done with LastMile, some core ideas seem broadly useful and support for
them has been baked into the platform.
Schema Extensions as described in ConfigNode documentation are an integral part of creating
Node Resolution and Rendering
LastMile is based on an object graph based system, in particular the components that are modelled (ex a Vuetify Toolbar) need
to be rendered into actual code (ie Vue component tag for instance). A RAD Kit developer needs to implement
a resolution algorithm that can render all nodes that make up the application based on their
LastMile object graph representation.
The resolution and rendering approach is up to the RAD Kit developer but the RAD Kits
available in the LastMile repository provide a guide as to how to go about creating
such solutions in LastMile.
Node rendering often may need to be customized as part of a RAD Kit implementation, one example
of where rendering needs to be customized can be seen from the layout differences of applications
in LastMile and the resulting framework code they generate.
For instance in the Repository example of
a Vuetify Tab control implementation, Tab labels are directly specified, there is no extra field
label te represent that data (ie no extra metadata); however the Vuetify code requires tab labels to be syntactically specified
in a way that doesn't match the LastMile layout, a RAD Kit implementation needs to account for this in order to render
Notice in the example below the tab label is specified directly, notice also that the view
of the tab is nested within the tab, this obviously differs from how a tab control is constructed in
the target framework (Vuetify in this case). The composition compiler is responsible for transforming
this object model into correct target framework code.
The easiest RAD Kit implementation is one where the composition language simply mirrors the
underlaying code it generates. Better RAD Kits however are those where the developer creates
a true composition language that is intuitive but may not model the target framework code that will have
to be ultimately generated.
Event handlers during resolution and rendering of object graphs into the target platform artifacts are
the way to customize rendering. It is possible to have event handlers invoked for pretty much every step of a node's
schemaExtension.settings.compilationDirectives is where all callback code is set for
the Vuetify reference implementation RAD Kit. The resolution algorithm will look up
callback code in that field and invoke them if available.
Custom Node Renderers
The Vuetify reference RAD Kit shows an example of core rendering algorithm.
This example also shows how the core rendering algorithm can defer to custom renderers to
override various steps of the rendering process for a node.
In addition to callback calls, certain additional directives can be set.
the compilation routine not to output the nodes named in that list whenever they are present in the current compilation
context, ie even if the field is a renderable node.
the compilation routine not to output node types in that list whenever they are present in the current compilation
context. The node type is either
solvent_object_type taking precedence when both are present.
the compilation routine to output the fields in that list as they are (ie assuming they are strings) whenever they are present in the current compilation
context. For instance a field representing a button's label can be rendered as such during
the compilation of the button node. It could also be custom markup.
LastMile relies on modern component based frameworks such as React/Vue/Angular..etc to form the basis
for RAD Kits. LastMile allows component developers who use these frameworks to create RAD solutions.
The idea of prototyping in this particular context is a way to allow widgets to be turned
into types that can then be used just like any other core component type to build applications.
A widget is basically any composition of components that can be thought of as serving a certain type
of use case. For instance a toolbar that has a search box incorporated into it, where the search box is a separate
component can be tought of as a widget, the composition of these two separate components constitutes
a use case that is rather common.
Prototyping in LastMile is simply a way to generate a schema (ie composition language) from
such implementations so others can reuse and extend the widget for their own applications, ie you
turn the widget into a composite component that can be used like any other component.
The set of application templates for Vuetify are implemented as prototypes. In other words
the application templates are really just a set of components pre-configured (sidebar, toolbar...),
the developer can then customize those initial configurations and of course add more components to
complete the application.