Game On Backbone and Ember

Dus je hebt de uitdaging aangenomen om dik te worden aan de client-kant; goed gedaan. U hebt alle raamwerken bekeken en weet niet zeker welke u moet kiezen? Je bent niet alleen. Lees verder.

Mijn ervaring, bij het leren van de manier om client-side apps te schrijven, blijkt te zijn stijl en hard. Het is niet gemakkelijk om bewust te kiezen voor gebruik MV * op de client voor iemand die JavaScript heeft geschreven, volledig gebaseerd op jQuery en zijn plug-ins. Dit is een geheel nieuw paradigma; het vereist basisvaardigheden voor programmeren en een aanzienlijke kennis van het ontwerp van JavaScript (de taal). Als je ervaring betrekking heeft op de mijne, lees dan verder!

Ik zal de belangrijkste verschillen tussen twee van de meest populaire JavaScript-clientframe-frameworks uitleggen: Backbone.js en Ember.js. Elk van deze tools heeft sterke punten, evenals zwakke punten die u kunnen helpen een meer doordachte keuze te maken.

Disclaimer: als softwareprofessionals moeten we omgaan met diversiteit van meningen. Backbone en Ember zijn resultaten van eigenzinnige en ervaren professionals, zoals jij en ik. Het ene hulpmiddel is niet beter dan het andere; ze dienen gewoon verschillende mensenmassa's en lossen verschillende problemen op. Bedankt Trek voor het gedegen advies.


De filosofie

Backbone is veel gemakkelijker te leren dan Sintel.

Eerst en vooral moet je begrijpen dat Backbone en Ember met name een iets andere drukte dienen. Wat de complexiteit betreft, is Backbone veel gemakkelijker te leren dan Sintel. Er wordt echter wel gezegd dat wanneer je eenmaal de leerling bent, het nauwelijks ingewikkelder wordt. Neem Trek's woord erop. Als je net begint met wat echt JavaScript, dan is Backbone misschien je tool. Als je echter weet dat je veel meer dan alleen een paar eenvoudige use-cases te verwerken hebt, zou je misschien een voorkeur hebben voor Ember.

ruggegraat

Jeremy Ashkenas heeft Backbone gebouwd, dus het zou mogelijk zijn om haal de waarheid uit de DOM. Wat hij hiermee bedoelt, is: wat je ook deed met alleen jQuery / Mootools / Prototype kon en zou beter moeten worden geëxtraheerd in pure JavaScript-structuren - objecten, als je wilt. In plaats van gebruiken DOM elementen om uw zakelijke elementen en gedrag te definiëren, Backbone nodigt u uit om het andersom te doen. JavaScript-objecten zijn de kern en de DOM is slechts een weergave van die gegevens.

Met Backbone heeft u een aantal beweringen:

  1. Gegevens liggen in JavaScript-objecten, niet in de DOM
  2. Gebeurtenisafhandeling ligt in JavaScript-objecten, niet jQuery-gebeurtenisbindingen
  3. De manier waarop u gegevens in een backend-server opslaat, gebeurt via de objecten die de gegevens bevatten

U krijgt volledige controle over de manier waarop u uw app bouwt. Backbone was bedoeld om u een eenvoudige manier te geven om uw modelobjecten te ontwerpen en hoe deze met elkaar omgaan via eventbindingen.

rendering HTML naar de DOM is van je verantwoordelijkheid. U bent vrij om elke sjabloon-engine te kiezen: Moustache, DoT, Handlebars, Underscore, etc. Backbone bevat a Uitzicht prototype dat de verantwoordelijkheid heeft van het articuleren van de DOM en uw JavaScript-kern.

gloeiende sintel

Toen Tilde begon met het bouwen van Ember, deed het dit met een veel uitdagender doel: naar bieden standaardconventies in client-side ontwikkeling, elimineren zo veel boilerplate als mogelijk. Het resultaat is een veel ambitieuzer kader dat streeft naar een voorspelbare architectuur en gestage ontwikkeling.

Ember deelt enkele gemeenschappelijke punten met Backbone in de manier waarop het probeert gegevens en gedrag uit de DOM door uitbreidbare JavaScript-prototypen te bieden, maar dit gebeurt op een heel andere manier dan Backbone.

Sintel staat op:

  1. Bidirectionele gegevensbinding: objecten in Sintel kunnen bindingen tussen elkaar registreren. Op die manier wordt, telkens wanneer een gebonden eigenschap verandert, de andere automatisch bijgewerkt.
  2. Berekende eigenschappen: als u een eigenschap wilt hebben die het resultaat is van een functie, kunt u deze maken en een eigenschap toewijzen zoals berekend door die functie.
  3. Automatische sjabloonupdates: wanneer een object in uw app wordt bijgewerkt, weerspiegelen alle weergaven die op het scherm worden weergegeven en die aan dat object zijn gebonden, automatisch de wijziging, zonder boilerplate.

The DOM - Views

Zowel Backbone als Ember hebben veel voorkomende kernbegrippen, zoals keer bekeken. Ze vertegenwoordigen allebei DOM communicatie, respectievelijk. De manier waarop ze dit concept uitvoeren, is echter iets anders.

Ik gebruik de Todo-use-case voor de onderstaande voorbeelden, geïnspireerd op de TodoMVC-showcase.

ruggegraat

Een Backbone View kan zoiets als dit:

var TaskView = Backbone.View.extend (tagName: "li", sjabloon: "task-template", render: function () // uw code om hier weer te geven., events: "click .mark-done" : "mark_as_done", "change .body": "update_body", mark_as_done: function () / * code hier * /, update_body: function () / * code hier * /);

Dit is gewoon de definitie van uw mening. U moet er een instantiëren als u wilt dat deze op de pagina staat. Zoiets zal het lukken:

var task_view = nieuwe taak (model: task_model); . $ ( "Body") toevoegen (task_view.el);

U ziet dat we een model doorgeven, zodat u een verwijzing kunt houden naar het gegevensobject dat de sjabloon invult. De sjabloon eigenschap in de weergave kan worden gebruikt om een ​​externe sjabloon te bellen, via een ID. Ik heb zoiets in het verleden gebruikt:

var TaskView = Backbone.View.extend (template: "# task-template", render: function () this. $ el.html (Moustache.render ($ (this.template) .html ()), dit. model); // snip);

gloeiende sintel

Ember heeft een andere kijk op meningen. In de conventie wordt zelfs gezegd dat views rechtstreeks met controllers en niet met modellen moeten praten. Dit is een goede gewoonte als u van plan bent om een ​​stabiele architectuur te volgen. Ik zal het voorbeeld voor dezelfde weergave uitleggen:

var TaskView = Ember.View.extend (templateName: "task-template", mark_as_done: function () / * code hier * /, update_body: function () / * code hier * /);

Dat is het. Maar waar zijn al het renderingmateriaal? Wel, Sintel tilt die boilerplate voor je op. Zeg eenvoudig wat de sjabloon is, de controller die het gegevensobject bevat en voeg deze toe aan de DOM.

var task_view = TaskView.create (controller: task_controller // Ember.ObjectController); task_view.append ();

Wanneer u een nieuwe weergave-instantie maakt, wordt de inhoud van de controller gekoppeld (dit kan een Ember.Object of een lijst ervan) in de weergave. Wanneer u besluit de weergave toe te voegen aan de DOM, het zal de sjabloon opzoeken en de gegenereerde markup voor u plaatsen.

gedachten

Backbone is meer expliciet en minder magisch.

Backbone is meer expliciet en minder magisch. Je maakt een Uitzicht, vertel het welke sjabloon je moet gebruiken en hoe, registreer de evenementen en doe wat je moet doen. Zij bezitten de pagina. Dat is een goed begin voor diegenen die een jQuery-achtergrond hebben. Wanneer iets echter moet worden bijgewerkt in de DOM, je zult tegen een boilerplate staan.

Met Ember worden updates automatisch uitgevoerd. U zegt welke sjabloon het is en event-callbacks zijn functies binnen het view-object. Elke keer dat een object wordt bijgewerkt, wordt de pagina automatisch bijgewerkt in de weergave.

Sommige algemene gebeurtenisbindingen zijn ingebouwd in Sintel en andere moeten in de sjabloon worden geplaatst. Het is goed voor degenen die vanuit een back-end perspectief komen, omdat het boilerplate op een aanzienlijke manier vermindert.


De data - modellen

Modellen in Backbone en Ember lijken veel op elkaar. Ze bevatten informatie voor een zakelijke entiteit.

ruggegraat

Een voorbeeld van een Backbone-model ziet er als volgt uit:

var TaskModel = Backbone.Model.extend ();

Met deze eenvoudige regel code heeft u een werkmodel met RUST UITvolledige communicatie ingebouwd. Je krijgt methoden zoals opslaan om de gegevens en halen om het gratis te laden; er is geen plug-in vereist. Validatie is ook ingebouwd in de manier waarop gegevens worden opgeslagen door een bevestigen callback, die een boolean retourneert die aangeeft dat de record moet worden opgeslagen of niet. De implementatie van de validatie is nog steeds voor de ontwikkelaar.

Als u een nieuwe taak wilt maken, maakt u een nieuwe taak TaskModel.

var task = new TaskModel (body: "Mow the lawn", done: false);

Je mag zoveel attributen injecteren als je wilt, omdat de attributenlijst van de taak niet strikt is (denk eraan als schemaless). U kunt nog steeds een instellen defaults eigendom bij verlenging Backbone.Model.

gloeiende sintel

Met Ember zijn er geen modellen, alleen objecten. Het ziet er ongeveer zo uit:

var TaskObject = Ember.Object.extend ();

Net als bij Backbone, moet je uitbreiden van Ember.Object om een ​​objectklasse te maken. Het neemt alle basisfuncties over van een klasse met callbacks voor wanneer deze wordt gewijzigd, gemaakt en vernietigd, naast andere functies. Het heeft echter geen back-endcommunicatie uit de doos. Ember.Data wordt ontwikkeld als een uitbreiding van Ember.Object door het kernteam van Ember om aan die behoefte te voldoen. Het is al bruikbaar, maar niet stabiel voor zover de documentatie het zegt.

Voorwerpen uit de Sintel worden ook beschouwd als te zijn schemaless. Om standaardwaarden in Sintel-objecten te injecteren, verleng je Ember.Object door een object met zoveel attributen door te geven als u wenst.

var TaskObject = Ember.Object.extend (body: "maai het gazon", done: false);

gedachten

Backbone heeft een geconsolideerde manier om te synchroniseren met een persistentielaag RUST UIT en dat is een goede afspraak daar. Het is een ding minder dat u hoeft te configureren om met een backend-server te werken.

Sintel werkt zijn weg naar het maken Ember.Data klaar voor productie gebruik, en het ziet er veelbelovend uit. Desalniettemin maakt de bijzonderheid van voorwerpen uit de Sintel met tweewegsbindingen het gemakkelijk om verbindingen tussen objecten uit te voeren.

Op dit punt in uw meting heeft u een omslagpunt tussen de stabiliteit van Backbone in de communicatie met de backend-server en de bindingen van Ember. Wat het meest belangrijk voor u is, moet uw beslissing bepalen.


De lijm - Controllers

Dit is waar de kaders uit elkaar gaan. Ze hebben een enorme conceptuele kloof over hoe je dingen in je app moet lijmen. Terwijl Backbone ernaar streeft zo eenvoudig en flexibel mogelijk te blijven, offert Ember de codebase-omvang op voor een betere architectuur. Het is echt een afweging.

Waarschuwing: de volgende voorbeelden bevatten geen voorbeelden van HTML-sjablonen.

ruggegraat

Zoals ik al zei, streeft Backbone naar eenvoud die zich omzet in flexibiliteit en deze eigenschappen bereikt precies door het ontbreken van een controllerklasse. Het grootste deel van het werkpaard is verdeeld over views, collecties, modellen en de router (moet u ervoor kiezen om Backbone's te gebruiken router).

Gezien een lijst met taken die moeten worden beheerd, zou het vereisen:

  • EEN Verzameling om de taken op te slaan.
  • EEN Model om de informatie van een taak op te slaan.
  • EEN Uitzicht om de verzameling te vertegenwoordigen.
  • Een ander Uitzicht om elke taak te vertegenwoordigen.
  • EEN router om URL's te beheren.

Het grootste deel van de applicatielogica zal in de views leven, omdat ze modellen verbinden met de DOM. Er is geen duidelijk onderscheid tussen verantwoordelijkheden, omdat het beeld alles doet. Het kan goed zijn voor kleine toepassingen waarvoor geen solide architectuur vereist is.

Om een ​​lijst met taken weer te geven, zou je zoiets als dit krijgen:

Verzameling

var TaskList = Backbone.Collection.extend (model: Task);

Model

var TaskModel = Backbone.Model.extend ();

Keer bekeken

var TaskListView = Backbone.View.extend (render: function () this. $ el.empty (); for (_i = 0, _i < this.collection.length; _i++)  var task = this.collection.models[_i]; this.$el.append(this.renderItem(task));  var tasks = this.$el.html(); this.$el.html(Mustache.to_html(template,  tasks: tasks, no_tasks: !this.collection.length )); , renderItem: function(task)  var view = new Row( model: task ); var el = view.render(); return el.el; , );
var TaskView = Backbone.View.extend (tagName: "tr", render: function () this. $ el.html (M.to_html (template, this.model.attributes)); retourneer dit;);

router

var Router = Backbone.Router.extend (initialize: function () this.tasks = nieuwe TaskList; this.view = nieuwe TaskListView (collection: this.tasks);, routes: "": "tasks_list" ,, tasks_list: function () this.view.render (); $ (". bucket: first"). html (this.view.el);, start: function () Backbone.history.start ( pushState: true, root: "/ tickets /"););

Merk op dat de verzameling geen eigen sjabloon heeft; in plaats daarvan delegeert het naar een enkele taakweergave die wordt weergegeven en toegevoegd aan het uiteindelijke resultaat dat op de pagina wordt geplaatst.

gloeiende sintel

Het aantal klassen dat vereist is om dezelfde setup te hebben is iets groter.

  • Inplaats van een Verzameling, je zou een hebben ArrayController, die heel veel op elkaar lijken.
  • Je zou een extra hebben ObjectController voor het beheren van een enkele taak.
  • Inplaats van een Model, je zou een hebben Voorwerp / DS.Model, die hetzelfde werken.
  • Je zou hetzelfde soort hebben Uitzichts.
  • EEN router is ook verantwoordelijk voor het beheer van URL's.

Je denkt misschien dat de twee frameworks niet te veel van elkaar verschillen. Het is nogal verleidelijk, maar het is niet helemaal waar. Enkele bijzondere verschillen zijn:

  1. De controller is verantwoordelijk voor de interactie met de gegevensobjecten, niet de weergave.
  2. De views zijn verantwoordelijk voor het gebruik van de DOM, niet de controller.
  3. De weergaven communiceren met de controller, niet rechtstreeks met de gegevensobjecten.
  4. De gegevens die de weergavesjabloon voeden, zijn in feite bindend voor de gegevens van de controller.
  5. De router is meer een staatsmanager, wat veel meer inhoudt dan het verwerken van URL's.

De scheiding van zorgen is goed op de lange termijn. Controller verwerkt gegevens, views verwerken de DOM, periode. Dit soort ontkoppeld en samenhangend, ketelvrij ontwerp maakt een meer gerichte testbaarheid mogelijk.

De implementatie om dezelfde lijst met taken weer te geven zou ongeveer het volgende zijn, gezien een volledige Ember-applicatie:

Application root-architectuur

window.App = Ember.Application.create (); App.ApplicationController = Ember.ObjectController.extend (); App.ApplicationView = Ember.View.extend (templateName: "application");

Voorwerp

App.Task = Ember.Object.extend ();

Controllers

App.TasksController = Ember.ArrayController.extend (content: []);

Uitzicht

App.TasksView = Ember.View.extend (templateName: "my-list");

router

App.Router = Ember.Router.extend (root: Ember.Route.extend (index: Em.Route.extend (route: '/', connectOutlets: function (router) router.get ('applicationController') .connectOutlet ('tasks');));

In het geval van Ember wordt er niet veel gezegd over hoe dingen binnen worden gedaan. Al dat overzicht is weggenomen, zodat je je kunt concentreren op wat echt belangrijk is in je app: je definieert een taakobject, een takenlijstcontroller met een array genaamd inhoud, jouw mening en de router combineert ze eenvoudigweg allemaal en plaatst het op de pagina.

gedachten

Nadat het zich heeft gerealiseerd hoe Ember echt werkt, begint het bevrijdend te worden.

Het is te verwachten dat dit segment het moeilijkst te begrijpen was voor beide raamwerken. Backbone was beslist gemakkelijker om te leren en zijn flexibele karakter geeft controle over de manier waarop objecten en DOM interageren. Dit kan goed voor u zijn, als u echt die flexibiliteit nodig hebt maar toch een structuur wilt behouden voor de logica van uw app in JavaScript.

Wat betreft Ember, zijn adembenemende implementatie kan in het begin eng zijn. Maar nadat het zich heeft gerealiseerd hoe Ember echt werkt, begint het bevrijdend te worden. Alle conventies die het raamwerk voor u instelt, ontheft u van boilerplate en configuratie, zodat u zich op uw app kunt concentreren. Dit is vergelijkbaar met wat Rails deed voor de ontwikkeling van serverside die zoveel aandacht trok.


Wat onderscheidt ze?

Ember was bedoeld om de gemeenschappelijke last van JavaScript-ontwikkeling in de browser op te heffen.

Tot nu toe is het hele punt van het tonen van de twee gereedschappen geweest om hun enige en nobele doel te erkennen: delegeren macht aan de client-kant, door zowel structuur en methode.

Backbone kernsterkte is absoluut de KISS-aanpak. Het biedt je het minimum om het te laten gaan DOM als de belangrijkste supporter van uw app en begin met het gebruik van echte JavaScript-objecten die op de juiste manier kunnen worden getest en ontworpen.

Backbone zit boordevol collecties, modellen, views en de router, naast andere kleine hulpprogramma's. Je bent vrij om te doen wat je wilt.

Ember daarentegen is gebouwd met een andere mindset, omdat het streeft naar een veel conventionelere en meer eigenzinnige manier om webapps te bouwen. Het pakt een aantal veel voorkomende problemen aan, zoals boilerplate, data binding en DOM sjabloneren, zodat je er vanaf het begin geen zorgen over hoeft te maken. Ember was bedoeld om de gemeenschappelijke last van JavaScript-ontwikkeling in de browser op te heffen.

Ember zit boordevol objecten, controllers, automatisch bijgewerkte views, state-machines, bindingen, waarnemers en een router (die ook een state-machine is), allemaal opgeroepen met een goede dosis conventies. Je hebt een architectuur die al is ontworpen en klaar is om te werken zonder de focus te verliezen.


Conclusie

Let op de leemte. Je ervaring en cultureel erfgoed zullen sterk bepalen hoe snel je je bij de klant voegt. Als je bang bent van wat te doen of welke je moet kiezen, dan heb ik een lef voor je geslagen en dat is goed! Wil je een goed antwoord kiezen? Beide.

Het draait allemaal om JavaScript

Als je niet zeker weet hoe zelfs jQuery al zijn magie doet, begin dan met het leren van Backbone. Het is gemakkelijker om te beginnen en de documentatie is doodeenvoudig om te lezen en te begrijpen. Nadat je klaar bent, begin je iets te bouwen. Ga vies. Raadpleeg deze tutorials als u hulp nodig heeft.

Als je nog steeds in het donker bent, lees dan Yehuda Katz's gegevens over hoe JavaScript werkt.

Zodra u een beter beeld krijgt van hoe JavaScript werkt als een taal, krijgt u meer grip hoe de objecten met elkaar omgaan. Als je dat doet, ga je voor Ember. In het begin is het ingewikkelder, maar geef niet op. Begin met het lezen van de documenten en de handleidingen. Je kunt het blogbericht van Trek Glowacki bekijken voordat je je handen vies maakt.

Mijn bottom line

Persoonlijk leun ik naar Ember; Ik geniet van de robuustheid op macro-schaal, en ik geef ook de voorkeur aan conventies. Backbone is een eenvoudiger en gemakkelijker hulpmiddel voor kleinere apps of kleine functies in een bestaande app.

Ik ben nog steeds allebei aan het leren en heb een paar uitdagingen om aan te pakken:

  • Automatische tests: hoe ze te doen en welke testreeks beter is. Qunit of Jasmine? Headless (denken PhantomJS), Node of browser test runner? Nog niet zeker.
  • Bestand uploaden
  • internationalisering

Wat zijn uw gedachten over dit hele debacle? Heb je uitdagingen in gedachten? Eventuele moeilijkheden of belemmeringen? Laat het me weten!