Our alphabetically first contender has been around less than a year. Less than a half year, in fact, but it has already garnered quite a lot of attention.
There is a company behind it, &yet (read: and yet). They make development tools, so they say, so one would think Ampersand is their core offering. Unsurprisingly, they put a lot of weight and passion behind it.
The introduction to the framework says:
But we missed the focused simplicity of tiny modules in node-land.
We wanted something similar in style and philosophy, but that fully embraced tiny modules, npm, and browserify.
Ampersand.js is a well-defined approach to combining (get it?) a series of intentionally tiny modules.
I confess I didn’t know what to make of that description. It seemed vague and pointless, especially for mobile developers. The remainder of the documentation is similarly vague or hints at things you would know as a Backbone developer. In essence, **Ampersand wants to be Backbone++. **
Things are wrapped up in small modules that are required using (you guessed it) RequireJS. As a result, there is a lot of code to write, and Ampersand almost flew out of the comparison because of the relatively large code base of the Todo app. (I should mention that I apparently missed the comments in one file.)
Let’s abandon generals and go down to the specifics of the Todo app. Let’s start with the index.html file. Here, we notice that the HTML is complete: it contains all the elements that will eventually show up on the page. What you’ll notice is that the elements that are relevant to the application – the inputs and divs that will change with the data that comes in – have **a “magic” attribute, **data-hook. Personally, I find the name pretty stupid, but the idea of separating application logic from the classes and IDs has some merit. In the documentation, they make it sound like that’s a panacea for development in mixed teams, where one side does the presentation and the other the coding, but I am just guessing that it’s as likely for some web dev to forget the data-hook attribute as to change the name of a class at random. (Note: apparently the web devs create separate templates in Jade that don’t have the data-hook. That is a little confusing.)
First, we note that require allows you to use something akin to import statements, and Ampersand makes full use of that. It buries each functionality into its own tiny file (in the case of this tiny demo, at least) and each module can invoke other ones by requiring them. The main object, app, is for instance started by this sequence:
var MainView = require('./views/main');
var Me = require('./models/me');
var Router = require('./router');
Paths are relative to the module, so there is a directory views under app.js that contains a file named main.js. Similarly, of course, there will be a file me.js in the subdirectory models.
The me.js file is a representation of the internal state of the application, including persistence methods (here handled as session objects). In general (as the name implies) the user’s state is stored. Since we don’t have a logged in user here, it’s just a general storage form for the open window/tab.
The model is completed by two more modules: one is todo, the other todos. One is the single item, the other the collection. The todo item does things that affect only the single item – like get edited, or deleted, or of course created. The collection handles those things that affect all todo items at once, like removing all the completed ones, or reading/storing localStorage.
Ampersand relies a lot on the observer pattern for items to receive notification of changes in the model. Some frameworks poopoo the approach, blaming it for everything from global warming to the decline and fall of the Roman empire; but it enables you to do magnificent things. Namely it allows your app to react globally to any changes. For instance, I am not surprised Ampersand doesn’t need extra code to handle the case of declaring an item completed while in Active view mode.
The views are pretty straightforward. We find a series of events handled, then a series of bindings. Finally a set of utility functions.
The last piece of the puzzle, the router, couldn’t be much simpler. Admittedly, this is not a complex application and the only three routes it needs to know about are the view modes of the Todo list: All items, Completed items, Active items.
All in all, an approach that is fairly easy to follow, but relies on more proprietary convention than I’d like.