Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

asqium

A JavaScript Plugin Framework for Extensible Client and Server-side Components

Vasileios Triglianos - vasileios.triglianos@usi.ch
Cesare Pautasso - c.pautasso@ieee.org

Good evening and welcome everybody, my name is Vassilis Triglianos and today we'll talk about architecting plugins to extend the functionality of JavaScript Web Applications. We'll focus on plugins that span both the server and client tier and present a design that we think allieviates some of the burdens pertinent to this task. Let's get to it.
JavaScript has come a long way from a frontend scripting language to a full stack programming language for both server- and client- side.

server svg client
More and more Web apps are written in JavaScript across tiers which results in code reusability, less glue code between different tasks, and a faster developer onboarding process (since they have to learn one Business language for both fronend and backend).

Sometimes we call this Isomorphic JavaScript

We found ourselves in a situation where we wanted to create plugins for such an application. These plugins have both server-side and client-side components which brings a lot of challenges. The most important for us were encapsulation, communication patterns application domain conformance and deployment and pubcliation. And this is what this talk is about.

Motivation
Let me be a bit more specific about motivation for this work and how it came to be.
We were in need of plugins that can span both the frontend and the backend for ASQ. I can see here some people that were in yesterday's Rapid Mashup Challenge. You saw ASQ in action yesterday. ASQ is a research platform offering a Web-based lecture delivery system that aims to provide presenters with awareness of the audience’s comprehension of the presented material.

Put simply, the flow of an ASQ presentation involves presenting slides, posing questions, gathering real time feedback, assess and discussing the results; we call this the ‘present-ask-answer-assess-feedback’ cycle, isn't this a mouthful?.

Questions are an integral part of ASQ, and one of the early design decisions was to allow content authors to create custom question types that can fit into the existing flow and extend it with new functionality, hence the need for a powerful plugin system to make the platform versatile and extensible.

After we present our design we'll see the plugin system in practice as was integrated in ASQ.
Design goals
Challenges
There are a lot of problems to solve and aspects to consider when designing plugin systems and more generally, component architectures. Application Domain Conformance, Encapsulation, Modularity, Communication, Security, Loose Coupling, Deployment and Testability to name a few. Today we will focus on a subset that troubled us the most:
Plugins are a unit of design encapsulation that reflects the structure of the architecture, and thus they should conform to the application domain.

Packing of data and functions into a single component is straightforward to do in Node.js serverside applications using CommonJS style modules, it's not trivial to do in the frontend.
To begin with, the cascading nature of CSS can lead to style bleeding where the appearance of UI elements is unintentionally altered. Methodologies like BEM and SMACSS have been devised to alleviate this problem but the root problem is in the technology itself.
Similarly, Frontend JavaScript suffers from global namespace variable leaks (leaking variable to the global window object or unintentionally overwriting global objects). There have been various attempts to mitigate this. One is t use namespaces. Another is to use anonymous functions in module loaders like CommonJS and AMD (at the cost of precompilation which negates the role of JavaScript as an interpreted language) and again it's a platform problem.

Luckily Web Components came along and made our lifes easier.

Plugin communication in our case can be categorised in four categories. between the backend components of a plugin and the core in the server, between frontend components of a plugin and the core in the client. Inter-plugin between client-side or server-side componentes of different plugins. And finally and maybe more interestingly, intra-plugin between the server and client components of the plugin.

And finally how do make deploying and publishing plugins with components that live both in browser and server painless.
Putting it all together
Of course, some of the problems mentioned before have individual solutions. Here we present the first approach that, to our knowledge, implements a JavaScript based plugin system for the client and the server that offers a unified and integrated solution to all of these problems.
Asqium Architecture
Let's dive into the design of the system.

Lifecycle methods

modelled after Wordpress and Ghost

Backend plugins feature four lifecycle methods. During the install callback, plugins may install dependencies persist bootstraping data and more. The Activate callback loads them in the memory and registers hooks and events, tWe will refer to them shortly. Deacticate is about releasing resources.
One interesting implementation detail that decouples the core from plugins and can isolate runnning plugins in case of failure is the proxy object. A proxy object is a single façade interface between plugin modules and the host system. It exposes the core API to plugins. Each plugin gets instantiated with one from the core.

Backend communication and message passing

Hooks
To implement the first type of communication we use hooks
It's good to go though an example
Frontend

Frontend Web Components

A Frontend plugin in asqium is implemented using Web Components. Custom Elements allows us to register our own HTML Element names which feature a shadow DOM. Shadow DOM can be viewed as a 'private' DOM for our element allowings to seperate structural markup from content and hide the implementation details. Moreover, Shadow DOM allows us to encapsulate CSS styles. HTML template elements, similar to Javascript powered templating languages, allow us to declaratively define HTML code fragments and reuse them. Finaly HTML imports enable us to automatically import HTML pages to our document, as well as their dependencies, akin to script tags with the src attribute set. Missing Web Components functionality can be polyfilled with the webcomponentsjs polyfill library. We use the Polymer library which builds on top of the Web Components technology to add extra functionality like data- binding and declarative element registration.
A typical Web Component defines one or more Custom Elements that encapsulate the User Interface and frontend business logic of the plugin. The plugin subscribes and publishes events to communicate with the rest of the application. Thus, the only dependency between front-end components and the front-end core of the application is the pub/sub implementation which is already present in the form of the EventTarget interface that most DOM Elements implement. Each plugin shares an instance of an EventEmitter like object that allows it to subscribe and publish events. The reason we used an EventEmitter like object instead of using DOM nodes as EventDispatcher objects, is to allow for a uniform interface between server and client. A Web Component can exchange messages with the core or it's coresponding server-side module (through WebSockets). Events generated from plugins should be namespaced with the plugin's name. The choice of WebSockets for plugin communication was dictated by the needs of the ASQ platform as a real-time tool. However it's absolutely acceptable to use AJAX and a RESTful style of communication.

Host application supplies the event bus

var eventBus = new EventEmitter2();

// 'polymer-ready' event is emitted when Web Components load        
document.addEventListener("polymer-ready", function(){

  // This is the only time we use a DOM event for communication
  var event = new CustomEvent(’app-ready’, { ’detail’: {appEventBus :
      eventBus} });
  document.dispatchEvent(event);
});

Plugins register for events

document.addEventListener(’app-ready’, function(evt){

  // we have the event bus, now subscribe to events
  evt.detail.appEventBus.on(’asq:question_type’, onQuestionTypeCb); 
}.bind(this));
It's time for a code snippet to better illustrate how plugins get a hold of their EventEmitter object from the core. The core awaits for all plugins to be ready. This will happen when the polymer-ready event fires. When they are, the core fires a DOM event named 'app-ready' with the EventEmitter (with the name appEventBus) attached to it. Plugins that have subscribed for the 'app-ready' event get notified and can subsequently use the EventEmitter to communicate with the core.

Notice that we used a DOM event to bootstrap the process. This is the one and only time we're using a DOM event for core-plugin communication. Afterwards only the event emitter is used.

Expressiveness vs. Compliance

In order to achieve expressive freedom without sacrificing compliance to domain constraints we think curation (or screening) is an important evaluation process. It follows the models of app stores for mobile devices and it can be performed by a dedicated curator team or directly by the community that consumes the plugins. This allows the core to expose more functionality.
in action
Going back to ASQ, our educational platform that was the motivation for this work, we will see the plugin system in action.

flow

Viewer
Presenter
Here's a typical interaction in ASQ: The presenter has posed a rating question which viewers are invited to answer. As a matter of fact, this is one of the plugin question types we used yesterday at the Rapid Mashup Challenge, where we used ASQ as a voting tool. The second plugin question type is the scoreboard, which I invite you to see it's implementation details during this evening's demo session.
Before asqium, our plugin system, ASQ was structured as follows: There was a Frontend, the backend and persistence layers.

On the serverside there was a, monolithic core, an HTTP server and a Websockets server. For persistence we use two types of stores a MongoDB database to store structured permanent data, and a Redis store to store volatile data that need fast access like session and socket ids.

On the frontend we had the core JavaScript business logic as well as communication layers based on AJAX and WebSockets. Time to introduce our plugin system to ASQ. Serverside we add the hook/events layer and the module plugin components on top of it. This results in a shrinked core. In a similar fashion we add the event middleware layer and the Web Component plugins on top of it on the clientside.
An <asq-highlight> question type plugin
Visibility Modifiers Variable Declarations Other keywords public class C { public void m() { int i = i + 5 + ((int)5.0); } }
What about seeing one of these plugins in action? This an actual question plugin for ASQ. It's name is asq-highlight and allows students to highlight ranges of text. It's styles are nicely encapsulated with the Shadow DOM as is it's structure. Let me show you that it just one tag.

<asq-highlight> template

<template if="{{role == roles.VIEWER}}">
  <asq-highlight-viewer mode="{{mode}}" theme="{{theme}}"
      fontSize="{{fontSize}}">
    <content></content>
  </asq-highlight-viewer>
</template>
<template if="{{role == roles.PRESENTER}}">
  <asq-highlight-presenter mode="{{mode}}" theme="{{theme}}"
      fontSize="{{fontSize}}">
    <content></content>
  </asq-highlight-presenter>
</template>

<asq-highlight> usage

<asq-highlight theme="textmate" mode="java" fontSize="1em">
    <asq-hl-color-task color="d9534f">Visibility Modifiers</asq-hl-color-task>
    <asq-hl-color-task color="428bca">Variable Declarations</asq-hl-color-task>
    <asq-hl-color-task color="f0ad4e">Other keywords</asq-hl-color-task>
    <code>public class C {
  public void m() {
    int i = i + 5 + ((int)5.0) + ((int)5f);
  }
}</code></asq-highlight>
From the enduser's point of view one needs to only specify the tasks with the corresponing color and the text to highlight. You can imagine how easy is to wrap this in a GUI authoring tool to graphically create such type of questions. As a matter of fact we have and feel free to ask me for a demonstration at the demo session.

Persisting an answer to the database

answerSubmission: coroutine(function *answerSubmissionGen (answer){

yield this.asq.db.model("Answer").create({
  question : answer.questionUid,
  answeree : answer.answeree,
  session : answer.session,
  submitDate : Date.now(),
  submission : answer.submission,
});

// this is an asynchronous task. When it's done it's going to send 
// the event shown next
this.calculateProgress(answer.session, ObjectId(questionUid));


//this will be the argument to the next hook
return answer;
}

Send an event to front-end plugin instances

var event = {
  questionType: "asq-highlight",
  type: "progress",
  questionUid: question_id.toString(),
  heatmapData: JSON.stringify(heatmapData)  
}

//use exposed socket API from proxy
this.asq.sendSocketEventToNamespaces(’asq:question_type’, event
, session_id.toString(), ’ctrl’);
Asq-highlight lives in one github repo. The plugin repo is structured as follows: There is the main custom element file, asq-highlight.html, which uses other elements from the elements directory. If we require the module on the backend, node will load index.js which points to lib/asqHighlightPlugin.js.
To use it in a presentation you can install it as a frontend dependency with bower. You also have to add it to the plugins directory in ASQ. ASQ will install dependencies from npm once you activate the plugin.

asqium

A JavaScript Plugin Framework for Extensible Client and Server-side Components

Vasileios Triglianos - vasileios.triglianos@usi.ch
Cesare Pautasso - c.pautasso@ieee.org

Thank you

Join us in this evening's demo!

Thank you for you attention, and you are welcome to join us to the evening's demo where we will recreate a plugin together.
http://asq.inf.usi.ch