I too think Angular is overly complex and "magical."
The JavaScript world should be learning from the mistakes of monolithic and semi-monolithic frameworks such as ASP.NET and SEAM not trying to recreate them.
For my part I'd like to see separate libraries for events, views, models, syncing models to persistent storage, and binding models to forms. Small micro-libraries allow maximum flexibility and efficiency, and facilitate more maintainable code.
The way that Angular violates separation of concerns between presentation and view is another symptom of a monolithic approach, and a step backwards in HTML client software design.
How I feel about angular now is that it's a vision of what web development could be like in the future.
A lot of this stuff only really makes sense once the entire environment is present. Polymer is actually fairly similar, but trying to tackle the problem from a different angle.
It has the potential to do less in the future, and I think right now it's an interesting proving ground for and ideas and teaching people to think about things differently.
I'm much much more comfortable with backbone myself. If I didn't specifically set out to build a couch-app, i would not have been able to justify using angular.
interestingly, i realized i like backbone for the opposite reason i like angular. I don't actively expect it to get more complex over time. It just feels like each new release 'tightens up' the formula.
Thematically, I'd say Angular's dependency injection is "supposed" to be resolved by the tooling. If you look at Angular.dart, it doesn't have this particular hack because it uses the type system to resolve what to inject. But Javascript doesn't have static typing... "specify it twice (as a list of strings, and then a list of arguments)" is a fairly ugly and error-prone solution. Specify it once and let the tooling do the work seems like a reasonable idea.
I tend to find that most of the awkwardnesses I come across in Angular likewise come from the underlying nature of Javascript and HTML. As a concept, Angular.js seems to me to be fairly straightforward -- client-side compositing of templates against data (without imposing constraints on the type of data), plus routes and a promises library for http calls.
"specify it twice (as a list of strings, and then a list of arguments)" is going to result in localized errors, in your own code, not spread through all 7 levels of dante's museum of abstractions.
Doing it at build time is also preferable to trying to do it at runtime, like it does now.
I would agree with your assessment, otherwise. I just think that this specific technique was railing against JS a bit too much, and was ultimately a dead end.
Interestingly, the new DI framework also uses ES6 and traceur.
One of the first things that "broke my brain" when starting with Angular.js (during its wild 0.x days) was inferred injection — I know Javascript. I know how arguments are passed. What the fuck is happening here??
At that time documentation was sparse and often incorrect, but I'm very glad they're moving to a more predictable and sane DI model.
I was reviewing the code spit out by a Yeoman generator, while reading some Angular docs (admittedly out of order), and I has confused about how variables were being defined. I finally read something that explained what to do (add a variable using a specific naming convention to the function declaration). I realized the framework was doing some sort of backhanded meta-programming, and I didn't feel so bad for not understanding what was going on.
The problem with this is you can be a pretty knowledgable JavaScript programmer and still not understand the code or the documentation. For this reason, I've never been a fan of meta-programming in general. Not only do you (as an application programmer) have to understand the language as defined, you have to understand other frameworks' reinterpretation of the language. If you bring in multiple frameworks that do this, it quickly becomes more difficult to reason about what a program does by simply reading the code.
When I realized angular actually parses views and module definitions and rewrites them, I lost interest in trying to figure out what was going on under the hood, and decided to stick with backbone. While the angular devs are obviously brilliant, the complexity is horrifying, and I don't want to debug my application code when I can't reason about the framework's internals.
I think one of the nice things about Javascript (man, I wouldn't have seen myself saying that a year ago) is that this kind of hackery isn't really considered idiomatic. You can get so much mileage out of an extra function expression wrapper.
I wish I could give this comment a million upvotes.
From my perspective as someone who has developed on the MS stack for 15+ years, frameworks like angular and ember strike me as (retroactively) following right in the footsteps of Silverlight and ASP.NET WebForms. To be clear, I don't think that's a good thing.
I think simplicity is undervalued in the programmer world in general. It takes so much more mind-energy for someone to implement/refactor/add-to/test complex code written by someone else as opposed to simple/verbose code.
> I think simplicity is undervalued in the programmer world in general.
I imagine every programmer will claim to value simplicity. Trouble is, they're all talking past each other because their working definition is "the way I personally do things".
maybe, except that I try to improve how I do things on every iteration.
i've been finding that it helps me to think about these things in a more concrete manner, so that i can vocalize to myself what I didn't enjoy in the recent experiences.
The problem is, simplicity is often not a possibility. The problems we're solving are complex, not simple. Simple solutions to complex problems are to be sought after and cherished, but they are also incredibly difficult and idealistic.
Instead, we value pragmatism. We favor structure which simplifies, rather than structure that is simple in itself. We do this because it increases our productivity in solving highly complex problems; problems that simpler foundations would not support or would not assist.
Angular simplifies, hands down. It does this by swallowing the complexity into itself, and dealing with it in some rather intelligent ways so you don't have to. This, above all, you need to understand to use it effectively. Some complexity leaks; a great deal of it is contained and managed well.
You may love a handsaw and hammer and nails for their simplicity and clarity, and there is merit to that, but they can only build so much so quickly.
Angular is not a combination of those simple tools: it is more like a 3D printer, enabling you to build components of things and use them to make final products as fast as you can dream them up. It knows what it is, and so should you. Please excuse the lofty analogy.
While I do the think author makes too big a deal about this, I very much agree with them.
The main issue is whether or not we should be teaching people, as a first brush with Angular, to code things with "automatic Dependency Injection", where the types are inferred from variable names. The alternative, and only way to code a "real" application, is to pass the names of things you want injected as strings.
For people unfamiliar with Angular, this difference means turning: myFunction(Dep1, Dep2) into myFunction(['Dep1', 'Dep2', Dep1, Dep2) (more or less).
Doesn't seem like a big deal, does it? But I think the decision to teach people the "bad" way to do things, all for the sake of making things "simpler", is completely wrong, and misunderstands what kinds of complexity people have a problem with.
Complexity isn't telling people "write the same word twice, cause that's how it works". Complexity is telling people "here's another thing you have to learn about this framework".
This is a small matter, but it isn't trivial, and is a common mistake with Angular.js (hiding the wrong kinds of complexity).
I'm only making a 'big' deal about this because I have given this serious thought.
This is the third part in a series of articles where I was trying to understand why my intuition was telling me that there was something not quite right about angular.
I finally managed to track it down to this specific little thing, and how the unintended consequences of a feature like this could have far ranging consequences to it as a viable platform.
My reasoning was not about how crazy this is now (which it is), but how this could end up 5-10 years from now if it doesn't get removed now.
Most platforms, at least major ones, ARE relevant for many years. Of course we have yet to see if Angular will be one of them, but it's looking like it will.
This is where i discovered the exact thing about angular that freaked me out the most, and how I was finally to get down in words what I felt about it.
I made a github issue about it, and the devs acknowledged the issue, saying it was no longer part of angular 2.0
>I made a github issue about it, and the devs acknowledged the issue, saying it was no longer part of angular 2.0
Ok so I read all both of your other articles and found them to be interesting. I was disappointed that there wasn't some kind of afterword to go with the sabre rattling. Seeing that you put in an issue makes me feel alot better about the whole series.
As I read these I kept thinking... yeah but... and then thinking of a feature that annoyed me that changed from release to release.
And ultimately I think the biggest thing I have always liked about angular is how quickly the community has learned from potential mistakes and shed chaff code....
I was always going to need to put this into an issue, once I identified why it bothered me.
I think angular is really special because I can see it getting simpler. I almost never see that in software.
They have shown that they are willing to change, and I think that they have the right people in charge to do it.
I think you are going to see some serious changes for 2.0 though. Now they are on semver, stuff is going to have to shift pretty majorly between major releases. You can see some of that in angulardart already.
I have read about potentially including lazy loading in the base which personally would be really huge. Not having to integrate Require would be a pretty interesting to me if it happens
I'm probably not the audience for require.js, because I've never had a situation where I was forced to not have a build step. Once you just accept that there's always a build step, life becomes so much easier.
I feel for you man. I really recommend you just try to build something, even if it's a little demo of some sort, with the assumption that you are going to have a build step.
I just found that the result of that assumption ends up with something that is a lot easier to work with and reason about, than trying to rail against it by using something like r.js.
As far as the particular issue he picks on, he is making a big deal about something that's not, at least if you accept the general premises of Angular, and trying to pin the core of his whole argument on that. Which is dumb.
Anyway, I have used many, many different UI frameworks on different platforms over the years. Including different .NET systems, Backbone, Angular and to some degree web components. And many other lightweight and heavyweight systems.
I am actually amazed that developers are not immediately seeing the obvious advantages of Web Components (with Polymer for now).
I am amazed that people are still trying to master AngularJS when we have Polymer. (At least the people who can tell their users to use a new version of Firefox or Safari, which is actually quite a lot of web apps these days, although obviously not all).
Angular is very obviously more complex than necessary.
Very few people are going to be with me on this, but this whole idea of separating out scope and avoiding global variables at all cost has got to the point where it is just ludicrous. And the only explanation is that this stigma about global variables has a religious and un-questioned association with incompetence. Unfortunately that particular cargo cult can lead to things like Angular DI.
Why aren't more web developers excited about Polymer and Web Components? Because many web developers, despite experience with Angular, get distracted by DI and other over-complex topics and somehow fail to completely grasp the basic concepts and advantages of what a user interface component is and does.
I disagree with you that the hacky DI scheme is something that should be ignored. It's brittle and really has no place in the core of a library like this. It's not an end of the world thing, but it's definitely worth addressing.
I totally agree with you that Angular is overly complex. I feel like they somehow either overshot or undershot the correct layer of abstraction, and I'm not sure how. It can produce really elegant projects for sure, but when you need to actually understand what's going on...prepare to navigate a whole new world of linkers, compilers, injectors, scopes, directive options. The spiral just keeps on going.
I don't get the defense of global variables. I feel like it's been proven time and time again that the trouble of encapsulating code and explicitly coupling parts of an app through clear interfaces pays dividends. I think class and module patterns have been a major turning point in the maturation of Javascript. I'm hoping that when we finally get native opinions of these concepts in ES6, we won't need so many reinventions of the same thing.
Hm. Forget I mentioned the term "global variable" since it is a religious term.
I am not trying to argue against proper encapsulation and coupling/decoupling. Those things are great. Classes and modules and great. Not sure how you see me as attacking those things.
Say I am working on a web application and I want to use AJAX. I should not have to keep saying in every place that I want to use it "oh by the way I am using AJAX".
If you agree with this then exactly what sort of encapsulation and coupling would you recommend for the overall application to achieve not having to keep saying that it wants to use AJAX?
I think you should basically say "oh by the way I am using AJAX", whether that means using Angular-style DI or require or a mixin some other means. In a language with a built-in concept of modules, you'd have to import or include something like that, wouldn't you?
There are some practical benefits, aside from the general happiness provided by namespacing. Not that every single app needs this, but it's pretty handy for example to be able to substitute a mock AJAX service for testing and offline development purposes.
Web developers are excited about Polymer and Web Components. However, using a product still on release 0.2 for building real-world, production apps is generally frowned upon by anybody over 16.
I've built a few projects with Polymer, including this public-facing one (http://securesha.re), which is a poster child for why you shouldn't use pre-alpha software (see the blown stack in the console; this was working just fine a few browser releases ago). Thankfully, it's not a critical app and it's more of a proof-of-concept than anything else. The source is available below [1].
It was a joy to build Secureshare with Polymer and it really made me rethink what an HTML element can be and what it can do. You have to unlearn years or decades of assuming that an HTML element has almost no useful API; with Polymer, you're likely to define many core application functions directly on DOM elements themselves. It's a lot of fun once you get used to it. <polymer-localstorage> and <polymer-media-query> really opened my eyes to what was possible with this new paradigm, and it is unquestionably cleaner than what has come before.
More than anything, I'm excited for the inevitable deluge of web components; finally, UI libraries that can that be mixed and matched in any web application without regard for what other JS and CSS is on the page. True isolation allows us to create truly fantastic projects.
Did you read my preface or the other 2 articles in the series?
My argument was just 'this is wrong. dont do that', not that angular was bad because it did that.
I am excited about web components and I'm dying to find the right project to build something with polymer, but they just aren't mature enough for this yet.
It isn't ready yet (another few weeks until a 0.1) but I'm working on a simpler UI framework that lets you bind HTML elements directly to REST-ful URLs, cutting out a big swath of complexity for many apps:
Again, this is not ready yet and I'm actively changing things, but if you are interested in an AJAX framework that is concerned with keeping complexity to a minimum, it might be worth checking out. Comments and criticisms very welcome.
I think DI in Angular should be an opt-in thing, too confusing otherwise. I've had moments where I thought I was just writing a regular function, and then Angular started throwing exceptions because it was trying to inject dependencies based on the argument names. (And the solution was to write a function with no arguments that returned the actual function with arguments!)
There are conventions around what string maps to what thing, so that sometimes strings like "controller" or "provider" are inferred and not required to be specified. This is bad -- things should just be referred to by their full names.
It would be nice to have the ability to ask for things directly in require-style function calls instead of having them be parameters to a function. It's actually sort of crazy that you can define a controller (for example) with angular.controller('MyController', function(){}), but then you can't ask for it back with angular.getController('MyController'), or whatever.
All this makes it a lot harder to try things out in the console, and lengthens the feedback loop of determining what works and what doesn't.
And I didn't even know about the minification thing. That is legitimately terrible.
It's interesting that he has a visceral reaction to the "hackiness" of Angular's clever way to do runtime DI but no visceral reaction to the fact that the problem was created by a third-party program which was instructed to purposefully obfuscate the actual source code of his program before delivering it to the runtime... the JavaScript world is indeed a funny place.
That said, I am empathetic to his argument. But as a very happy Angular user, the benefits that are gained by having a runtime DI layer that works such that it can be built into the entire platform so far outweigh the one-time tooling change that it doesn't bother me at all.
The rest is a slippery-slope argument that I don't think is fair. If you trust Angular as a project, then you have to trust to some extent that they'll make sane decisions. Since this particular clever hack is the only one that won't get "better" over time as runtimes improve, I think that they deserve the trust so far.
DI is fine, i was just concerned that they have something that breaks as the first recommended way to do something. Much less that they have it at all.
Minification pretty much counts as 'normal use' these days, as much as we all have a distaste for it, we really can't change it.
You should watch the video on my post and tell me you are still comfortable with it doing that at runtime.
And the slippery slope thing? I spent 10 years of my life building open source projects with thousands of contributors and untold thousands of users. That's experience talking there. My point was that you can't deny the sufficiently promising excuse to abuse it further, without admitting that it is flawed to begin with.
My suggestion was that now that the ngmin exists, make that the only way to do it and remove all the crazy stuff out of the main execution.
I also said that clever hack is the only one that could never get better. There's no standards path for it.
They have been shown to deserve the trust. they are removing the hackiness from 2.0.
Great ideas! Sounds like we generally agree. I read the whole post but didn't watch the video or read all of the 2.0 stuff... though I am aware how their DI hack works.
That said, the title of your post makes it sound like you think they're heading off a cliff, but your response to me sounds like the opposite... I was just responding to the tone set by the article.
I'll also agree that it is frustrating early in the AngularJS experience to hit that minification bug. But it's easy to get over also.
Yeah. I was mostly concerned about the fact that nobody was pointing this out.
If you read the [1] previous post you will see that I am remarkably positive about it. My concern was that the answer to working around the DI hack was always "dont do that".
Even ngmin is just a really elaborate way to 'dont do that'. With it's own issue queue and grunt plugin and almost 22000 hits on google.
From working on open source for a long time, I know that existing code also sets precedent. And i couldn't think of any way that you could keep using that code for the next 5-10 years without somebody thinking of something else 'clever' to do with it.
They devs realized that though, without me. which is great news. You are in awesome hands imo.
AngularJS is not complex , when I think complex , I think SpringMVC or Struts complexity. AngularJS has problems ,but complexity is not one of them, definetly.
Seems like JS programmers who only know JS think they can get away with ignoring patterns like dependency injection, Guess what, in order for code to be maintainable and testable it needs it.
Front-end is about GUI dev,and that's where OOP shines. It's high time for JS folks to read classics like "Design Patterns" books, and embrace SOLID principles , or AngularJS wont even help when developping their so called "fairly large" apps.
The author is concerned about the future of Angular because of the idiosyncrasies of one method of including dependencies. I mean, really? Is it so bad, the stench of automatic dependency injection, it overcomes all other beneficial features of Angular, it would jeopardise it's future as a web framework, such that it would lose compatibility with future browsers and your web app built in angular will stop working, with no support available? IMO it's a bit hyperbolic to suggest this is the case.
no. i was worried about the fact that people weren't questioning the logic of it, and that once this kind of magic takes hold ... it's really hard to take it out again.
Nobody said anything about future browsers and losing compatibility.
I do think that if this kind of thing grows, the system will become complex enough that developers will move to different frameworks that do similar things but don't have all this magic and baggage.
This seems like a one-sided overthinking of the auto dependency injector (which is like 30 lines of code).
1. The auto DI means beginners can get to "Hello World" in angular without learning some wonky injector syntax. If Angular's goal was to bring some of the jQuery crowd on board, then it was a smart move.
2. The auto DI doesn't survive minification, so not all code can be copy-pasted, and there are two different syntaxes. Unnecessary complexity?
I see no reason to make a bunch of analogies to argue on one side.
Those 30 lines of code require the hundred or so lines of ngmin to actually work correctly, and then results in the extra (im assuming) hundred or so lines of grunt-ngmin and all the tooling around that. And then all the tests, the issues for the main project and all of the related projects, every bug that anybody has ever faced with minification of angular apps.
The auto-di is not that much simpler than the array format, and the array format is also actual valid javascript. They are abusing language features in such a way as to bypass the semantics of the language itself.
The fact that it doesn't survive minification is a sign that you shouldn't really be doing it to begin with. There are 3 different formats, and one of them introduces some crazy magic into the main framework, that is all really unnecessary and could just be as easily avoided. Auto-Di is the 'wonky' format in any reasonable context, I'm afraid.
- AngularJS is a tool for building complex single-page web applications, not brochureware.
- If you're building complex SPAs, you're going to require a decent level of tooling.
- If you have a decent level of tooling, the points in this article are meaningless.
As an aside, ngMin is the most trivial thing in the world to set up, and if you can't figure it out, array notation is slightly painful but well worth it for all of the tools Angular provides.
I still can't decide if angular dependency injection is more amazing or revolting.
It's magic, it's non-intuitive, it breaks the standard paradigm that function arguments have no external significance, and it doesn't add much real value by just saving one extra line per function - inject(fn, ...)
On the other hand, it's elegant if you ignore all the above criticisms.
I'm a huge fan of dependency injection, it makes life infinitely better when designing your code & testability.
That said, I'm somewhat sympathetic to this complaint - it turns me off towards Backbone. However, I argue that it isn't nearly as bad as views with Backbone. In addition, this is changing in 2.0 with a much cleaner injection mechanism.
It does when it comes to not leaving your views in an ugly string representation of html - you use a build process of some sorts to get around that fundamental flaw so that you can still use a nice html template file. That alone was enough to sour me on Backbone, hence the comparison.
This flaw in Angular isn't nearly as deep was my point.
HTML is HTML, why does it matter what file type it resides in? All my templates are stored according to the view's type within my ./templates folder. If I want to include the HTML in an "actual" HTML file I can do that too. Have you even used Backbone?
The JavaScript world should be learning from the mistakes of monolithic and semi-monolithic frameworks such as ASP.NET and SEAM not trying to recreate them.
For my part I'd like to see separate libraries for events, views, models, syncing models to persistent storage, and binding models to forms. Small micro-libraries allow maximum flexibility and efficiency, and facilitate more maintainable code.
The way that Angular violates separation of concerns between presentation and view is another symptom of a monolithic approach, and a step backwards in HTML client software design.