In many ways, I’m a web conservatist, who is very proud of it. It doesn’t mean that I avoid every wave of freshness, but I’m always a little bit sceptic about it – as I was about Angular.js. Sometimes I accept changes and add a new toy to my toolbelt, but sometimes I become one of the thoughest enemies of the new kid on the block. As you have probably already noticed, I didn’t fall in love with the new big thing from Google. And I have my own reasons, which I want to somehow rationalize and sum up (and maybe – like a good Dalek – make someone else also a hater of Angular.js!) – some of them are strictly subjective, some of them try to be objective (or rather intersubjective).

It’s the first (and for me one of the most important) reason why Angular.js is wrong: declarative approach. We all know it well. The hype for „declare all the things” was begun around 1998, when W3C started working on XHTML. At the first glance, it looks promising and refreshing. Is it? I don’t think so.

If I call something a „JS framework”, I expect that it uses JS to accomplish tasks. When I talk about Angular.js, I see not JS, but – as they call it – enhanced HTML. Binding function to some elements? Use [ng-click] attribute. Trying to create button, which should be disabled under specified circumstances? Use [ng-disabled]. Doing something else? Use [ng-whateverYouNeed].

We fought for unobtrusive JSfor years and when I finally became happy that the war is over, mixing JS with HTML came back through back door, using something worse than DOM0 HTML attributes. Yes, [ng-click] is worse than [onclick]. While the latter is native (and, because of that, its’ behaviour is standardised, predictable, probably optimised by browsers and their DOM parsers), the former is just an unkown attribute. And as it, Angular.js is forced to parse the whole DOM tree just to get that attributes and, after doing that, it must parse the attributes themselves. It doesn’t sound funny. What’s more, Angular.js sanitizes that attributes and compile them into JS functions, that have access only to defined scope… So the framework must have some kind of HTML sanitizer & parser and it’s somehow big. And there is also parser to get over templates.

<label>{{ key | camel2Space | capitalizeFirst }}</label>

Templates in HTML? Tempting, but impractical. Yup, I know that there is template tag in Web Components, but it works in very different way. The main difference is that template is used to create a DOM subtree, that it’s not included in main DOM tree. Thanks to that, nothing is visible to user until we decide to show something. Every change is made through DOM methods, because… everything is in DOM. Angular.js’s approach is completely different, as Angular.js treats the page as a template. It’s not elegant. And there are just silent errors, when something went not so well.

Why I found page as template as not elegant? Because page is a view, not a template. And in the ideal world, template shouldn’t depend on DOM. DOM based templates are browser-centric – tight coupling between product and device on the device agnostic Web sounds ridiculous. The situation in Angular.js is even worse, because silent errors can lead to situation when view is based on not well compiled template and it becomes unusable.

So what’s the case with template from Web Components, that it’s enhanced by Polymer to understand {{mustaches}}? Is it also so bad? Well, yes – it’s bad, but it also strictly separates view from uncompiled template, just because its DOM tree is completely decoupled from page’s DOM tree. And it’s the main diffence. All other points against Angular.js’s templates seem to be also applicable to template tag (especially in its Polymer flavoured kind!). But in some cases I find DOM methods friendler than string-based templates – template.querySelector('.img').src is just… sexy.

Going back to our attributes – John Papa said:

The declarative nature works great at removing oft used features and making them simple

Of course we must implement our bindAction function, but it should be dead simple, using document.querySelectorAll + element.addEventListener. And it clearly decouples our JavaScript from our HTML. Because JS should be in JS, not in our HTML. Modifying HTML just because our JS was changed is just funny. Very good example of decoupling HTML, JS and CSS is BEM methodology (I like to call it „architecture”, rather than „methodology”) – the only „glue” between these layers is [class]. No more attributes, like [ng-click], [on-click] (maybe they are just the ways to fool CSP to think that they’re not connected with scripting in any way?). Our HTML is dead simple (and fully semantic) and we have some nice bindings in JS and CSS (they even nicer when we got to know the concept of BEM tree).

I also don’t get Angular.js’s love to repeat the same information – in JS, in models (model.$dirty, model.$pristine) and in HTML (.ng-dirty, .ng-pristine). Even the argument about styling is not good – in that case we need just one class (and in JS we need just one state), because it can be true (present) or false (absent). model.$dirty means the same as !model.$pristine – nothing more. I also don’t get developers that come up with solutions, like [focus] directive, which does exactly the same thing as native [autofocus], being worse at it not recognizing that there was some other field focused and probably user don’t want to move focus while typing. Reinventing the wheel in its pure form.

Rather than building upon the DOM, we build upon our application’s data.

It looks like an advertisment of jQuery. Yup, using Angular.js we don’t need to think about DOM… but we actually build everything upon the DOM! Angular.js’s main core is HTML/DOM parser – so it’s just silly to think that we don’t need to think about DOM, working with that framework. It was the cancer of jQuery, which created the cast of jQuery-only developers, not knowing anything about the inner workings of DOM or JS. How can anyone become a magician, not knowing the magic? Maybe he even becomes popular, but one day he would just fuck up some tricks.

AngularJS absolutely does a lot of HTML parsing. But, if you do any maintenance of apps or care much about productivity then the declarative approach AngularJS provides is refreshing.

Well, the idea of enhancing HTML is refreshing… before we realise that we’re in hell. First of all, we tightly couple our JS with HTML and it’s not good (hey, show me the MVC framework – it doesn’t have to be written in JS – that states that view and model or view and controller should be so tightly coupled!). In Angular.js the HTML is even more important than JS itself – the HTML is the one that dictates how elements behave. The view also decides which controller is going to be used. It sounds crazy and I can’t stand it. Such an architecture moves the management of our app to something that is a hybrid of view and template.

Not yet convinced? Angular enables us to create custom elements easily, as well as modularising our functionality. We can write a complex web application like so (this is a simplified snippet of one of our production Angular applications):

No, it’s not convincing for me. Angular.js (in 1.x branch) is not based on Web Components, so that structure means nothing. Yes, it means nothing. Semantics? There aren’t any. Some nice DOM addons? Nope. Accessibility? Neither. So what do we get? Verbosity (it’s the same issue, as with „Semantic” UI). Angular.js even doesn’t treat that tags as custom elements, but as unkown DOM elements, which can be used in some tricky JS.

It could be done better with Web Components (and will be in Angular 2.0), but it still doesn’t solve the problem. Web Components, as I see them, should be treated as the mean to create „semantic” (for developer) GUI. It’s a technology for creating interactive views, composed from independent, isolable modules. And they should not include any logic not connected with UI. Declarative router is just insane. Application/bussiness logic should be outside Web Components and interact with them by events. With that we can create reactive, responsive GUIs, that are still highly decoupled from our application. I have written about it (in Polish) some time ago. And situation is not happy. Web Components are not accessible and creating tags like application means nothing without enough ammount of ARIA. ARIA is the foundation for „developer’s semantics” and without it all custom tags are just silly.

Going into „declarative apps” can create some totally insane ideas, like HTML6 (HTML with XML namespaces? RLY?) and putting logic into HTML attributes is one of them. Not mentioning that invalidating HTML just because [data-attributes] are so passé seems somehow funny.

Strong statement and not so true. 2-way data binding can help build applications faster and in more effective way. In fact I like that technique, but… I don’t like the way that Angular.js uses it. I’m disgusted by the only right declarative way to do it and I prefer using DOM Mutation Observer/events & getters/setters from ES5 to accomplish it. Probably BackBone’s way is nearest my heart at the moment. It’s just a matter of preference, I think – I really don’t know what are the performance’s differences between that two approaches.

Dirty checking, accessors (Ember and Backbone), Object.observe and all that stuff. Wrong! It’s slow and brittle and it will consume mobile battery like hungry dog, for no reason. You don’t need it. Use Facebook Flux rather.

Well, I find dirty checking… dirty, but I like the idea of accessors, based on previously mentioned technologies. Object.observe + Mutation Observer also should be a nice tool.

Model.bindTo or something similar – it’s how I see 2-way data binding. Everything declared in JS and view stays clean and small. Maybe use WeakMaps and Proxy to create nice API (but it’s still a future, not today…). Something like:

And I totally agree with it. HTML is language that provides semantics for content. Nothing more. It’s not a template language (if you want declarative template language, look at XSLT and some other crazy XML stuff) nor programming language, that can provide some logic for your app. It’s all about semantics.

Bindings in JS – yes, bindings in HTML – no.

Duplicated app structure with obsolete angular.module. Almost for every app feature you have to 1) change HTML 2) change its controller.

Angular provides the ability to create modules that can be combined with other modules to promote re-use and simplified maintenance. That’s one of the big reasons I like it so this is another comment that made me laugh but also wonder exactly what the author meant. There are certainly improvements that can be made here (lazy-loading of modules, dynamic loading of specific scripts, etc.) but it works well and it’s going to get even better in version 2 as the entire framework becomes more modular – including things like dependency injection.

I’m nearly certain that they missed the point here. The problem is not with modules, but the linking between modules and HTML, via [ng-controller]. It’s completely needless – view shouldn’t even know about controller!

But, as they also stated, modules in Angular.js are not perfect. The main problem, visible to me, is the fact that Angular.js came up with propertiary module syntax. It’s not compatible with AMD or CommonJS and it’s bad, because it’s reusable only in Angular.js’s context. The situation is clear here: we had 2 standards (3, if we count ES6 modules or even 4, counting UMD… ok, 5, with Melchior.js’s Chainable Module Definition) and someone creates the next one, so we have now 3 standards (the Angular.js’s one is a standard just because Angular.js is „a standard”). What’s even funnier it’s the fact that Angular.js’s modules have syntax that is very similar to AMD.

If I had a dollar for every time I’ve heard someone say that about a framework over the years I’d be retired! People love to make generalized statements like “Framework X is slow” if they don’t like it and want to turn others off to it.

Well, I don’t want anyone to earn money because of my words, but I really don’t like Angular.js, so I will say it: Angular.js is slow (and look – some new & shiny stats, that somehow back up my words!).

Yes, it’s slow. And I’m not speaking about real performance of that JS code – it doesn’t matter at that case. Angular.js is slow, because perceived performance is bad. Proof? Just look on that demo – you’ll probably see FOUC (or rather FOUT – Flash Of Uncompiled Template). That enemy was defeated years ago and now – alongside with DOM0-alike event bindins – is back.

The problem is caused by treating the page as template. It must be downloaded, parsed and finally it’s usable for user. Of course, we can prevent FOUT by moving JS to head, but it’ll probably also harm perceived performance, blocking page until JS is downloaded. And no, Polymer’s approach (body[unresolved] that hides entire page until all Web Components are parsed) is also bad. To tell you the truth, there’s no good way to solve it. Well… There is one, but it’s troublesome, so let’s move to it…

Well, server side rendering would deal with the problems described in the previous point, just because Angular.js is always going to be slower than rendering the content on server. Twitter knows it well. But it’s not about performance only. No server side rendering is a big deal, unfortunately completely misunderstood by Angular.js’s defenders.

My best guess is that this has to be a reference to Search Engine Optimization (SEO). So let’s assume that is the case. This is probably the biggest area of improvement that is begging for a better solution in the SPA space. Some companies must have SEO ready applications and it is not simple as it should be to use it with Angular. However, there are ways to tackle it such as prerender.io and these techniques.

Ehmmm… No, it’s not about SEO. It’s about USER! I mentioned perceived performance before, but even this is not the main deal here. The biggest concerns are accessibility and usability. What’s about Progressive Enhancement? Noone, really? You must be kidding me. And no, it’s not for people without JS – it’s for everyone.

Strive for simplicity. Use progressive enhancement. Don’t do it for people who disable JavaScript. Don’t do it for people who use older browsers. Don’t even do it just to be thorough. Do it because you acknowledge the important of delivering content first. Do it because you acknowledge that your site doesn’t have to look the same in every device and browser ever. Do it because it improves user experience. Do it because people on mobile networks shouldn’t have to suffer the painful experience of a broken web.

Do it for the ones with slow mobile connections, for ones that don’t get your JS, because your CDN is down for a moment and for disabled ones, who use screen readers, like Jaws or NVDA. And Google will benefit from it too.

So what’s the problem?

Angular needs a DOM to work. This is unlike other approaches where string templates are used, or even a virtual representation of the DOM that is not coupled to an existing DOM. And in the server we don’t have a DOM available. At least not a real one. We have some libraries that create DOM structures that claim to be compatible, and they may be up to some extent, but they won’t be exactly the DOM that angular needs.

Building the whole application upon a DOM sounds totally insane and it probably is. Main part of Angular.js seems to be broken by design.

DOM dependence of Angular.js is the worst thing of it, because it’s killing the accessibility and usability with one shot. ARIA and showing state of changing elements to user? There isn’t anything like that. Content for someone with disabled JS? Nope. Content for ones with slow Internet? Nope (ok – there is content for them… when their sluggy browsers complete downloading JS and parsing template). Better semantics for user? No. Good perceived performance by prerendering site? No. There isn’t even proper URIs… Hashbangs are just retarded – especially today, when we have History API.

SPA is not an exuse here – developing an accessible app is our duty, because we develop for people, not ourselves!. And SPA with server prerendering still can be SPA (hey – Angular.js needs server to send template; so why don’t send compiled template?). And yes, web apps without JS don’t have sense… almost. Look at GMail – it’s (not so) good example here: it also works without JS, having second, simpler UI (not so good example, because by using PE they could create only one version and just bind JS through DOM methods in JS). Nearly every app in Angular.js is using some kind of RESTful service – so without JS that info is still there. Angular.js could consume JSON and browsers without JS – full views. Accessible? I dare you.

And, well, I know that Angular.js was developed with SPAs in mind, but today is used everywhere (just like jQuery), breaking the Web.

Angular is hard to learn. It’s irony because Angular itself is promoted as easy framework for beginners. But it’s very complicated kind of easiness. You have to learn a lot of Angular specific patterns useful only in Angular world. Yeah, it’s result of bad design. This is both sad and ridiculous. Abstract layer can solve many problems, except problem of having too many abstract layers.

I can’t agree more: Angular.js tries to exchange JS with Java. In the old days, when I wanted to instantiate object in JS, I wrote new Object. Now I must have a service that provides the provider of factory, which inherits from factories’ factory… Gosh, no. Just no. When I want to create new object, I create new object. Period.

We had a good thing, you ruined it. We had an escape route from that ridiculous enterprise hand-holding bullshit and instead of learning how to fucking code you’ve just brought your factory provider providers with you into what was once an okay place to get stuff done.

It will be definetely a pain, just look into Angular 2.0 code: ES6 (or AtScript) & Dart, modules in modules, even more classes than now… It’s totally different framework, with different approach, different syntax, different differences… Only name is the same.

I don’t know if Angular 2.0 would be better, but I know one thing: it’s still overabstracted.

It’s easy to see how Angular itself could change the face of web design. Dedicate a part of your team to building a part or the whole of your application in Angular – I promise, you’ll never look back.

I’m glad you’ve asked. There are some new heroes, like Taunus or super simple Mithril (it can’t be simpler than that, I dare you!). The old ones are still powerful, like BackBone.js. And… that’s my types. Not many of them exist, but I think that this list is long enough.

I think that Angular.js doesn’t enhance HTML – it breaks it. It also breaks JS, overabstracting it. It can be more performant and for me it’s behind today’s trends for simplicity.

Yes, there is need to evolve and enhance our Web, but I think that Angular.js’s road is a dead end one.

Podobne

Komentarze 6 komentarzy

I haven’t investigated it deeply, but people say that it’s used by YouTube internaly and DoubleClick.
But yup, it’s quite meaningful. Although I don’t think that something like GMail should be rewriten from stable technology to something new & shiny, even if this new toy is better. The same case as NASA’s systems, created in FORTRAN 😉

Most of your arguments are just silly. You haven’t use Angular by yourself, haven’t you? I’ve seen projects with more than 800 directives that were managable, no performance issues AT ALL (oh, btw, your example is just badly written code).
„DOM dependence of Angular.js is the worst thing of it, because it’s killing the accessibility and usability with one shot” – bullshit, we deliver applications for hospitals worldwide and conducted hundreds of tests on real patients out there. Honestly, when reading something like „There isn’t even proper URIs… Hashbangs are just retarded – especially today, when we have History API.” I really think you don’t know anything about Angular… Very poor post, indeed.