Can you specify some of the forthcoming improvements? I want to like Angular, but every time I've actually used it has been a practical and conceptual headache. (Also, the idea that they're creating a new compile-to-JS language seems strange and unnecessary.)
It's TypeScript with the addition of a few key features that are helpful for Angular's design.
Technically, Angular 1.0 also had its own scripting language too. It's kind of inevitable, since Javascript itself is one of the obstacles to making a better web framework.
It's utterly insane. Just as in AngularJS 1.3 they have invented there own expression language which floats around in HTML attributes, thereby eliminating the use of Javascript itself and all it's functional goodness. And worst, the user has to incur the cost of downloading this needless code for the expression language to bootstrap the framework.
Check out examples of using TypeScript with Angular (or DartAngular). Gives you a lot of benefits today. Personally I think Angular is great but React is even better and I will probably use the latter for my next project if I can choose.
And to make up for it, they threw in some even worse parts. Like breaking the syntax of HTML with their templates, making it impossible to edit, validate, transform, generate or consume templates with any of the thousands of existing HTML and XML processing tools.
That, in my opinion, was one of the most terrible ideas I've ever heard come out of the Angular community. And even worse, they refuse to acknowledge that it's a bad idea. That's a very bad sign indeed.
Maybe you're not using ng-app? In that case, document.querySelectorAll("[ng-app]") wont return any elements, and it wont find the root scope. Replacing "[ng-app]" with a selector that finds your root element should work I think.
The dependency injection thing is really a non issue. Just use something like ng-min before you minify and you are set. Just for the price of another entry in your grunt.js file.
And his reasoning around that was inanity disguised with high concept. He already advocates for a build process to minify code, ng-annotate simply expands the condensed DI syntax to the array notation.
> And his reasoning around that was inanity disguised with high concept.
To elaborate: invoking the argument "you reduce to the Halting Problem, suxxor!" without some concrete examples of how the practical problem (i.e. ng-min implementation) encounters difficulties is disingenuous. It's not uncommon to be able to cover some very useful space of a real-world problem, skirting "inside" a problem which is theoretically limited by the Halting Problem or similar. Occasionally you hit a limitation in your algorithm and add a special case, further claiming practical territory from The NP-Complete Beast.
In this case, the strict di enforcement that baconner mentioned in this thread provides an escape hatch: if you're using ng-min while having di enforcement enabled, you'll at least get warned if something goes amiss. If so, add your manual DI annotations, maybe file an ng-min bug, and move along.
There's also a new strict di enforcement option that'll make angular error if you don't have the min friendly di syntax in use. That's the best way imo and probably what angular should've always done.
Maybe your use of quotes is to make fun of the article, but in any case, I'll say this: I disagree it is a bug, rather it is a shortcoming of a minifier that it does not preserve the semantics of the input program.
Since this shortcoming is hard or impossible to overcome completely, case-specific post-processors to help out the minifier sound reasonable to me.
I think it's simply a flawed design to use reflection to read function parameter names and then use that information to apply semantics. I think parameter naming is something that shouldn't directly be semantic, as that's what most developers except. If, for example, I'm supplying a callback function to a library, I don't except the library to read the parameter names and then do stuff differently depending on the variable naming I happened to use.
I think your point about the minifier being "broken" is a good one, but the real problem is with AngularJS in my opinion.
I agree, it's flawed design and a crutch that comes about due to the lack of a better type system. But the cited reason (that it doesn't work with a minifier) is bogus.
No, ActiveRecord never looks at argument names. (unless you're talking about Ruby's named parameters, which is nothing like Angular's DI and not AR-specific)
What I meant is db tables and field names get converted into ruby class names and properties/methods. This is basically convention over configuration. It's the same with angular.
The way you spell your parameters does not fall under the "semantics of the input program". That is purely syntax, and it should have no bearing on the execution of the program.
This shortcoming is easy and possible to avoid in the first place, totally eliminating the need for case-specific post-processors to help out the minifier.
Some advice: next time you design a framework, how about designing it not to require case-specific post-processors from the start? Then you won't end up with so many shortcomings that are hard or impossible to overcome completely.
> The way you spell your parameters does not fall under the "semantics of the input program". That is purely syntax, and it should have no bearing on the execution of the program.
I agree that identifier names should not matter for semantics, but it's quite possible to write JS (and other language) programs that do. So, your first sentence is simply incorrect, it is part of the semantics.
So yes, it's not best practices to do this, but it's not exactly "insane". Constraining your design on non-semantic-preserving minifiers is not the answer.
Also: In your last sentence, like in the linked article, it sounds like you and the author are under the belief that framework/api design is easy - and anyone who gets it wrong is an idiot.
Actually the naming of parameters do have meaning in many programming languages and changing a name of a parameter is there considered a breaking change. In both Python and c# you can call a function like foo(bar=4), where bar is the parameter name. Whats interesting here is also that python is dynamic and c# staticically compiled. Automatic mapping of functions to xmlrpc or other serializing would be another example.
I'd say that angulars behavior here is very unexpected, by mapping parameter names to registered controllers, but I'm not sure if the minifier can be said to be incorrect. If javascript has a way to get the names of the parameters, is it then incorrect to assume this can be used? Strictly speaking if you want to conform fully almost nothing can be minified since object==dictionary but you have to draw the line somewhere, maybe parameter names are moving over that line.
Or just get into the habit of writing minifiable code. I think the benefits of using angular (dirt-simple two-way binding) largely outweigh the criticisms levied here, especially for simple applications. I have written large and complex applications with routing, and there were a lot of difficulties, but I think that is probably true of any framework that tries to do as much as angular.
Decades ago I got out of the habit of writing C code that was easy for the compiler to translate into VAX machine language instructions. I didn't realize those skills I let atrophy might someday became useful again for JavaScript.
When do you think schools teaching JavaScript should instruct their students how to write easily minifiable code? Is that an appropriate topic for JavaScript 101, or is it more of a graduate level thing?
Can you please suggest any good online course where I can learn this important skill that you're suggesting all JavaScript programmers should have?
Has Doug Crockford written a book called "JavaScript: The Minifiable Parts"?
Does Google test job candidates for the ability to write minifiable JavaScript code on the white board during job interviews, by giving them a dry erase marker that's almost run out?
No need to go overboard there Don. In fact, my statement was really intended to mean "minifiable" in the sense of an angular application. That is, following documented best practices for writing a minifiable application in angular as described here: https://docs.angularjs.org/tutorial/step_05
By "especially for simple applications" do you actually mean "only for extremely simple applications"?
So do you really believe that the insane scoping madness described in the article, and the fact that Angular's new templates breaks HTML syntax making it impossible to edit/validate/transform/generate/consume them with standard off-the-shelf HTML tools, are really not big issues, and dirt-simple two-way binding outweigh those problems, and are impossible to do without causing those other problems in the first place?
Since the order a user fills out text fields on a web page affects the scope in bizarre unexpected ways, shouldn't Angular automatically disable the offending second text field until the first is filled out, and provide tooltips and help text explaining to users why they're disabled, to force users to enter them in the correct order, that will not undermine the intent of the developer? Is that the kind of implicit magic that you expect from your full service front end web development stack, that makes it all worth it in the end?
Personally, I'd rather have a scoping mechanism that's less magical and astonishing, and more deterministic and predictable. And a templating system that doesn't forsake and reject the rich existing ecosystem of HTML and XML tools.
FWIW, back when I joined Google Search in 2009 the whole company was on a huge latency kick, and yet inline JS snippets in the HTML weren't compiled, and so there were instances where we had to "human compile" Javascript down into its minimum form. Single-character variable names, foreach-loops that look like "for(var i,e;e=c[i++];){...}", ordering statements so that they would GZip better - basically we were trying to simulate an optimizing JS compiler in our heads. I had code reviews turned back because I could save 1 byte in total GZipped size with a different for-loop construction.
Yes, this is insane. No, they don't do this anymore. But I'm glad I had the opportunity to do this (on somebody else's dime), because it made me really think about latency and on the performance trade-offs you make to get maintainable code. Code size is not free; many devs think it is, and they write really bloated SPAs as a result. And there's also a lot of low-hanging fruit that doesn't require lots of engineer effort but gives appreciable latency benefits.
I'm pretty new to front end development, and a few months ago I started learning Javascript by experimenting with a few front end frameworks. When I got to Angular, I dropped it the moment I saw string-based expressions. How is that even remotely acceptable? I can't even imagine the bugs I would be embedding everywhere.
So, on one hand, yes. As a clojurian, I feel as if I should add an additional level of condemnation (the whole syntax of my favorite language is good old-fashion data structures, as is almost every construct within the language).
That being said, it's frontend stuff. The turnaround times are so small that those kinds of bugs are pretty hard to ignore, and very easy to find.
Note: I have used Angular, but don't use it anymore, for other reasons.
Their model for dom composition is substantially more complex than I would prefer. Angular, at it's core, is something like a re-imagining of the dom + js-event-loop that is hackable and modifiable. Good goal, but the complexity doesn't buy you much over e.g. reagent or meteor, which are _much_ simpler.
You ask that as if not suggesting an alternative to Angular invalidates suggesting avoiding Angular like the plague.
There are MANY viable alternatives. No one solution fits all, but some solutions, like Angular, fundamentally suck at everything, because they're terribly designed, and their developers refuse to acknowledge or correct that fact.
In order to answer your off-topic question, which is outside the scope of this article, you'll have to explain in detail all about what your actual requirements and experience and expectations are, and for that you should expect to pay a reasonable hourly rate for an experienced developer to listen to you and give you advice.
If that's what you really want, then good luck finding someone to help you with your problems choosing a decent web framework, but at least you now know that Angular simply doesn't qualify. But if you're just trying to imply that it's not right to criticize Angular without evangelizing an alternative, you're wrong.
> No one solution fits all, but some solutions, like Angular, fundamentally suck at everything, because they're terribly designed, and their developers refuse to acknowledge or correct that fact.
That's utter BS. There are lots of very good ideas in Angular. Yes, some of it is not done nice but at the end of the day it's quite a nice framework. Have you even worked with angular?
Two-way data binding really is very convenient, even if it doesn't scale well to large amounts of data. It still saves you a lot of jquery-style boiler-plate code to read values from once place and manually update it in several other places in the DOM.
Also, Angular forces structure on you in ways JQuery doesn't. It makes unit testing viable. I rewrote a javascript slider in Angular, and the code became a lot simpler, shorter and more readable, exactly because of all the stuff Angular abstracts away.
So in comparison with JQuery, the previous best javascript library, Angular has some very clear improvements. How it compares to Ember and Knockout, I have no idea.
Give react.js a try. I am not a web developer either. Saw Angular first. Got lost in the soup of new terminology -- digest cycles, dependency injections, services, factories, scopes. I suspect Angular probably made sense to already experienced JS developers who had to struggle with jQuery before...
But then I tried react and the whole idea of unidirectional event flow made sense, JSX was a little confusing but it was simple to grasp the need and use of it.
> I suspect Angular probably made sense to already experienced JS developers who had to struggle with jQuery before...
Not really. Angular is its own little world of terminology and ideas. I've heard it said that Angular users don't learn JavaScript, they learn Angular.
Absolutely the case - I enjoy Javascript coding but can't stand having to follow Angular's opinions on everything that should be done to the DOM. Having a consistent model of interaction is great, and Angular enforces that while giving you quite a few nice tricks, but it does it in a way that feels so far away from JS itself that I'd bet it actually hurts your Javascript composition to know Angular.
That is the route that I'm currently going down. So far, it has been a joy to work with. My only complaints to date about React have been the incompleteness in the documentation about events, and the jsx attribute renaming (ex. className="foo" => class="foo"). I also worry (but haven't been disappointed yet) about pre-1.0 instability.
I really like the acknowledgment that UIs are fundamentally state machines, and React's explicit connection between state and rendering. I do wish they would introduce more featured state transition/events modeling...Something similar to Jake Gordon's javascript-state-machine[1] library would be amazing.
That annoys everybody. It's that way because the JSX attributes map directly onto the DOM attributes which in turn are named that way to avoid ES3 reserved keywords. It's supposed to be less magic/surprising but far more people interact with JSX (e.g. designers) than work with raw DOM manipulation.
The concepts on Angular have nothing to do with JavaScript. The new changes they propose to JavaScript borrow most from Dart, which in the eyes of a JavaScript programmer is an attempt to turn JavaScript into Java.
Meh, over the last two years I've worked on a team that put two medium complexity SPAs into production built with Angular; in my experience, the string-based expressions are a non-issue, I can't really think of any time when it caused difficulties in our development. Yeah, it's less than elegant, but if you keep the expressions simple (e.g. use functions for anything more complex than single term expressions) then there really isn't much to stumble over.
This is the first time I have read some of these criticisms of Angular on HN. Can you point to threads where there was discussion of these issues? Would like to get more info on these. Thanks.
Ah yes, the old "this has be discussed before" statement that assumes that everyone has already read everything and that new people to the group should always search through old posts about subjects they may not even know exist. Because nothing must ever be discussed more than once.
Usually stated by people who feel the need to comment in the thread about an article covering a subject they've already read about; just to point out they don't want to read about the subject again. It's like a driving need to spread their negativity towards discussing anything more than once.
I actually think this is a good thing. Angular doesn't get nearly enough heat for its flaws. The more they are publicized, the more the framework can improve.
Just today I lost half an hour figuring out why my ng-show worked for all other strings except for "f" and "F". AngularJS definitely has it's own traps..
Yeah, "!!variable" works, and in my case I used ".length > 0". Boolean(variable) works too. It's just unfortunate when you're assuming that the expression or typecasting works like in JavaScript, and then AngularJS had to invent these unnecessary rules that make no sense. JavaScript's type coercion is tricky enough, you don't need to make it worse.
But it would be good if the obvious way to do something didn't have certain magic conditions in which reasonable expectations aren't met (e.g. a variable is evaluated to its value, regardless of its name, or rather don't just change the language semantics in some places; yes I know it's fixed, still a good example), thereby minimizing those pitfalls.
I think digest loop is one of the best parts of AngularJS. I wonder how it ended on this hate list. I dont think I will agree with much of the rest either.
Out of curiosity - what do you like about the digest loop? I have never thought of it as anything other than a necessary evil in implementation to achieve some high level goals.
I understand most of it, but digest loop is a great idea! It's much better than manual `model.on('change', view.render)` of backbone for example. Developer might forget to do this manual rendering for certain actions which is bad
Even if you like the digest loop, why do you need the rest of the framework? Why not just use a lightweight alternative that provides that functionality?
The digest loop is highly flawed, as the article describes - it is not performant, and requires disabling for many common scenarios.
Worse, and I don't see this mentioned, is that the digest loop is not tied to any notion of lifecycle - you can accidentally keep retriggering it until you bomb out after 10 loops.
I view it as an icky hack. I much prefer the `model.on(...)` explicit wrapping of model data/eventing in an object. It's a lot more performant and easier to look at and say "that is a model" vs "this is a javascript object, but I don't know if it's being listened to or not."
Forgetting to set up your eventing fabric is not a great reason to choose a framework. If you forget to hook up the wires, the view doesn't render properly. This is easily debuggable.
Actually, I think an opportunity was missed in the section about dependency injection. The problem of minifying is easy enough to avoid - you just don't use that form. (I do agree that the tutorials shouldn't be teaching the dangerous form, and the dangerous form shouldn't even be a thing.)
No, what I hate about Angular's DI is that it tries to make inferences about the name you give it, instead of the name being an unambiguous identifier. It does this for "convenience" but it just ends up causing problems and making incorrect guesses.
I'm talking about how, for example, if you have a class called WobbleController, you don't inject 'WobbleController', you inject 'Wobble' and Angular just "figures out" the 'Controller' part. Pretty sweet when it works! Wow, you don't have to type 10 characters! (Good luck grepping for it later, though.)
But when it makes a wrong guess it seems impossible to fix. The other thing that sucks about this is that you have to reload your app to see if Angular will actually be able to find the thing you're injecting. This whole thing is supposed to save time, and it just doesn't. It sucks.
I am torn about how minification affects metaprogramming. I don't believe that reducing the delivery footprint should ever effect how the code is interpreted.
On the other hand, if you think of access to argument names as part of the Javascript language, then a "minifier" that threw out that information would by definition not be a Javascript minifier - it would be a minifier of a subset of the language.
lol. i have to laugh at this. it is not normal to write a framework that requires exact argument names in userland code. it is completely strange and unusual for something to break just because an argument name was renamed; this data is theoretically private to the function. The only reason this is not the case in Angular is because of the insane hack of stringifying functions. This is a violation of how things are designed and assumed to work in JavaScript. You don’t run functions by toStringing them and eval-ing them; you just call them... anything else is an experiment, not a supported use.
Controller was just an example. I remember at one point I wanted to inject a value, and its name was "Foo", but the DI loader (whatever it's called) kept wanting to turn that into "FooProvider". There was no way to say -- no, the name is just Foo! It's not a shorthand for some other thing!
And like I say, no way to check that you've fixed the problem except reloading your whole app and waiting for it to show you an error, or not.
I just think that's a bad way for it to work. It should look for the thing by the name you give it and then find that thing, or not.
edit: This portion of a down thread comment captures my complaint well:
"In a sane framework, errors are meant to direct you to the cause, not simply to announce that something somewhere is written in a way that the framework doesn't like because of complex reason foo."
Providers are really the only place where this is likely to happen. A FooProvider is an object that provides Foo to the dependency injector. So you tell Angular to provide Foo, and Angular creates the corresponding FooProvider for you. And what sets providers apart from services and factories, is that you can configure your FooProvider before the Foo gets injected, which is very useful, but you are suddenly talking to an object that you never created; Angular did.
By the way, Ruby on Rails does tons of this sort of thing, and goes a lot further. It automatically matches your Person class with the People table in your DB.
Our team chose to use angular admittedly because of its popularity (it's also why we chose bootstrap over foundation, though that probably had smaller repercussions). Most of the rest of the team then ran off to work on other stuff, so I ended up with most of the angular work. It's been at least 8 months now, and I've gotta say the article is pretty spot on.
But I don't really mind anymore for two reasons: I know most of the gotchas now (probably after some loss/whitening of hair), and I haven't used any of the other major frameworks (like ember) to really be able to make an informed comparison.
I don't know if there's a real takeaway here. Maybe "evaluate major contenders even if one is super popular" or "be more vocal when someone tries to blindly railroad in a candidate"?
That happened to me at my last job too. There was no real, actual discussion about what we would use, the party line was "Angular looks like the future of web development" (this claim came from people who spend all their time in C#, not front-end devs).
It only took me a couple days of fooling around with it before I built something useful with it. The steep learning curve is only if you want to know the how-and-why behind every feature of the framework (which I still am not even close to). Learning 100% of the framework is simply not necessary for certain apps.
It's easy in my opinion, it's quick, and it gets the job done. If I run into any problems, there about a bazillion stack overflow post addressing my issue already.
Think so? To me it sounds like the sort of person who leaves messes to get cleaned up by others. No need to learn the tools you're using, just shove shit out the door and let someone else worry about it!
This is absolutely true. When you start out, and have gotten the hang of the main concepts, it's easy, beautiful and a joy to work with.
But eventually you will run into more complex use cases, and the beautiful abstractions of Angular will fall apart. And the problems I run into often only have unanswered questions on Stackoverflow.
There is so much in this article that is disingenuous.
For example point #4 complains that Angular redefines Constructor to mean something else.
The controller constructor IS a constructor, it constructs an instance of a controller and can request and decorate(or construct) a new scope by injecting $scope.
But the debate aside... the quoted revision is over a year old! (It also hasn't reflected the behaviour of the controller constructor for even longer than that, but that's a separate matter.)
The article didn't mention my favourite (ha) pet peeve with Angular, error handling, which makes me wonder about if everyone else doesn't have that problem: even after working with the framework for a couple of months now, I still run, about every other week, into the issue that if something doesn't work, there is exactly zero indication of that. Most prominently misspelled names and parameters of directives. You're lucky if you get an error in the Javascript console, if you happen to have that open all the time.
To me that's infuriating. I get that Javascript isn't Haskell (and I don't even want to go that far into that direction), but the combination of extreme leniency and the remarkable absence of checks is really bad.
Yeah I find it very odd that ng-click="some_function()" doesn't throw up any kind of error if that function isn't defined on the scope (even when you click). Very very frustrating (though maybe I'm missing some setting?).
That is a huge reason why I like to do as little "programming" as possible in templates. When something goes wrong, you either don't hear about it or if you do hear about it, you don't get a stack trace and so forth. Or, you can't find out where in the template the problem is, and instead get a stack trace full of internals of your templating library/framework.
I can see why they did that. Null/undefined checks in templates are messy and ugly, and there are a lot of cases where objects on the scope won't be ready when the scoped element is first rendered.
Templates shouldn't be throwing exceptions for something like customer.name when customer is null. Angular's rendering tries to do something sane by default in a very common case.
If it really bothers you, you can easily write your own click-log-error directive that writes to the console if the function isn't defined.
Actually thanks to Angular's DI system you can replace the base ng-click with one that does throw an error.
I didn't mean the template part in particular, rather think directive arguments, scoping behaviour (the dreaded "wrap your value in an object if you want data-binding").
Sure, not rendering a null value is, while I disagree, a possible choice and certainly useful in certain contexts. However the point about objects not ready should IMO be rather fixed by delaying until the object is ready and I'm actually horsing that if possible so that no uninitialised state is visible at any point.
And again, for production mode you mostly don't want exceptions to pop up, but a strict mode for development is useful. Otherwise someone (who? the customers won't notice this way) has to tell me that some values don't show up (yes, modulo testing).
Replacing those handlers is actually a very interesting idea, I'll try and see how that goes.
i've written a fairly large angular app, and the ng-if case struck me as totally incomprehensible (why the hell would ng-if have its own scope ?).
Then i realized i've never had to use ng-if.
That's not to minimize the trouble you get when you first have to learn about scope inheritance, but I think ng-if may be the only completely non-intuitive directive of the framework.
(As opposed to something like let's say ng-repeat, where you sort of get the intuition that some care will be needed).
"Too complicated" is a huge issue in the real world. It makes code hard to maintain, hard to pass off to others, and hard to reason about. That's the main issue with Angular: it's hard to reason about the code, and it frequently violates the principle of least astonishment.
> Whatever the reason is for Angulars popularity, it isn’t that it’s a great framework.
Something similar to this seems to be true for every piece of programming technology that is popular. How did it come to this? Other professions don't go in masses towards the worst solutions, do they?
"There are only two kinds of languages: the ones people complain about and the ones nobody uses."
-Bjarne Stroustrup
Every piece of tech involves design tradeoffs. Most software benefits from network effects -- there are advantages to using what everyone else is using. Because of that people inevitably end up using software with design decisions they disagree with.
It's worse in programming because their are fewer hard design limits. Everything comes down to preference.
The things that beginners want are often diametrically opposed to the things experts want, and since everyone is by definition a beginner before they are an expert then they will tend to gravitate toward solutions that are beginner friendly (and therefore expert hostile).
To me, this is already revealing. A critique of a web framework and this is the first impression I get? Not off to a good start. There’s a reason people find it hard to trust a fat nutritionist. I see parallels here.
Lately there has been a lot of negative feedback about AngularJS and I have been interested in the critiques of its shortcomings. For this reason, I gave him the benefit of the doubt, pulled up the article on my computer, and dug in.
His initial complaint about prototypically inherited scope properties (Bad Idea #1) being confusing and "literally impossible" to predict was perplexing to me. He states that he understands a child scope will inherit from its parent scope, yet doesn't explicitly instantiate any object on the parent controller in his example of the so-called problem ( http://jsfiddle.net/1op3L9yo/ ). A child of a parent with no properties inherits nothing from its parent -- this seems obvious. If properties are actually defined on the parent the child will inherit them. Is this not the expected behavior?
The "fix" for his "impossible" scenario, is to make sure you explicitly define the property on the parent.
In his specific example, that would look like this:
He complains: "Whether or not a new scope is introduced by a directive is up to its implementer. And if a new scope is introduced, it is up to its implementer to decide if it inherits from its parent scope or not."
How is this a bad idea? I like choices in life, don't you?
He talks about dynamic scoping being a terrible thing. I think the alternative, dictating One True Way of doing things, removes flexibility. This would be far worse than the current status quo of leaving it up to the developer. He advocates for removing this choice altogether, but is there NEVER a good use case for this "dynamic scoping"?
He also complains about the digest loop -- how two-way bindings constantly check for changes and impact performance as your number of bindings grow. There is truth to this, but it is easy to write your own directives that only update UI elements when a change occurs. This can easily be achieved in a variety of different ways. (The most universally familiar of which being a simple callback paradigm.)
Building a quality application with angular requires you to think, but I would argue that designing a performant application with ANY framework demands the same thing. You might initially think you get some things for free, but everything has its costs. If you want things to happen automagically, without needing to be explicit about the needs of your specific use case, that'll cost you. Is this not a near universal truth in programming? People fault the framework when, instead, they should be faulting themselves: their own laziness or lack of clarity.
He talks about having a page listing where their UI already had 2000 bindings and how clicking a "load more" button added another 1000 bindings, killing performance. I can't understand why you would possibly have that many bindings... for ANYTHING, unless you're Doing It Wrong. Why would you need any two-way bindings for explicitly appended information? When the user clicks "load more", we know something needs to change. If performance is a concern, why would you ever allow that listing to be automatically updated by checking for changes on every digest cycle? Instead, you can either explicitly update the element when the action is called (no two-way bindings), or use a SINGLE binding for the...
I've also been using angular for about the same amount of time, and I think a lot of what he's saying is valid. On more than one occasion, a co-worker would come asking for help with a bug and to explain why it was happening was far more complicated than it really should be.
Of course putting enough time on a framework can pay off once you've mastered the tool and know all the caveats. The problem is that if you weigh the pros vs the cons objectively, the cons are not something you can scoff at. Angular has a lot of complexity that is difficult to reason about, and there are a lot of traps along the way to mastery (speaking from experience seeing co-workers shoot their own feet).
For me, the biggest problem is that it throws some seriously useless errors (e.g. race-condition infdig on a route redirect). In a sane framework, errors are meant to direct you to the cause, not simply to announce that something somewhere is written in a way that the framework doesn't like because of complex reason foo. This can be a serious showstopper if you are more than a single developer working on the codebase and even more so if the rest of the team touching the codebase isn't made of Angular superstars (which is often the case).
When I was evaluating Angular, the near deal breaker for me was that the router could only swap a single view area - which is useless for anything more than a trivial "Hello World" example. To build a real app, I would have to divide it into multiple small Angular apps. Is this still the case with core Angular?
I realize there's the third party AngularUI UI Router project. I'm assuming everyone who uses Angular for any real project uses that.
Glad you mentioned this. Not every SPA has a UX that lends itself to nested controllers. The routers and $scope handcuff you. And sibling views in ui-router don't solve the issue either.
Bad Idea #1 : can be prevented easily with `controllerAs` syntax — this is pretty widely accepted to be best-practice, so the approach that he points out should never be used to begin with
Bad Idea #2: can be avoided using gulp. If you are minifying, you should be using gulp anyway, so it’s just a matter of adding a plugin to take care of that
Bad Idea #3: this is true, and you have to take care of it for large-scale applications to prevent performance breakdowns. Since angular 1.3 there are one-time bindings as well.
Bad Idea #4: This sounds like nitpicking from a JS purist
Bad Idea #5: I agree that this stuff is unnecessarily complicated
so yeah… there are many ways that you can break Angular :p learning curve is definitely steep.. and there are plenty of edge-cases that will bite you. Despite all that, it’s pretty powerful at what it does, once you get around it…
130 comments
[ 4.3 ms ] story [ 200 ms ] threadThe kicker is elimination of these concepts: Controllers, Directive Definition Object, $scope, angular.module, and jqLite
Technically, Angular 1.0 also had its own scripting language too. It's kind of inevitable, since Javascript itself is one of the obstacles to making a better web framework.
That, in my opinion, was one of the most terrible ideas I've ever heard come out of the Angular community. And even worse, they refuse to acknowledge that it's a bad idea. That's a very bad sign indeed.
It's the realisation that this is a fundamentally bad idea that was the real kicker for me.
The more you try to write clearly structured, maintainable Angular, the more it begins to resemble React.
Uncaught TypeError: Cannot read property '$$nextSibling' of undefined
By the way, very nice article, and after working with some real time angular apps, the thing that haunt me the most is the number os binds.
People just want more information, and it can hard to explain that we have a limit.
To elaborate: invoking the argument "you reduce to the Halting Problem, suxxor!" without some concrete examples of how the practical problem (i.e. ng-min implementation) encounters difficulties is disingenuous. It's not uncommon to be able to cover some very useful space of a real-world problem, skirting "inside" a problem which is theoretically limited by the Halting Problem or similar. Occasionally you hit a limitation in your algorithm and add a special case, further claiming practical territory from The NP-Complete Beast.
In this case, the strict di enforcement that baconner mentioned in this thread provides an escape hatch: if you're using ng-min while having di enforcement enabled, you'll at least get warned if something goes amiss. If so, add your manual DI annotations, maybe file an ng-min bug, and move along.
Since this shortcoming is hard or impossible to overcome completely, case-specific post-processors to help out the minifier sound reasonable to me.
I think your point about the minifier being "broken" is a good one, but the real problem is with AngularJS in my opinion.
This shortcoming is easy and possible to avoid in the first place, totally eliminating the need for case-specific post-processors to help out the minifier.
Some advice: next time you design a framework, how about designing it not to require case-specific post-processors from the start? Then you won't end up with so many shortcomings that are hard or impossible to overcome completely.
I agree that identifier names should not matter for semantics, but it's quite possible to write JS (and other language) programs that do. So, your first sentence is simply incorrect, it is part of the semantics.
So yes, it's not best practices to do this, but it's not exactly "insane". Constraining your design on non-semantic-preserving minifiers is not the answer.
Also: In your last sentence, like in the linked article, it sounds like you and the author are under the belief that framework/api design is easy - and anyone who gets it wrong is an idiot.
I'd say that angulars behavior here is very unexpected, by mapping parameter names to registered controllers, but I'm not sure if the minifier can be said to be incorrect. If javascript has a way to get the names of the parameters, is it then incorrect to assume this can be used? Strictly speaking if you want to conform fully almost nothing can be minified since object==dictionary but you have to draw the line somewhere, maybe parameter names are moving over that line.
When do you think schools teaching JavaScript should instruct their students how to write easily minifiable code? Is that an appropriate topic for JavaScript 101, or is it more of a graduate level thing?
Can you please suggest any good online course where I can learn this important skill that you're suggesting all JavaScript programmers should have?
Has Doug Crockford written a book called "JavaScript: The Minifiable Parts"?
Does Google test job candidates for the ability to write minifiable JavaScript code on the white board during job interviews, by giving them a dry erase marker that's almost run out?
So do you really believe that the insane scoping madness described in the article, and the fact that Angular's new templates breaks HTML syntax making it impossible to edit/validate/transform/generate/consume them with standard off-the-shelf HTML tools, are really not big issues, and dirt-simple two-way binding outweigh those problems, and are impossible to do without causing those other problems in the first place?
Since the order a user fills out text fields on a web page affects the scope in bizarre unexpected ways, shouldn't Angular automatically disable the offending second text field until the first is filled out, and provide tooltips and help text explaining to users why they're disabled, to force users to enter them in the correct order, that will not undermine the intent of the developer? Is that the kind of implicit magic that you expect from your full service front end web development stack, that makes it all worth it in the end?
Personally, I'd rather have a scoping mechanism that's less magical and astonishing, and more deterministic and predictable. And a templating system that doesn't forsake and reject the rich existing ecosystem of HTML and XML tools.
Yes, this is insane. No, they don't do this anymore. But I'm glad I had the opportunity to do this (on somebody else's dime), because it made me really think about latency and on the performance trade-offs you make to get maintainable code. Code size is not free; many devs think it is, and they write really bloated SPAs as a result. And there's also a lot of low-hanging fruit that doesn't require lots of engineer effort but gives appreciable latency benefits.
The issue is resolved simply by using controller as syntax which is recommended in many blogs. Point taken about the pit of dispair though.
http://jsfiddle.net/sndyxfdk/1/
That being said, it's frontend stuff. The turnaround times are so small that those kinds of bugs are pretty hard to ignore, and very easy to find.
Note: I have used Angular, but don't use it anymore, for other reasons.
There are MANY viable alternatives. No one solution fits all, but some solutions, like Angular, fundamentally suck at everything, because they're terribly designed, and their developers refuse to acknowledge or correct that fact.
In order to answer your off-topic question, which is outside the scope of this article, you'll have to explain in detail all about what your actual requirements and experience and expectations are, and for that you should expect to pay a reasonable hourly rate for an experienced developer to listen to you and give you advice.
If that's what you really want, then good luck finding someone to help you with your problems choosing a decent web framework, but at least you now know that Angular simply doesn't qualify. But if you're just trying to imply that it's not right to criticize Angular without evangelizing an alternative, you're wrong.
That's utter BS. There are lots of very good ideas in Angular. Yes, some of it is not done nice but at the end of the day it's quite a nice framework. Have you even worked with angular?
Also, Angular forces structure on you in ways JQuery doesn't. It makes unit testing viable. I rewrote a javascript slider in Angular, and the code became a lot simpler, shorter and more readable, exactly because of all the stuff Angular abstracts away.
So in comparison with JQuery, the previous best javascript library, Angular has some very clear improvements. How it compares to Ember and Knockout, I have no idea.
But then I tried react and the whole idea of unidirectional event flow made sense, JSX was a little confusing but it was simple to grasp the need and use of it.
Not really. Angular is its own little world of terminology and ideas. I've heard it said that Angular users don't learn JavaScript, they learn Angular.
I really like the acknowledgment that UIs are fundamentally state machines, and React's explicit connection between state and rendering. I do wish they would introduce more featured state transition/events modeling...Something similar to Jake Gordon's javascript-state-machine[1] library would be amazing.
[1] https://github.com/jakesgordon/javascript-state-machine
That annoys everybody. It's that way because the JSX attributes map directly onto the DOM attributes which in turn are named that way to avoid ES3 reserved keywords. It's supposed to be less magic/surprising but far more people interact with JSX (e.g. designers) than work with raw DOM manipulation.
The concepts on Angular have nothing to do with JavaScript. The new changes they propose to JavaScript borrow most from Dart, which in the eyes of a JavaScript programmer is an attempt to turn JavaScript into Java.
and here https://news.ycombinator.com/item?id=8527230
https://hn.algolia.com/#!/story/forever/0/angularjs
Usually stated by people who feel the need to comment in the thread about an article covering a subject they've already read about; just to point out they don't want to read about the subject again. It's like a driving need to spread their negativity towards discussing anything more than once.
The digest loop is highly flawed, as the article describes - it is not performant, and requires disabling for many common scenarios.
Worse, and I don't see this mentioned, is that the digest loop is not tied to any notion of lifecycle - you can accidentally keep retriggering it until you bomb out after 10 loops.
Forgetting to set up your eventing fabric is not a great reason to choose a framework. If you forget to hook up the wires, the view doesn't render properly. This is easily debuggable.
No, what I hate about Angular's DI is that it tries to make inferences about the name you give it, instead of the name being an unambiguous identifier. It does this for "convenience" but it just ends up causing problems and making incorrect guesses.
I'm talking about how, for example, if you have a class called WobbleController, you don't inject 'WobbleController', you inject 'Wobble' and Angular just "figures out" the 'Controller' part. Pretty sweet when it works! Wow, you don't have to type 10 characters! (Good luck grepping for it later, though.)
But when it makes a wrong guess it seems impossible to fix. The other thing that sucks about this is that you have to reload your app to see if Angular will actually be able to find the thing you're injecting. This whole thing is supposed to save time, and it just doesn't. It sucks.
Yes - use a minifier that doesn't break Angular code. Asking me to insert repetitive verbiage isn't an acceptable solution.
And like I say, no way to check that you've fixed the problem except reloading your whole app and waiting for it to show you an error, or not.
The DI looks for 'Foo', can't find it so it looks for 'FooProvider', can't find it, and throws an error saying it can't find 'FooProvider'.
edit: This portion of a down thread comment captures my complaint well:
"In a sane framework, errors are meant to direct you to the cause, not simply to announce that something somewhere is written in a way that the framework doesn't like because of complex reason foo."
By the way, Ruby on Rails does tons of this sort of thing, and goes a lot further. It automatically matches your Person class with the People table in your DB.
But I don't really mind anymore for two reasons: I know most of the gotchas now (probably after some loss/whitening of hair), and I haven't used any of the other major frameworks (like ember) to really be able to make an informed comparison.
I don't know if there's a real takeaway here. Maybe "evaluate major contenders even if one is super popular" or "be more vocal when someone tries to blindly railroad in a candidate"?
It only took me a couple days of fooling around with it before I built something useful with it. The steep learning curve is only if you want to know the how-and-why behind every feature of the framework (which I still am not even close to). Learning 100% of the framework is simply not necessary for certain apps.
It's easy in my opinion, it's quick, and it gets the job done. If I run into any problems, there about a bazillion stack overflow post addressing my issue already.
But eventually you will run into more complex use cases, and the beautiful abstractions of Angular will fall apart. And the problems I run into often only have unanswered questions on Stackoverflow.
For example point #4 complains that Angular redefines Constructor to mean something else.
The controller constructor IS a constructor, it constructs an instance of a controller and can request and decorate(or construct) a new scope by injecting $scope.
But the debate aside... the quoted revision is over a year old! (It also hasn't reflected the behaviour of the controller constructor for even longer than that, but that's a separate matter.)
To me that's infuriating. I get that Javascript isn't Haskell (and I don't even want to go that far into that direction), but the combination of extreme leniency and the remarkable absence of checks is really bad.
Templates shouldn't be throwing exceptions for something like customer.name when customer is null. Angular's rendering tries to do something sane by default in a very common case.
If it really bothers you, you can easily write your own click-log-error directive that writes to the console if the function isn't defined.
Actually thanks to Angular's DI system you can replace the base ng-click with one that does throw an error.
Sure, not rendering a null value is, while I disagree, a possible choice and certainly useful in certain contexts. However the point about objects not ready should IMO be rather fixed by delaying until the object is ready and I'm actually horsing that if possible so that no uninitialised state is visible at any point.
And again, for production mode you mostly don't want exceptions to pop up, but a strict mode for development is useful. Otherwise someone (who? the customers won't notice this way) has to tell me that some values don't show up (yes, modulo testing).
Replacing those handlers is actually a very interesting idea, I'll try and see how that goes.
That's not to minimize the trouble you get when you first have to learn about scope inheritance, but I think ng-if may be the only completely non-intuitive directive of the framework. (As opposed to something like let's say ng-repeat, where you sort of get the intuition that some care will be needed).
ng-model will auto-create scope variables if they don't exist. That's a handy shortcut.
But if you have two inputs that can auto-create variable you're asking for trouble, and you should probably initialize it on the scope constructor.
Or at the very least, use an ng-init so that you know where it will be created.
Something similar to this seems to be true for every piece of programming technology that is popular. How did it come to this? Other professions don't go in masses towards the worst solutions, do they?
-Bjarne Stroustrup
Every piece of tech involves design tradeoffs. Most software benefits from network effects -- there are advantages to using what everyone else is using. Because of that people inevitably end up using software with design decisions they disagree with.
It's worse in programming because their are fewer hard design limits. Everything comes down to preference.
To me, this is already revealing. A critique of a web framework and this is the first impression I get? Not off to a good start. There’s a reason people find it hard to trust a fat nutritionist. I see parallels here.
Lately there has been a lot of negative feedback about AngularJS and I have been interested in the critiques of its shortcomings. For this reason, I gave him the benefit of the doubt, pulled up the article on my computer, and dug in.
His initial complaint about prototypically inherited scope properties (Bad Idea #1) being confusing and "literally impossible" to predict was perplexing to me. He states that he understands a child scope will inherit from its parent scope, yet doesn't explicitly instantiate any object on the parent controller in his example of the so-called problem ( http://jsfiddle.net/1op3L9yo/ ). A child of a parent with no properties inherits nothing from its parent -- this seems obvious. If properties are actually defined on the parent the child will inherit them. Is this not the expected behavior?
The "fix" for his "impossible" scenario, is to make sure you explicitly define the property on the parent.
In his specific example, that would look like this:
$scope.obj = { prop: '' };
( http://jsfiddle.net/355fuxk5/ )
He complains: "Whether or not a new scope is introduced by a directive is up to its implementer. And if a new scope is introduced, it is up to its implementer to decide if it inherits from its parent scope or not."
How is this a bad idea? I like choices in life, don't you?
He talks about dynamic scoping being a terrible thing. I think the alternative, dictating One True Way of doing things, removes flexibility. This would be far worse than the current status quo of leaving it up to the developer. He advocates for removing this choice altogether, but is there NEVER a good use case for this "dynamic scoping"?
He also complains about the digest loop -- how two-way bindings constantly check for changes and impact performance as your number of bindings grow. There is truth to this, but it is easy to write your own directives that only update UI elements when a change occurs. This can easily be achieved in a variety of different ways. (The most universally familiar of which being a simple callback paradigm.)
Building a quality application with angular requires you to think, but I would argue that designing a performant application with ANY framework demands the same thing. You might initially think you get some things for free, but everything has its costs. If you want things to happen automagically, without needing to be explicit about the needs of your specific use case, that'll cost you. Is this not a near universal truth in programming? People fault the framework when, instead, they should be faulting themselves: their own laziness or lack of clarity.
He talks about having a page listing where their UI already had 2000 bindings and how clicking a "load more" button added another 1000 bindings, killing performance. I can't understand why you would possibly have that many bindings... for ANYTHING, unless you're Doing It Wrong. Why would you need any two-way bindings for explicitly appended information? When the user clicks "load more", we know something needs to change. If performance is a concern, why would you ever allow that listing to be automatically updated by checking for changes on every digest cycle? Instead, you can either explicitly update the element when the action is called (no two-way bindings), or use a SINGLE binding for the...
Of course putting enough time on a framework can pay off once you've mastered the tool and know all the caveats. The problem is that if you weigh the pros vs the cons objectively, the cons are not something you can scoff at. Angular has a lot of complexity that is difficult to reason about, and there are a lot of traps along the way to mastery (speaking from experience seeing co-workers shoot their own feet).
For me, the biggest problem is that it throws some seriously useless errors (e.g. race-condition infdig on a route redirect). In a sane framework, errors are meant to direct you to the cause, not simply to announce that something somewhere is written in a way that the framework doesn't like because of complex reason foo. This can be a serious showstopper if you are more than a single developer working on the codebase and even more so if the rest of the team touching the codebase isn't made of Angular superstars (which is often the case).
I realize there's the third party AngularUI UI Router project. I'm assuming everyone who uses Angular for any real project uses that.
Bad Idea #2: can be avoided using gulp. If you are minifying, you should be using gulp anyway, so it’s just a matter of adding a plugin to take care of that
Bad Idea #3: this is true, and you have to take care of it for large-scale applications to prevent performance breakdowns. Since angular 1.3 there are one-time bindings as well.
Bad Idea #4: This sounds like nitpicking from a JS purist
Bad Idea #5: I agree that this stuff is unnecessarily complicated
so yeah… there are many ways that you can break Angular :p learning curve is definitely steep.. and there are plenty of edge-cases that will bite you. Despite all that, it’s pretty powerful at what it does, once you get around it…