Migrating a large JavaScript project from DOM spaghetti to Backbone.js
ofbrooklyn.com
ofbrooklyn.com
You will still bind to events, you will still manipulate the DOM, you will still do all the manual work.
I really recommend looking at Knockout.js instead.
It really gets rid of all the DOM manipulation code that tends to become so complex and spaghetti like.
How? It provides a declarative language for two-way binding between the UI and the data.
Check out this example: http://jsfiddle.net/FEVbz/
In the HMTL pane, edit the input boxes and watch as the other DOM elements update automagically.
Notice how simple and clean the Javascript code is. All it's doing is initialization and setup. Nothing else. No event binding. No dom manipulation. No spaghetti. No nothing.
Shameless plug:
Here's an article I wrote about why I think Knockout.js is so much better than Backbone.js
Backbone... I just don't get it. It seems like there's too much complexity. I'm mainly a back-end developer, so perhaps it's just me.
Later I discovered Knockout and in 2 hours, I was up and running, and it never got in the way so far.
I can only encourage people to at least try the tutorials, it will be time well spent:
> It seems like there's too much complexity
Backbone helps you to do the things you understand. Knockout let's you do things you don't necessarily understand.
Sometimes black-box approach is OK. Sometimes not.It's not really a "blackbox". It's quite easy to understand and extend too.
For instance, you can create your own custom bindings: http://knockoutjs.com/documentation/custom-bindings.html
This is about the only place where it gets low and dirty and involves you writing DOM manipulation code.
It was much more pleasurable to work with when it was no longer magical.
Then can even be used together (see, e.g., knockback.js which combines Knockout data binding with Backbone) to complement each other.
All you're really complaining about seems to be lack of data binding in Backbone. So you pick your preferred data binding mechanism and plug it in.
For data binding there's tons of alternatives that co-exists nicely with Backbone, including Knockout via Knockback, or Rivets, or any number of modules written specifically to work with Backbone - the choice of data-binding mechanism is orthogonal to the choice of using Backbone or not.
... and it was written in a horribly obnoxious manner. The disclaimer clearly shows you realize they have different purposes. So why the antagonistic tone? If your issue is really as stated that people use Backbone for the wrong things and to highlight the benefits of data binding for views, then address that, instead of writing some inane comparison blasting Backbone for not providing features you the at the end admit isn't its focus.
It's a bit as if I were to review your blog post as musical theatre and then at the end admit I knew all along it was actually a technical blog post but that I'd decided to slate it for lack of singing anyway.
As stated in the disclaimer itself; because people use backbone as if it will help them manage the complexities of creating rich client side UI, when I actually think it's a terrible choice for that.
> If your issue is really as stated that people use Backbone for the wrong things and to highlight the benefits of data binding for views, then address that, instead of writing some inane comparison blasting Backbone for not providing features you the at the end admit isn't its focus.
I want to grab people's attention that they're doing it wrong. It's like when you slap someone in the face to wake them up.
> It's a bit as if I were to review your blog post as musical theatre and then at the end admit I knew all along it was actually a technical blog post but that I'd decided to slate it for lack of singing anyway.
Well, you're evaluating my article as if it was meant to be an objective non-biased review of "pros and cons". It's not. It's an opinionated piece of text that comes from personal frustrations.
Though for the record, I actually respect and admire the author of backbone, after all, he's also the author of coffee-script, which is just awesome.
The components built are FX tiles, trade and order tickets.
I've abused knockout to some rather interesting ends, but I've never attempted to use it for as an in browser MVC setup.
I think of Knockout and Backbone as fulfilling two different purposes.
Dude Backbone only works for trivial examples, and even then, and I mean, even with trivial examples, Backbone is almost useless.
I haven't yet been bitten by Knockout in any bad way.
I disagree. Backbone is a structuring framework; if you can't make it work with bigger projects, you're doing it wrong.
Angular is more of a framework than a library. You have to do everything the Angular way or things will become very difficult. In trying to learn it, I found it quite complex (beyond the basic hello world examples).
I would sell it as a framework to invent your own HTML tags, handles the communication with server and does routing, if needed. The two-way data binding is very very nice, but it feels so natural it not even is a selling point :)
- Knockout's organizational conventions appear inadequate to organizing larger projects, whereas Angular puts its module system right out front
- Yes, Angular definitely has the highest learning curve of any JS framework, but it more than makes up for it in the power, simplicity, composability, and expressiveness of the resulting app code; if it's too difficult for you, stick to something like Knockout or Backbone.
- Oh, and there's no extra hand-waving for data-binding, because Angular uses a much simpler (and in aggregate, more efficient) approach to computing DOM updates
Knockout.js is great to get started at adding interactive UI on a JSON back-end, and I think AngularJS is the natural progression.
Knockout's declarative language is not messy; just verbose.
View part is too much DIY. Seriously, _.template is okay for views with no input and simple updates, but if you have heavy IO views become bloated. Check the wiki, there are 7 "yet another binding plugins". Make default one, and make it an option (view binding can be slow and not needed sometimes).
Another DIY are models relations & nesting. These two additions wouldn't be big for the core, but they could really improve the ecosystem. Now you have to take in mind those third-party plugins people are using for these covering basic gaps.
I haven't created a monolithic backbone application but model relations and nesting could add significant complexity. Adding binding, model relations, and nesting will make backbone look more like Ember which I think they are trying to stay away from.
For developers I suggest to try some of plugins, which are listed on GitHub wiki in the binding section and also take a look at Knockout/Ember/Angular so at least you would know what other frameworks offer.
We're using Backbone for a large project and yes we have to track and dispose of everything manually but it's so small that we can make it do what we want. I will say this, Backbone has made our team better JavaScript developers because it didn't throw the kitchen sink at us. I just hope AngularJS is not Struts on the client side.
Like TodoMVC on steroids :)
https://github.com/angular/peepcode-tunes/commit/87dfa695d99...
Diff stats: 360 additions, 636 deletions, on a total of 628 original lines of JavaScript (app + test code; deletions include redundant lines of template code).
If your time's worth so much, why are you on HN spending time contradicting someone? Saving all your HN-time and writing an article to educate people would give greater value to your time and educate more of humanity...
In trying to learn it, I found it quite complex (beyond the basic hello world examples).
Also, Angular is the only framework where the DOM itself is your template. This cannot be explained, only experienced. :-)
Hey, the same applies to Knockout.
Yes, the declarative syntax is verbose, but the DOM is your template.
For arguments sake, I'm talking an IDE in the model of Eclipse/IntelliJ/Netbeans, not vim/emacs/etc. I'm aware that people have some pretty awesome configurations for such editors, but I'm for the most part extremely happy with IntelliJ.
When the company started, we were full of inexperienced devs with no official programming education/experience. Now we have a team that is more aware of things like design patterns. As such, the newer modules are easier to extend and add new features to, so we anticipate that rewriting entire modules should not be necessary when the newer versions need new features.
So to answer your questions, we are just waiting for the old versions to die, and for somebody to pay enough for a job that we can rebuild the old module from scratch :)
Of course, contributing factors such as time, blah, blah, man power, etc. come into play also. Always things that need to be done, never the time to do them.
I personally use requireJS in a rather large Backbone project, and it works remarkably well.
Yet there have still been those JavaScript developers who insist that it's a good language to use for anything beyond small (that is, a few lines of code) scripts. They go right ahead creating large amounts of extremely unmaintainable code.
I don't think the solution is to extend JavaScript. Realistically, the only sensible thing to do is to discard JavaScript for anything serious. Sure, maybe the language being used instead will compile down to JavaScript and try to fake properly modularity support, for instance, but this should only be a temporary measure.
All I think it would take is for a major player, like Google or Mozilla, to embed a more capable programming language in their browser. Python, for instance. It's has decent support for modularity, and has been proven with very large systems, yet it still offers the benefits of a scripting language.
The situation wouldn't improve over night, but after a few years we'd likely see Python support in the other major browsers, even if it's just the open source ones, and Opera. These days, that'd likely be enough to gain some good traction. Then we'd at least have a viable option for large-scale, client-side scripts within the browser. It'd be a far better situation that what we've got with JavaScript currently.
Also: http://wiki.ecmascript.org/doku.php?id=harmony:modules
Works well.
The reason why you see big .js files is that it's not easy to split your code in a.js and have it include b.js from the server.
(function() { /* your code */})()
I'd argue that's significantly easier than most languages. But still - this can easily be a single bash line in your deploy script, or you can run `make` before copying the files over FTP. It's not easy, it's trivial.Things like "as long as you build them intelligently", "bash", and "deploy script".
So lets assume you have a totally-static website. That involves copying files over e.g. FTP at worst. So you have an FTP application, editing tools, etc. How unlikely is it that either A) the tools don't offer JS minification, or B) you're using flat text editors, and can't find someone who can write `cat /.js > all.js` or apparently the Windows equivalent `copy /b file+file+file all.js` in an executable text file? Then it's a double-click and drag the all.js file over.
Remember, we already have multiple source files which are included everywhere or this wouldn't be a debating point. So your files must be include-able in every page, which are either order-agnostic or must always be in the same order. Either you maintain that by hand, or you run one of those scripts or you use your editing application. Is editing every file by hand easier or harder than a single double-click?
This is such ridiculous FUD, and I'm surprised every time I hear it. Compare the apps built with Backbone section of their site against similar lists of any competing framework. There are some seriously complex apps there. More big ones than any competitor.
Just because a framework is minimal doesn't make it ill suited for large projects. That goes for all frameworks, not just js ones. And yet I see this argument trotted out against minimalist frameworks in every language I work in.
Links, for the curious:
http://backbonejs.org/#examples
The main issue as I see it is that people choose a framework for a project in a short period of time and larger frameworks tend to take time before you see where they shine. I hear people's reason for going with Backbone because it was really the first major MVC out there and because of it's popularity. When I hear why people go with another framework it's because of features - not popularity.
Add on to this whenever I've talked to people or read blogs on systems made with other frameworks the majority of talks on backbone are how to solve problems they encountered while talks about larger frameworks are how to use new features and get more from your code. Maybe it's just because Backbone has been around longer that we've all had more time to find the hardships, I don't know but time will tell.
Is it FUD to say all this? Probably a little, but if we don't have any fear, uncertainty or doubt when taking on a new project then you probably haven't got any idea what you're getting yourself in to.
"Backbone.js is a great example of an abstraction pushed too far. While we initially liked the ease of wire-up, in practice it suffers from the same issues as all such data-bound frameworks from WebForms to client/server tools. We find that it blurs the framework and model too much, forcing either bad architectural decisions or elaborate framework hackery in order to preserve sanity.
As the industry shifted from desktop GUI development to the web, it seemed natural to port the most successful patterns and designs to the new paradigm. After 15 years of trying, we feel that there are still no component-based frameworks that have successfully achieved this. We recommend not attempting to make web development into something that it fundamentally is not. It is time to accept the page and request-based nature of the web, and focus on the frameworks that support - rather than work against - these concepts."
This is diametrically opposed to my experience, and I'm really surprised by the stance of ThoughtWorks on the matter. Hope I'm not doing a disservice by spreading the FUD. My belief is that most of the competing JavaScript frameworks are abstractions (and magic) pushed too far.
I've certainly run into many issues using backbone for moderately sized applications (form workflows, several different types of records, etc) but every time I get myself out of them I gain general javascript knowledge rather than domain specific knowledge about framework xyz. I'd much rather know how to effectively manage memory in javascript than how to use a particular framework.
The point of programming is about creating abstractions, so that you dont have to think in terms of the underlying infrastructure. The higher the level of abstraction, the faster you can code, the faster your output will be and faster the business can progress towards a product.
The question is : Is the end goal of your project a product for a business or a means for you to learn the nitty-gritties of javascript?
At that point the question is whether the troubleshooting, as stated, will teach you about how to solve the problem with javascript in general or framework specific contortions to work around it.
In my current company, we were building a multi page form for registration. It took us ( 2 guys ) a whole of 3 weeks ( with html and css pre built! ) to bring it to a level that is acceptable. I had built the same with angular earlier because I was trying to show that it could be done faster and with lesser code. The guys in management did not accept it because it is still "new". So we spent 3 weeks building this which would have taken around 3-5 days in angular.
I realize this can be a bit complicated, but at some point you'll be wishing you could just turn off an event from firing because it's interfering with a juggling act. This is what that technique is used for.
But any project that reaches a certain scale will tend towards having some unfortunate ties between models that makes a more-than-ordinary transition hard to accomplish. It can be done, but I'm not quite there, and I suspect many other developers aren't either. This one's a stopgap.
Can someone point me toward a good and simple explanation/tutorial?
Backbone is an object-oriented library that can increase maintainability for so-called single-page applications. E.g. it's often used in an architecture which pairs a dynamic web service with static HTML templates, CSS, and JS (no dynamic server-side HTML generation). In this way it is similar to ExtJS/YUI, but generalizes those widget-centric frameworks.
It's not for tightly-scoped JS enhancements.
In terms of patterns, it adheres mainly to the Model-View-Presenter pattern (embodied in the Model class, the HTML template, and the View class respectively). Switching between logical pages in the single-page app is supported by the Router class (which implement the front controller pattern). Data persistence/retrieval is oriented toward RESTful web services (this is customizable) and therefore pairs will with ActiveRecord-based server frameworks like Rails. The separation of concerns it encourages increases testability, and also allows it to pair well with asynchronous module loaders (e.g. RequireJS).
I did have one question regarding redundancy - if I take advantage of something like validation with Backbone, I still need to do the same validation on the server-side for any data that I POST or PUT back to the server since I can't trust what comes from the client. Is the only gain from doing the client-side validation in Backbone the faster feedback to the user without requiring a round-trip to the server?
I'm currently trying to decide between Backbone.js, Angular.js, Ember.js or sticking closer to what I know with a jquery pjax solution.
Thank you!
I would suggest using something like https://github.com/afeld/backbone-nested to enable a.get('foo.bar.foo') so you don't have to a.get('foo').bar.foo and suffer undefined errors.
It shouldn't have to be a library with custom handling of the edge cases like that :|
function get(p, o) {
var parts = p.split('.');
for (var i = 0, l = parts.length; i < l; i++)
if (o.hasOwnProperty(parts[i]))
o = o[parts[i]];
else return undefined;
return o;
}
var o = { a: { b: { c: 1 } } };
console.log(get('a.b.c', o)); // 1
console.log(get('no.way', o)); // undefined
I'd be more likely to reuse something like that because it's already useful in the codebase than bringing on another library.However, I am speaking out of ignorance, as it appears that the library you cite does a lot more than this simple thing: https://github.com/afeld/backbone-nested/blob/master/backbon...
In any case safe lookup methods are very useful!
if(defined jQuery.unknown.propierties)But...
You may find that moving to a higher level, more declarative solution (like Knockout) yields a considerable additional improvement.
Knockout feels more like exoskeleton — it may be very comfortable when you fit in, but as soon as you don't you are in a lot of pain.
As far as letting the file deteriorate to that length, NewsBlur was a side project of mine for two years. That's how long it took, and because I only had 45 minutes at a time (my commute) to work on it, large scale refactors were not a priority.
And it took two years before I realized that NewsBlur would be sticking around and I should care for the code base. It was at that point that I began the process of refactoring the bejeezus out of it.
Admitting that there's a better way to do things is a good first step to become better. To share what you've learned is a sign of being humble.
Granted 8.5k lines is a lot - but I'll bet there are more shocking projects out there than that. (I've seen much worse than that on the server side)
One file with 8500 lines could have easily been avoided with the module pattern either by handrolling it or using various libraries out there like requirejs, commonjs, etc.; backbone is not required.