
Mistakes AngularJS Developers Make - davidkellis
http://www.airpair.com/angularjs/posts/top-10-mistakes-angularjs-developers-make
======
lars
This is possibly better called a list of framework design mistakes made by the
AngularJS team.

#3: The fact that the default dependency injection mechanism breaks when
minified means it should never have been included. If this mechanism sneaks in
anywhere in your app (and there are plenty of third party libs that use it),
it wont start breaking until you bundle and minify the code, at which point
you may already be in production.

#5: The service/factory distinction adds a conceptual complexity that is
completely unnecessary, as demonstrated in this blog post.

#7: Having too many watchers will slow your app down to a crawl on a desktop
machine, and be even worse on a phone. This happens more easily than you'd
think and it's fundamentally caused by Angulars reliance on its digest loop.
This loop is the essence of how Angular works, and it means that there are
tons of applications that cannot ever run efficiently if they're built on
Angular.

8#: Because of the way their $scope system works, it is actually literally
impossible to tell what the the meaning of ng-model="foo" is by reading the
program. It may in fact depend on the order in which the user interacts with
elements of the web page. Consider this example:
[http://jsfiddle.net/7kkxLkxh/](http://jsfiddle.net/7kkxLkxh/) What foo binds
to is dependent on which input you type into first. Yes, there are ways to
avoid this, but it should have been avoided by either disallowing this
construct, or requiring foo to be declared before it is used. (If you miss a
var in JS, you get a global - that turned out to be bad language design.
Removing the var keyword and effectively deciding on variable scope at runtime
is certainly a much worse language design.)

After working on a large Angular project, it is clear to me that there are a
lot of ideas in there that are frankly not good. It's sad that there seems to
be very little discussion anywhere about the downsides of the various
frameworks that are out there.

~~~
nawitus
>#3: The fact that the default dependency injection mechanism breaks when
minified means it should never have been included. If this mechanism sneaks in
anywhere in your app (and there are plenty of third party libs that use it),
it wont start breaking until you bundle and minify the code, at which point
you may already be in production.

I think the real mistake in that scenario is not minifying the code until "in
production". You should minify your code from the day one.

Although I agree that the "not safe for minifying" mechanism shouldn't have
been included in AngularJS.

On the other (other) hand, it's pretty abhorrent that minifying is something
that developers need to actually place any thought into..

~~~
boydjd
> I think the real mistake in that scenario is not minifying the code until
> "in production". You should minify your code from the day one.

How are you debugging minified code?

~~~
nawitus
That's a big problem. Firefox and Chrome these days support debugging source
mapped files. However, I'm running through two source map steps: TypeScript to
JavaScript and JavaScript to minified JavaScript. For whatever reason the
browser debuggers don't work that well with this setup. They're buggy and make
the browser _very_ slow. I often do have to resort to "console.log" debugging.
On the plus side I'm always running code like it's run in "production", which
will make it easier to catch any bugs resulting from minifying.

~~~
kaoD
I use Webpack with a similar setup (CoffeeScript->JavaScript->Minified) and I
didn't notice any issues. Source maps stop working when using Webpack's hot
code reloading, but it's a price I'm willing to pay.

------
troybetz
Grouping files by feature has made navigating and reasoning about a codebase
so much easier. I've even found myself grouping stylesheets & test files
alongside templates and app code, it really helps enforce the idea of
composing smaller apps together.

Google has released a recommended app structure similar to this as well [0],
though I haven't actually seen it being used too often in the projects I've
come across.

[0] -
[https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDz...](https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/)

~~~
maaaats
I understand the grouping of the JS files by feature. But I have a hard time
including the partials/HTMLs with that. Because when building (concat, minify
etc) the project, they will then need to be copied around and all template-
references updated.

It's easier instead to just dump all of them into one place and copy that
folder, no need to update references etc. then.

Any ideas on how to solve this?

~~~
dougcorrea
I use this Yeoman generator that uses a very good structure like recommended
above [https://github.com/cgross/generator-cg-
angular](https://github.com/cgross/generator-cg-angular)

~~~
jzig
We're using the same generator for a large government app. "Widget" partials
are stashed in their respective folders under /widget while /services,
/directives, and so on are contained in the root folder. HTML/CSS/JS stored in
each folder. It's all super organized and modular IMO. Of course it helps to
be working with the creator of said generator.

------
mfrisbie
These types of articles are great, but too frequently I see phrases such as,
"It makes testing much simpler" sprinkled throughout them without any
justification. These claims are generally not untrue, but it seems like it
would be appropriate to demonstrate scenarios of the unit and e2e tests
actually being affected by decisions in the application code.

~~~
hcho
Apologies if this comes across as unsolicited advice; but if you really
struggle with this, your software dev fundamentals are weak. Before learning
frameworks, you should focus on concepts like decoupling, single
responsibility, etc...

~~~
thisGuysAccount
upvoted because software developers who avoid heavily testing their code, and
the use of code analysis tools, are often surprised once they start testing
and analyzing their code.

------
benlesh
It's a good article, but a good portion of these aren't "mistakes" but rather
"opinions".

#1 isn't a "mistake" it's a preference, really. Also, I'm really not sure
about putting the template files in the directory with the other files. Then I
guess I'd have to add something to my build script to copy them to a hosted
directory?

#3.1 IMO, Is actually more of a mistake. Imagine you have 3-4 modules, which
one do you define that underscore service in? Oops, better make a 5th "common"
module, I guess. Just to include something that you could have injected with
$window. Notably, the underscore service is also missing that it should be
injecting $window. How is he going to test that? Scrap the whole underscore
service, and just inject $window where you need something from the global
scope.

#9.1 Protractor - Protractor is great. But it's a little hefty for true "unit"
tests. Jasmine with `angular-mocks` works a little better for unit testing
Controllers and Services, where Protractor is better at testing directives and
full end-to-end tests.

and one thing I'd add to this list:

#11 - Overly "DRY" Jasmine tests.

A lot of Angular developers I know are way too fond of drying up their Jasmine
tests with nested describe() blocks and lots of beforeEach() clauses. Tests
should really be "DAMP" not "DRY".

~~~
benaiah
DAMP?

~~~
wtetzner
Descriptive And Meaningful Phrases

[https://stackoverflow.com/questions/6453235/what-does-
damp-n...](https://stackoverflow.com/questions/6453235/what-does-damp-not-dry-
mean-when-talking-about-unit-tests)

~~~
thisone
as an industry, we really love those backronyms

------
joesmo
I disagree with #10 (Using jQuery). Why would I rewrite perfectly good widgets
(jQuery plugins) in Angular (or any other library) when I can create a thin
Angular wrapper around them? Because the philosophy is different? That's
hogwash. At the end of the day, you're still manipulating HTML no matter what
library you use or don't. This is pure nonsense, not to mention impractical,
and bad advice.

~~~
ejdyksen
I think a better way to phrase #10 is "Don't do DOM manipulation anywhere
other than a directive."

If there's a complex jQuery widget (say, a date selector) that works well for
you, then wrap it in a simple directive and be done.

I've done this a number of times with no problem.

~~~
jaunkst
This is the way to go. Sometimes you just have to build your own from scratch.

------
maaaats
Point 3 about "Dependency injection" is often not needed. Just use ng-annotate
before minify/uglify, and it will convert the code to the array syntax for
you. It handles most of the cases, leaving your code without the ugly array
stuff.

It doesn't work for everything, though, so suddenly it blows up. So if you
want to be 100% sure your code works as intended do it manually.

~~~
thathonkey
It sounds like you talked yourself into doing it the way the author in the
article suggests halfway through your post :)

~~~
maaaats
Well, yeah, deployed a minified angular app yesterday, and ng-annotate handled
almost everything except a controller that's initialized a custom way. So it
broke. :(

~~~
olov
That occasionally happens when you do things in non-standard ways, although
ng-annotate has become quite smart lately and can now follow references and
more. Did you use the latest version (also feel free to open an issue)? ng-
strict-di in AngularJS 1.3 will greatly improve the error messages for these
situations.

------
jcampbell1
This is all really great advice. The only thing I would add is that the number
of watches is important, but the type of watch (reference vs value) is also
important.

I have seen people make Angular charts, and they use deep value type watches
that kill performance. It is fine for angular to watch a massive array with
time series data, but use a reference watch, and swap out the array when the
data changes.

People talk about the scalability of Angular's dirty checking, but in my
experience the number of watches should be roughly the number of interactive
elements in the user interface. Since there are limits to how much interface a
human brain can process, the theoretical problems of dirty checking are not
real problems in practice. If you have more than 2000 interactive elements on
a page, then you probably have a different problem, not an angular problem.

------
mckinnsb
Hey - #8 regarding "consulting the prototype chain if the value is an object"
is something of an oversimplification, and slightly incorrect. The prototype
chain is more or less always consulted because that is the only way to
evaluate the property on a child scope.

What is happening in the first example is that the ng-bind directive is
creating a new entry on the child scope, called "user", which overwrites the
reference to the property defined in the parent scope. When you ng-bind an
attribute of an object, your child scope is not changing the reference to the
original object, so both scopes will show updates.

Example fiddle:
[http://jsfiddle.net/02f4o7u9/1/](http://jsfiddle.net/02f4o7u9/1/)

~~~
nuclearghost
Yeah I agree it's an oversimplification. It's tough when writing a piece like
this where a deep level of language knowledge is required to make a clear
explanation. I tried to lead people toward the cause without getting bogged
down in too many details.

Thanks for the example!

------
yesimahuman
The modules one isn't necessarily true. I'm seeing a lot of Angular devs keep
things under one module (esp for libraries). I don't think the value of
multiple modules has really been realized. Exs: we do this for Angular
Material and Ionic.

~~~
nuclearghost
Hey I'm the author of the article. I created a library of modules that were
reused across single page apps. For individual libraries I agree it doesn't
make sense, but not enough people take advantage of the module system

~~~
tericho
At the moment breaking a monolithic app into modules has little benefit, but
is theoretically a beneficial practice to take advantage of future Angular
features. I'm speculating but my guess would be some sort of lazy-loading
system will be implemented.

I can't find the exact article I read where the authors discussed this, but I
did find a presentation by Brian Ford[1] that touches on the subject.

[1][https://docs.google.com/presentation/d/1Gv-dvU-
yy6WY7SiNJ9QR...](https://docs.google.com/presentation/d/1Gv-dvU-
yy6WY7SiNJ9QRo9XayPS6N2jtgWezdRpoI04/)

------
AdamCraven
On point 1: "AngularJS is, for lack of a better term, an MVC framework."

It is not an MVC framework. The angular team even describes it as an MVW
framework (the W stands for Whatever).

Angular on its own does not provide enough structure to work on large
projects. It requires a better structure than using directories called
'controllers', 'services' and 'directives'. These are just angular concepts
that do not translate well into understanding of what functionality should go
in each directory. If you've worked on a larger project, you may have already
seen this problem.

Angular documentation is not very helpful in pushing this point to the
developer, however. It recommends[1] the use of 'services' as the place to do
all business logic, which causes many projects to put most of the code in the
'services' directory.

To work on larger projects, you should create the MVC structure to fill in the
gaps that angular does not provide. Creating top level folders such as:
Models, View Controllers, Controllers, Endpoints (server communication). And
using services, not as a top level folder, but as a way to instantiate
components.

[1]
[https://docs.angularjs.org/guide/concepts](https://docs.angularjs.org/guide/concepts)

------
rezistik
I've never understood the pattern of separating out services, controllers and
directives into different modules. Your post controller is probably going to
need your post service, so why put them in separate modules? Makes more sense
to have a post module with your WYSIWYG directive, post service, post
controller, etc.

Every time I see it I just wonder aloud, what problem did you think this
solved?

~~~
emgeee
I think it was such a ubiquitous pattern in tutorials and apps early on that
it became a norm people didn't question. As the author mentioned, it isn't
really something that matters too much until you really start to build a
complex app.

In my own experience, I've found taking such a modular approach too early on
can actually hinder productivity as I find myself spending too much time on
boilerplate and figuring out if, for example, this service REALLY belongs with
feature X or feature Y.

------
knicholes
9: There are no excuses for not testing an AngularJS app, I have never
actually written unit or integration tests.

The author mentions nothing of protractor's use of selenium webdriver and how
it does blackbox testing of your app. There is no mention of Karma interacting
with your app's code for integration tests, as well. They talk about unit
tests under the "Protractor" header, but integration tests can be run both by
Karma and Protractor.

9.2: "Once integration tests have been written using Protractor?" Karma and
Protractor are both test runners that support tests written for Jasmine (among
other various JS testing frameworks). Perhaps the author meant to say "Once
integration tests have been written using Jasmine."

Also, I fail to see how, "Waiting for tests to run, especially integration
tests, can be frustrating for developers" has anything to do with Karma.

The rest of the stuff was useful, but the author clearly has never even
coherently used these testing tools.

------
bicknergseng
That first (and, to the extent that the author relates the two, second) point
feels pretty dubious. I imagine most adherents of the "directory by feature"
camp come from the Django-like world, while "directory by type" campers have
Rails-like backgrounds. I haven't found a concrete, objective reason to use
one over the other. I tend to find a hybrid, "directory by feature"
organization mirrored in each of the MVC roles to be the best of both: easy to
find all views or models at once and therefore easy to spot and combine
functionality across similar models or views, but also easy to find all files
related to a feature via grep/fuzzy searches/navigating through the same
directory names from different starting points.

~~~
nuclearghost
I think what you describe is a great approach.

The reason I claimed it was a mistake for angularJS devs was that angular seed
and yeoman lead to doing directory by type, which I think becomes a burden as
an app scales.

------
ilovecomputers
I think this the first Angular article I read that actually showed a
functional difference between Factory and Service: factory can return a
constructor function, service can't. Personally, I have my factory be an
actual factory by having it posses a method that returns a new instance of an
object.

------
riffraff
> Whether using Sublime, Visual Studio, or Vim with Nerd Tree, a lot of time
> is spent scrolling through the directory tree.

There might be a lot of reasons to use dir-by-feature or dir-by-function but
if the above is a problem you should probably get a better editor.

EDIT: or use yours better.

~~~
shangxiao
I actually close my file browser "side bar" in Sublime and just open files
with the "Goto" command (⌘ P). With strict naming conventions I find this to
be quicker than navigating a file browser.

------
joshfinnie
These are great suggestions!

I really enjoy 1, 9 and 10. Learn something new everyday.

------
seaghost
Best of advices and guides are here [https://github.com/johnpapa/angularjs-
styleguide](https://github.com/johnpapa/angularjs-styleguide)

------
andrew1601
Not mentioned: Coding things so that your site content is invisible to the
Google search engine. Which is ironic considering Google's support of Angular

~~~
yid
Except that the crawler now executes a lot of Javascript:
[http://googlewebmastercentral.blogspot.com/2014/05/understan...](http://googlewebmastercentral.blogspot.com/2014/05/understanding-
web-pages-better.html)

------
tbatterii
great advice here, I would have liked to see some code examples for #4, b/c I
am currently struggling with a ng codebase where the controller are doing way
too much in my opinion. using ui-router helps some, but, I would love to see
more ways to keep the controllers slim.

------
davexunit
The biggest mistake is using AngularJS. Been there, done that.

------
insertnickname
Mistake #1: Thinking it is a good idea to use AngularJS or any other JS
framework that reimplements _loading a page_.

