leslie-mvp, the Beginning

Friday, May 9th 2014

My friend Philip accuses me of being one of a handful of people that likes Yahoo! User Interface. It’s true and I feel no shame. However, I had to just give up on mojito because it didn’t meet my needs for the Web application that I’m using. So, I decided to write my own dispatcher to make the use of express much easier. In this post, I will write about the influence of mojito on the design of leslie-mvp and the other stuff it does.

Hooking into express.js

leslie-mvp derives a lot of inspiration from mojito for the way that a programmer uses it to hook into the express.js framework. Here’s how you would wire up a simple app with mojito.

1
2
3
4
5
6
7
8
9
10
11
12
var express, mojito, app;
express = require('express');
mojito = require('mojito');

app = express();
mojito.extend(app);

app.use(mojito.middleware());

// Route '/' to the hello.index action
app.get('/', mojito.dispatch('hello.index'));
app.listen(8666);

In leslie-mvp, you would see this.

1
2
3
4
5
6
7
8
9
var express, leslie, app;
express = require('express');
leslie = require('leslie-mvp');

app = express();

// Route '/' to the hello#index action
app.get('/', leslie.bother('hello#index'));
app.listen(8666);

Nearly identical and I like that. This allows me to express my URLs in any way I wish, something I always had a hard time doing in Rails.

Directory structure

mojito is a strongly-opinionated Web application framework based on the well-known MVC architecture. As part of the YUI family of tools, it uses the YUI Global Object module loader to register and discover controllers and models packaged together into units of deployment.

Unlike Rails, which organizes its controllers, views, and models in an app folder separated from one another, mojito keeps related files together in a concept they call a “mojit”, a portmanteau of “module” and “widget”. Each mojit in mojito represents a unit whereas the whole Rails app is the unit. I like this idea.

leslie-mvp follows a convention for its organization similar to mojito.

The following ASCII art shows the difference in the directory structure.

+ «rails app»            + «mojito app»             + «leslie-mvp app»
|                        |                          |
+-+ app/                 +-+ mojits/                +-+ lib/
  |                        |                          |
  +-+ controllers/         +-+ «mojit name»/          +-+ «controller name»/
  |                          |                          |
  +-+ models/                +-+ assets/                +-+ views/
  |                          |                          |
  +-+ views/                 +-+ models/                +-- controller.js
  |                          |
  +-+ public/                +-+ tests/
  |                          |
  +-+ tests/                 +-+ views/
                             |
                             +-- controller.server.js

Convention over configuration for module composition

Rails wins over mojito in this area. With its principle of convention-over-configuration, Rails does what you want it to do after you learn the convention with its autoloading facilities. I think that mojito has a superior organization, though. They just chose a really heavy-handed way to work with that organization.

mojito, has an immensely heavy JSON- or YAML-formatted configuration file named application.json|yml to handle the composition of mojits into an application. You can view a “simple” configuration here. As an alternative to this configuration file, you could create an object at runtime that represents the same configuration and call a dispatch method that would assemble the proposed composition.

For leslie-mvp, I wanted a similar organization for the application modules and a way to compose them. However, I did not want to have to build crazy configurations either in a file or in memory. So, I use a very simple method that you will see explained in the last section.

Single context to handle request

mojito introduces the ActionContext as a way to unify the request and response for a controller. leslie-mvp has that, as well.

In contrast, mojito uses a plug-in pattern to decorate the instance of the ActionContext passed to the controller for each request. leslie-mvp provides a callback to decorate what I call “the scene”.

Moreover, ActionContext provides a method done that indicates that the controller has finished its work and mojito should render a view. Unfortunately, the structure of the done method really limits the use of mojito to do anything more than serve content in ‘text/html’, ‘application/json’, and ‘text/xml’ formats.

leslie-mvp has a variety of methods on “the scene” to provide different access to the response stream.

scene.stage
This method acts like the done method in mojito by passing information onto the view for rendering. It also allows the controller to invoke other modules and uses that output in its rendering, as well.
scene.cut
This method indicates that an error occurred.
scene.block
This method provides a redirect, something that mojito has a really hard time doing.
scene.run
This method provides a way to send a file back to the requestor

Invoking other modules with scene.stage

The idea of composite modules really makes a lot of sense to me and I saw the kernel of greatness in the way that mojito approached the subject.

Too much overhead in mojito’s implementation

mojito has the concept of composite mojits. To configure one, you could define it in your application.json file. In this example, we see a ParentMojit associated to two children mojits, SonMojit and DaughterMojit.

{
  "specs": {
    "parent_mojit": {
      "type": "ParentMojit",
      "config": {
        "children": {
          "son": { "type": "SonMojit" },
          "daughter": { "type": "DaughterMojit" }
        }
      }
    }
  }
}

In the mojit controller, you would need to make sure that you mixin the composite addon for the ActionContext and invoke the done method of the mixin. Notice that we have to know that ParentMojit is meant to be a composite mojit (as we declared in the configuration), but we don’t know the children, here.

1
2
3
4
5
6
7
8
9
YUI.add('ParentMojit', function(Y, NAME) {
Y.namespace('mojito.controllers')[NAME] = {
index: function(ac) {
ac.composite.done({
title: "Statistics for YUI"
});
}
};
}, '0.0.1', {requires: ['mojito','mojito-composite-addon']});

Then, in the view for the ParentMojit, you would have something like this. Again, the view knows not only that the mojit has children, but also the names of the children from the configuration file, “son” and “daughter”.

1
2
3
4
5
6
7
8
9
10
11
12
13

<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
{{{son}}}
<hr>
{{{daughter}}}
</body>
</html>

This scheme disassociates the associations of the of the mojits while increasing rigidity in its definitions. This represents (probably) my largest gripe about mojito.

Getting explicit with leslie-mvp

As mentioned before, leslie-mvp doesn’t have all of that configuration. Instead, it just relies on the programmer to specify the other modules that she may want to invoke during the invocation of a module. Here’s the controller for a leslie-mvp module that does the same thing as the mojito example.

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
get: function (scene) {
var data, controllers;

data = { title: 'Statistics for leslie-mvp' };
controllers = {
son: 'son',
daughter: 'daughter'
};

scene.stage(data, controllers);
}
};

The view is the same.

1
2
3
4
5
6
7
8
9
10
11
12
13

<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
{{{son}}}
<hr>
{{{daughter}}}
</body>
</html>

Still in progress

I also like the mojit-specific assets found in mojito where a mojit carries around its own javascripts, css, images, and the like. I figure I’ll provide a helper for that with the leslie object and the scene‘s’ methods.

mojito also has this dream of working in the browser and on the server. I like this idea, too, but don’t know how useful I really find it. Nevertheless, I may try to steer it toward this.

Finally, I am not completely keen on the way that leslie discovers templates for rendering. Right now, leslie looks for a template with the same name as the method. Because I like the compiled Handlebars template concept, I think I could concat them into a single file and use it. It would move me toward an isomorphic library more quickly.

Finally, I question whether leslie really needs to know about a templating engine other than Handlebars. If someone doesn’t want to use leslie for their application because they must use jade, then I think they should find a nice toolkit that supports jade. (I really like jade. This is not poking fun at jade.)

In a couple of days, I plan on showing you the Todo List using leslie-mvp.