Architecture for Big Backbone Applications
Jorge Dias
Tech lead developer at XING
Jean Carlos Meninno
Frontend developer at XING
The good
old days
Not really
Browser wars
- Incompatible versions
- Global space pollution
- Javascript events in the html
jQuery and others
- Browser inconsistencies abstracted
- Lots of plugins but often incompatible
- Ad-hoc AJAX handling
- Lack of client side templating
MV* – Backbone and friends
- Modular structure
- Communication through events
- Consistent interface to backend
Models and collections
- Restful interface
- Data and presentation are separated
- Lifecycle events
Views
- Easy handling of dom events
- React to model/collection events
History
- Routes handling
- Back button keeps working
- Push state (where available)
- No full page reloads
Others
- Not opinionated
- underscore integration
- jQuery integration
- Fits into existent projects
- Small footprint
Zombies
Not a framework
- Setup your own conventions
- No clear way to structure your app
- Lacks specialized views
- Make your own framework on top
Others
- No controllers
- Mixed concerns between views and models
- Huge routers
The Challenge
Rewrite the whole frontend in 4 months.
Previous version was 1.5 years in development.
The constraints
- Don’t screw up by learning another framework
- Lots of time preassure
- 80% of team was backend
Alternatives Evaluation
- Marionette
- Chaplin
- Thorax
What makes Marionette a good choice?
Clean understandable code
Specialized views
- Layouts
- Region Manager
- Collection/Composite View
- ItemView
Memory and events management
Good bye zombies
Modules
- Application structuring
- Promotes modularity and encapsulation
Controllers
- General purpouse coordinators
Commands
App.commands.setHandler("log:request", function(request){
console.log(request);
});
// Somewhere else
App.execute("log:request", request);
Requests
App.reqres.setHandler("foo", function(bar){
return bar + "-quux";
});
App.request("foo", "baz"); // => returns "baz-quux"
Pub/sub
vent.on("foo", function(){
console.log("foo event");
});
vent.trigger("foo"); // => "foo event" appears in console
App routers
- Router composition
- Router as configuration
Example
someController = {
someMethod: function(){ /*...*/ }
};
Backbone.Marionette.AppRouter.extend({
controller: someController,
appRoutes: {
"foo": "someMethod"
}
});
- User clicks on facet
- View triggers event
- Controller responds updating the search
- User clicks on Profile
- View triggers event
- Controller executes command to navigate
- Profiles app handles the command
- It initializes controller
- Controller requests profile model and renders the views
Data layer
- Models and collections contained in one place
- Events all the way
- Everything is a promise
- Only place that instantiates models/collections
// Inside entities/user
App.reqres.setHandler('user:current:entity', function () {
return currentUser;
});
// Inside users/show/show_controller
// ...
currentUser = App.request('user:current:entity');
// Inside entities/search
App.reqres.setHandler('search:new:entity', function () {
return new Search();
})
// Inside search/new/new_controller
var newSearch = App.request('search:new:entity');
var view = new New.SearchFormView({model: newSearch});
this.layout.mainRegion.show(view)
Core specialized classes
Patterns, patterns and more patterns
Examples
- Dropdowns
- Forms
- Layouts
- Modals
- Tooltips
- etc
Directory structure
- Apps
- Restful structure
- Lib
- Entities
- Templates
Thank you
Cat picture for presentation completeness