Upload
nicolas-carlo
View
292
Download
1
Embed Size (px)
DESCRIPTION
This talk was built in French (for now), at the occasion of Backbone.js Meetup #2 hold in Paris. http://www.meetup.com/backbone-paris/events/189771252 Online presentation : http://metidia.com/talk-enlarge-your-backbone-project/ GitHub source : https://github.com/metidia/talk-enlarge-your-backbone-project
Citation preview
ENLARGE YOURBACKBONE PROJECT
COMMENT ORGANISER SON PROJET DE FAÇON MODULAIRE ?
Présenté par Nicolas CARLO ( ) et Fabien BERNARD ( )@nicoespeon @fabien0102
KIKON EST ?
NICOLAS CARLOVP of Engineering
FABIEN BERNARDCTO
SAYKOIKON FAIT ?
Jeu social sur le thème du vin dans lequel on peutacheter en vrai les bouteilles que l'on produit virtuellement
En HTML 5… ‘‘full-stack JavaScript’’Backbone.js + MarionetteNode.js + MongoDBGrunt, Mocha, Yeoman, …
LES GARS, CE SOIR ON FAIT UN PROTO !- UN MANAGER UN PEU TROP CONFIANT
// Probablement à l'arrache, dans un ̀main.js̀ FTW// Note - pas besoin de routage pour nous donc on fait sans =)$(function() { // (…)
// On prépare nos bouteilles var bottlesModel = Backbone.Model.extend({ ... }); var bottlesCollection = Backbone.Collection.extend({ ... }); var bottlesView = Backbone.View.extend({ ... }); var bottlesCollectionView = Backbone.View.extend({ ... });
// (…)
// Et on initialise tout le monde ! var myBottlesList = new bottlesCollection(); myBottlesList.fetch();
var myBottlesListView = new bottlesCollectionView({
LE LENDEMAIN- AKA THE HANGOVER
$(function() { // (…)
// On prépare nos bouteilles var bottlesModel = Backbone.Model.extend({ ... }); var bottlesCollection = Backbone.Collection.extend({ ... }); var bottlesView = Backbone.View.extend({ ... }); var bottlesCollectionView = Backbone.View.extend({ ... });
// On prépare nos bâtiments var buildingsModel = Backbone.Model.extend({ ... }); var buildingsCollection = Backbone.Collection.extend({ ... }); var buildingsView = Backbone.View.extend({ ... }); var buildingsCollectionView = Backbone.View.extend({ ... });
// On prépare nos cépages var cepagesModel = Backbone.Model.extend({ ... }); var cepagesCollection = Backbone.Collection.extend({ ... });
TIENS, C'EST DRÔLE...parfois ça plante, parfois ça passe…quand j'enlève ce bout de code y'a tout qui plante !je retrouve plus où on a codé cette boite de dialogue ?!faudrait p'têtr qu'on mette des tests unit... oh wait!le soleil se lève dehors =)
IL FAUT S'ORGANISER!
YAKA SÉPARER LESFICHIERS PAR TYPES
CONCRÈTEMENT, ÇA DONNE QUOI ?app/
main.jsmodels/
bottles.jsbuildings.js
collections/views/tests/ (parce-qu'il faut pas déconner non plus)
THE GOOD PARTS =)On y voit plus clair quand même !Les tests sont isolésFacile de trouver des exemples pour cette archi
THE BOF PARTS =/L'achitecture du code ne reflète pas vraiment nos ‘‘modules’’Et mon style, il est pas modulaire mon style ?
Pis faudra pas oublier :
beware la dépendance entre les ‘‘modules’’
LES QUESTIONS À SE POSER- MERCI ADDY OSMANI \O/
A quel point ce module est instantanément ré-utilisable ?Mes modules peuvent-ils exister indépendamment ?Mes modules peuvent-ils être testés indépendamment ?Mon application n'est-elle pas trop étroitement liée ?Si une partie de mon appli fail, est-ce-que tout s'écroule ?
NOTRE SOLUTION(PROPOSÉE)
UN DOSSIER = UN MODULE- ETPICÉTOUT !
app/main.jsmain.lessmodules/
bottles/bottles.jsbottles.lessmodels/collections/views/
bottles.views.composite.jsbottles.views.item.js
templates/tests/
EN PRATIQUELES ÉLÉMENTS DE BOTTLES
// bottles.model.js// Une seule dépendance -> Application Coredefine( [ "app" ], function( app ) {
return Backbone.Model.extend({ ... });
});
// bottles.views.item.js// Une seule dépendance -> Application Coredefine( [ "app" ], function( app ) {
return Backbone.Marionette.ItemView.extend({ ... });
});
EN PRATIQUELE MODULE BOTTLES
// bottles.jsdefine( [ "app",
// Le modèle "bottles/models/bottles",
// Les vues "bottles/views/bottles.views.item"], function( app, Model, ItemView ) {
// Initialise le module avec les méthodes de base. var Bottles = app.module();
// On spécifie nos API Bottles.Model = Model.extend( { ... }); Bottles.Views.Item = ItemView.extend( { ... });
EN PRATIQUELE MAIN.JS
// main.jsdefine( [ "app",
// Les modules "bottles/bottles.js"], function( app, Bottles ) {
// Initialise le module avec les méthodes de base. var myBottlesList = new Bottles.Collection(); myBottlesList.fetch();
var myBottlesListView = new Bottles.Views.Collection( { collection: myBottlesList } ); myBottlesListView.appendTo( "#bottom-bar" );
});
UN MODULE C'EST COMME UN ENFANT- MERCI MONSIEUR ZAKAS \O/
Les modules doivent garder les mains dans leurs pochesOn ne touche pas au DOM des autresOn ne touche pas aux méthodes des autres
Les modules demandent, ils ne prennent pasLes modules ne laissent pas traîner leurs jouets : pas devariables globales, encapsulationLes modules ne parlent pas à des étrangers : on ne parle pasdirectement aux autres modules
NOS OUTILS
REQUIRE.JSGESTION DE DÉPENDANCES + OPTIMIZER AVEC R.JS
Détermine les dépendances de chaque bout de codeRe-compile ces dépendances en un seul fichier JS optimisé
NOM DE CODE BRAIN.JSNOTRE PATTERN MEDIATOR À NOUS
Tour de contrôle des modulesCentralise la communication = découplage des modulesÉcoute les événements intéressants - Backbone.EventTrigger d'autres événements pour déclencher des actions
MARIONETTE.JSENTRE AUTRES UTILITAIRES
Boite à outil indispensable pour gérer des vues de plus en pluscomplexesAbstraction + cache de l'UISimplifier la conf.Enregistrer de requests pour découpler son codeSinon y'a Chaplin aussi si besoin d'aller plus loin
ABSTRACTION + CACHE DE L'UI<div class="builds__menu"> <ul class="builds__menu__tabs"> <li data-ui="tab">Bâtiments</li> <li data-ui="tab">Décorations</li> </ul></div>
<!-- (…) -->
return Backbone.Marionette.ItemView.extend({
ui: { "tab": "[data-ui~=tab]" },
events: { "click @ui.tab": "switchTab" }
// (…)
highlightTabs: function() {
this.ui.tab.each(function() { // Do something awesome! });
SIMPLIFICATION DE LA CONF.return Backbone.Collection.extend({
events: { "click": "displayName" }
appEvents: { "bottles:do:setName": "setName" }
// (…)
initialize: function() { Marionette.bindEntityEvents( this, app, Marionette.getOption( this, "appEvents" ) ); }
setName: function( appellation, name ) {
ENREGISTRER DES REQUESTSreturn Backbone.Collection.extend({
requests: {
getCategories: function() { // Retrieve categories… return categories; }
},
// (…)
initialize: function() { app.reqres.setHandler( "builds:getCategories", this.requests.getCategories, this ); }
// Pendant ce temps, ailleurs dans le code
var buildsCategories = app.request( "builds:getCategories" );
// (…)
AXES D'AMÉLIORATIONAméliorer l'init. des modules dans le mainMultiples Brain.js, parce-que ça grossit viteDifférents ‘‘channels’’ pour les événements
Des suggestions ?