
Lessons Learned: A Year with a Large AngularJS Project - joelhooks
http://joelhooks.com/blog/2013/05/22/lessons-learned-kicking-off-an-angularjs-project/
======
jasallen
I think people who've worked a lot on 'classic' web pages misunderstand some
things. Angular and other MV* frameworks are not out to replace or add on to
JQuery or Underscore or any other JS toolkits. They _are_ out to replace Rails
and ASP.Net and Zend. Or at least large parts of what _those_ apps used to
handle.

You will still use all your JS tools, it is your server tools that will get
lighter-weight as page flow and layout are (exclusively sometimes) moved to
the client. Ideally your server logic returns only JSON and otherwise your
server is a file host for HTML, JS, CSS.

Edit: my comment is in response to some other comments I've seen, not the OP.

~~~
olegp
This may be the case for pure single page apps, but any real world application
will have some pages you want to load faster and have easily indexed by search
engines.

At <https://starthq.com> we started out as a single page app with a RESTful
API using Angular, but with time it has become apparent that there are certain
public pages that need to have the HTML generated server side. Now we have a
hybrid solution, where some parts of the page are generated on the server and
others, namely the parts that are different for anonymous and logged in users,
on the client.

We've experimented with the likes of <https://github.com/apiengine/seoserver>
but the truth of the matter is it's actually easier to generate the HTML
server side than using Angular.

~~~
prodigal_erik
Yikes, Angular can't generate semantic HTML at the server yet? That explains
why <http://docs.angularjs.org/misc/faq> is such a trainwreck. Letting crap
like

    
    
      <a href="{{page.url}}">{{page.shortName}}</a>
    

go out on the wire to be uselessly displayed by arbitrary clients (even
ordinary browsers that don't blindly trust your scripts) is a really severe
failure mode.

~~~
troygoode
Um, Angular runs on the client. "Generating semantic HTML at the server" isn't
Angular's job.

------
abrkn
I used to have a problem, so I thought to use AngularJS. Now I have a
ProblemDirectiveFactory. <http://stackoverflow.com/a/15253892/521834>

Show me any code that cannot be written faster and shorter using only jQuery,
Underscore templates and a CommonJS compiler. Does not exist. You are writing
enormous amounts of glue code to please AngularJS and getting lost in your
obsession with tools, imagined reusability and over-complicated testing
procedures.

~~~
marknutter
You are completely missing the point of directives. Your proposed alternative
strategy of using "only jQuery, Underscore templates and a CommonJS compiler"
will leave you with DOM manipulation code entangled with your controller logic
and a nearly untestable mess. Directives are meant to encapsulate any code
that directly deals with manipulating the DOM so that stuff doesn't leak into
your model or controller logic.

You of course don't have to throw everything into directives but then you risk
making your code less portable and your tests more brittle. Wrapping a jQuery
plugin in a directive is so trivial it's not even worth mentioning, and it
certainly doesn't result in "enormous amounts of glue code to please
AngularJS".

> over-complicated testing procedures

And this is where you showed your hand. You can't have written tests for an
angular app because if you had you wouldn't have made such a bizarre
statement. Angular's dependency injection combined with the fantastic Karma
test runner makes testing an absolute breeze.

~~~
kaeawc
> so trivial it's not even worth mentioning

If it is so trivial then it 'is' worth mentioning. Give an example or
reference. Personally I like Angular, but I'm learning and finding articles
like the OP's are great to read to have others' perspectives on how to work
with it.

~~~
adamnemecek
E.g. [http://amitgharat.wordpress.com/2013/02/03/an-approach-to-
us...](http://amitgharat.wordpress.com/2013/02/03/an-approach-to-use-jquery-
plugins-with-angularjs/)

------
dustingetz
dear bloggers and commenters, you really need to qualify "large". "Large"
probably means something between 10k LOC and 1M LOC and the approach to coding
at either end if this spectrum is vastly different.

For example, I'm at the 50k mark on the frontend and I found angular's basic
building blocks to be too restrictive in terms of organizing things into
reusable components. I had to answer questions like "can views do I/O", "does
a view own his model", "how deeply should views nest", "should my models be
tree-like or rectangular", "can my contracted designer write arbitrary markup
with arbitrary UI widgets or does the framework not like that". Angular's way
of doing controllers with dependency injection got in my way of answering
these questions. I would love to read someone's opinions on this, especially
if I'm wrong, but nobody (including me) has time to write a well thought out
essay on this.

~~~
chaddeshon
I agree. I think when people say "large" they mean that spaghetti jQuery code
wasn't working anymore. I was able to get to 10K LOC with a well thought out
hombrew jQuery framework (Angular, Backbone, etc weren't available when we
started), and it was still fairly maintainable. As I approach 20K lines of
code it is getting out of hand. I would like to switch the project o Angular.

I'd love to hear more about the problems/questions you are having. Have you
found answers to some? Here's what I have come up with. How does it compare to
what you are doing?

 _"can views do I/O"_ I've put file I/O in a controller. If I would have
needed to share it across multiple pages, then I would have put it in a
service

 _"does a view own his model"_ I have model classes defined outside of
Angular. Services access my API to create new objects (of types defined by my
models). Controllers request data from the services. The service figures out
if it already has the data or if it needs to call the API.

 _"how deeply should views nest"_ I often wonder how much I should be breaking
up my views into smaller view. For the moment, I only create "subviews" if I
am going to reuse the subview in another view. This has lead to some large
template files. I may need to reconsider if they get much bigger.

 _"should my models be tree-like or rectangular"_ I don't understand what you
are asking. What's the difference?

 _"can my contracted designer write arbitrary markup with arbitrary UI widgets
or does the framework not like that"_ Again, I'm not sure what you are getting
at. Arbitrary markup and UI widgets as apposed to what?

~~~
dustingetz
i do believe i have answers to all those questions; its really something that
i need to write an essay about, a short blog post or HN comment can't do it
justice. If enough people upvote this or ask me on twitter, maybe I will write
something up this week.

~~~
grinich
You should really do this. The Angular docs are OK, but don't make any
discussion about these larger questions. There some scattered posts on the
mailing lit about different approaches, but that's it.

------
jlongster
I have a hard time adopting frameworks because of the all-or-nothing aspect of
them. If you use Angular, you have to use their templating language, right? I
know that they do a lot of powerful things with it, but honestly it's
difficult for me to throw away _all_ of my current tools. It's just too much
of a jump.

There's so much I love about libraries like angular and ember, but I'd love it
if someone was working on a way to allow additional templating languages. I
don't know how it would work, but you could possible compile other templates
down to angular templates.

I've been thinking of a way to convert simple templates in angular's style, so
that you can do all the cool auto-updating features. If there was a standard
for this, templates like mustache, etc could compile a subset down to it.

Disclaimer: I'm the creator of nunjucks
<https://github.com/jlongster/nunjucks>.

~~~
ww520
Try use Knockout.js. I also don't like the heavy weight tools like
Bootstrap/Ember/Angular with their my-way-or-the-highway approach. Knockout.js
does bidirectional two-way view-model binding and other MVVM goodness without
insisting you have to abandon other tools. You can use other template engine
easily.

~~~
encoderer
I can only assume you've never actually used Backbone (Which I also assume is
what you meant when you said 'bootstrap'). It's neither heavy or "my way or
the highway."

Knockout is great, but the two-way bindings do come with a non-trivial
performance impact.

------
onehp
Everytime I read an Angular postmortem I'm intrigued that I never see memory
issues being raised.

In a recent rewrite of one of our applications into Angular we had huge issues
with it consuming memory. I think our use case is quite distinct, we have a
telephony component that needs to stay loaded so single page app really does
mean single page app for us, but even so I would expect to see memory
mentioned every now and then.

~~~
zenocon
I haven't had significant memory issues with Angular. Have you profiled your
app? Where is the large portion of memory being consumed. The apps I'm
building are being deployed on an embedded system with a custom WebKit --
where the memory constraints are significant (the hardware has a total of
about 400MB RAM for everything) -- so I'm pretty conscious about memory
issues, and we did test/profile Angular on this hardware and did not find
issues.

That isn't to say you still can't shoot yourself in the foot with Angular
(especially with something like ng-repeat). There are ways to code an Angular
app with an eye on memory / performance, and there are ways to do the
opposite, but I don't feel like the framework itself introduces significant
overhead.

~~~
onehp
It seemed it was detached DOM elements that were causing most of the problems.
We tried profiling with the Chrome dev tools but found it very difficult to
pinpoint where to start looking from the thousands of elements generated
every-time we repeated our workflow.

In the end we looked at the bottom line memory consumption and experimented
until we saw reductions. We found using things like ng-show instead of ui-if,
essentially preloading the partials and switching between them instead of
reloading everytime, saved us enough memory to make the system viable.

~~~
sgrove
We've had similar problems before (outside of angular), and the lack of
visibility and tooling is horrendous.

However, at Google I/O they demoed the new object allocation tracker, which
seems like a vast, vast improvement. Highly recommended for figuring out where
memory is leaking and what code is causing it.

Here's the session:
[https://www.youtube.com/watch?feature=player_embedded&v=...](https://www.youtube.com/watch?feature=player_embedded&v=x6qe_kVaBpg&t=24m10s)

Still pretty primitive, but progress at least.

------
michaelw
I'd add a few more thoughts.

Keep your controllers lean and mean. Put more of the UI logic into services.
This makes testing a lot easier.

Only use routing ($route, $routeProvider) if your app has very little UI state
and could reasonably thought of as several totally independent pages. I
switched to managing $location.path() explicitly and haven't looked back.

Embrace promises throughout your app. Angular templates can now render
promises naturally but I've found that I prefer to be more explicit:

    
    
      $http.get(url).then(function(response) {
        $scope.something = response.data;
      }, function(error) {
        $scope.$emit('error', error);
      });
    
    

Wrapping jquery widgets in directives often results in more code than just
doing it yourself. Obviously this increases your maintenance surface area but
typically less than you would expect.

The Angular Bootstrap project is trying to create directives that avoid jquery
and could be bound (with different templates) to other UI frameworks. What I
really want is a core set of UI widget directives and then separate (bootstrap
or foundation inspired or not) CSS libraries for styling them.

~~~
joelhooks
really good points. We were "promise shy" and I'm now completely sold and in
love with them.

We actually use a Command implementation that I ported, which has been really
handy for leaning up the controllers, plus they aren't stateful so they are
always available. <https://github.com/joelhooks/js-command-center>.

------
gizzlon
Took his advice and opened up a random angular source file. Found this fun,
little snippet:

    
    
      // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
      // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
      // with correct but slower alternatives.
      if ('i' !== 'I'.toLowerCase()) {
        lowercase = manualLowercase;
        uppercase = manualUppercase;
      }
    

Looks like Angular is more battle-tested than I would expect..

~~~
iso8859-1
It's a weird comment because the definition of "correct" is not specified. Is
it a workaround for a bug in Unicode or a bug in its implementation?

~~~
taeric
The bug is developers not realizing that a capital "i" is not universally
constant. That is, there is no bug in either unicode nor implementation. Just
something highly non-obvious to the rest of the world.

------
danso
Having just built a hobby Angular.js app, it's cool to see that it fits large
aims. For personal use, I found it incredibly refreshing to use, even as
bizarrely different as it was to anything else I've tried. Not in a bad way,
but in the sense that it was more convention than I was used to (outside of
Rails)

I would add that the Yeoman build manager is an absolute delight to
structuring and managing your project. It was so slick that when making my
first Angular app, I also ended up learning CoffeeScript to kill two birds at
once...Yeoman made this otherwise prickly situation as smooth as possible.

And I also would agree that directives are Angular's killer feature...and
unfortunately for me at the time, one of the hardest to grok because of their
magic. Anyone writing an Angular tutorial would do a great service to
emphasize the power and use cases for directives.

~~~
thisone
re directives

two places really helped me go from wtf to, "hey I can do that!" (and now I'm
onto transclusions)

<http://www.egghead.io> as mentioned

and the Angular meetup video about directives:
<http://www.youtube.com/watch?v=WqmeI5fZcho>

The documentation for Angular is dense. As in I've found myself having a lot
of "ahah!" moments from reading 3 words.

I'm actually starting to annotate it on my blog as I find stuff out.

All that being said, I'm using Angular to make single page app prototype very
quickly, coming from having no experience creating single page apps, but with
a fair few years of MVC under my belt.

~~~
joelhooks
The angular internals is another great resource for directives, as the
framework itself uses them heavily.

------
VilleSalonen
Can anyone point me to real world AngularJS project with a healthy amount of
unit and end-to-end tests? I've read the tutorials from official site and
elsewhere on the web but they seem to stop after showing how create a
controller with mock $http. As a relatively novice JavaScript developer, I'd
like to see more comprehensive examples with mock services etc.

------
cletus
I too have built a reasonably sized Angular app in the last year [1] and echo
a lot of these thoughts. I'll add a few of mine:

1\. For CSS, honestly for any project it'd be hard for me not to simply use
Bootstrap and be done with it and then do the minimum CSS possible (I say this
as someone who has been doing CSS for years). Bootstrap really is the de facto
CSS for the modern Web;

2\. Organization: I agree the angular-seed project (which I started with and
still use) isn't suited to organizing large projects and I agree separating
into functional modules is the way to go;

3\. Directives are awesome but to get all the two way data binding working
requires a fairly deep understanding of how they work (to get the correct
combination of scopes, transclusion, etc);

4\. Directives also have limits that are sometimes annoying. You still can't
generate definition list items with an ng-repeat, for example (a template has
to have one top-level element). A solution to this is coming;

5\. There's no good way of both just including code and using the parent scope
plus some extras. This is done for reasons of code separation but there really
is a use case (IMHO) for includes vs imports for templates;

6\. $resource has no HTTP PUT method;

7\. I'd probably avoid $resource altogether although it looks attractive. Use
rich objects [2] instead;

8\. Angular allows you to use a bunch of different other frameworks but it
doesn't always play completely nice with them. Take the popover in Bootstrap.
The way this works is by moving an element around in the DOM. This doesn't
lend itself to a "nice" Angular directive (my version at least is kind of a
hack).

9\. Underscore.js is awesome. Use it;

10\. Try to limit yourself to using jqLite that Angular comes with rather than
full jQuery. This isn't really possibly with any reasonable part of Bootstrap
however;

11\. Isolate scopes in directives results some weird and unexpected behaviour.
For example, if you reference something with an attribute, it'll work if it's
an object (including an array) but won't with a simple value, requiring you to
put such values in objects just so the directive can get a reference to it.
This tripped me up a few times;

12\. Scopes aren't always truly isolated either. For example, you can get
tripped up by this if you have two attribute directives on the same element.

[1]: for those who follow IO, I am the Tech Lead of the Open Bidder project at
Google ([http://googleadsdeveloper.blogspot.com/2013/05/announcing-
op...](http://googleadsdeveloper.blogspot.com/2013/05/announcing-open-bidder-
beta-platform.html))

[2]: <http://stackoverflow.com/a/11850027/18393>

~~~
beggi

          10. Try to limit yourself to using jqLite that Angular comes with rather than full jQuery. This isn't really possibly with any reasonable part of Bootstrap however;
    

Can you explain this better?

~~~
ganarajpr
Angular renders the most used parts of JQuery useless, if you use Angular the
"right" way. If we do consider it, two of the most used parts of JQuery are
$.ajax and querying the DOM.

Because angular already provides you $http and $resource which are more than
capable of doing everything that $.ajax does - $.ajax and all its variant that
JQuery brings in become redundant.

Because of the way Angular is and because of its philosophy of directives -
You generally dont need to query the DOM at all most of the time ( like 90% of
the time ). For the rest of the 10% of the time when you do need to query the
DOM, you only need to go one step below a directives element (direct
children). If you are doing anything more complex, then you are doing
something wrong again. For this basic case, Angular already provides you
JQLite which is capable of doing the querying for simple scenarios like this.

About the helper functions that JQuery provides - angular too provides quite a
few helpers - and they are sufficient for like 95% of the cases. For other
stuff you might want to consider underscore.

So, why do you need to include JQuery?

~~~
jacques_chester
> _So, why do you need to include JQuery?_

Because it's the foundation of jQuery UI, and JQUI has modules that I don't
feel like writing myself from scratch (sortable nested lists).

Still, the joins between Angular and JQUI (through AngularUI) are fairly
visible. It's not a smooth ride at the moment.

------
zenocon
I agree on this. Angular is awesome for organizing large JS, and making re-
useable components. Directives are a killer feature, along with DI (to
facilitate testing) and 2-way binding (to eliminate all the boilerplate glue
you'd have to write with something like Backbone). The team I'm on recently
set up a fantastic Grunt build that incorporates Jade, Stylus, Angular, Google
Closure Compiler along with testing infrastructure that works with CI/Jenkins
using Mocha, Phantom, Sinon, Chai. It makes developing web apps fun again.

Right now, we don't pull in any other libraries aside from Angular. We've
found we don't need jQuery anymore, and are able to build up re-useable
widgets with directives and use them across projects.

~~~
Kiro
Re-usable widgets with directives sounds great but the problem I have (with
widgets in general?) is that every situation requires a slightly different
widget which means the directive gets polluted with conditionals and stuff.
For me it sounds good in theory but never works in practice.

------
skype
I too have built a reasonably sized Angular app in the last year [1] and echo
a lot of these thoughts. I'll add a few of mine: 1\. For CSS, honestly for any
project it'd be hard for me not to simply use Bootstrap and be done with it
and then do the minimum CSS possible (I say this as someone who has been doing
CSS for years). Bootstrap really is the de facto CSS for the modern Web; 2\.
Organization: I agree the angular-seed project (which I started with and still
use) isn't suited to organizing large projects and I agree separating into
functional modules is the way to go; 3\. Directives are awesome but to get all
the two way data binding working requires a fairly deep understanding of how
they work (to get the correct combination of scopes, transclusion, etc);

------
pmaccart
One of the issues I struggled with while toying around with AngularJS was how
to load the many scripts (controllers, directives, etc.). Is there any
suggested reading out there on how to perform this without just including a
bunch of script tags on the page? Or, is this considered more of a build tool
problem, where the scripts should all be concatenated, then loaded as a single
file?

~~~
smhinsey
I use require.js for this. There are a number of seed projects out there to
get you started, but I suggest not following them too closely. Once you
understand the basic technique it's easier to figure out your own
organizational structure. My main suggestion is to discard the seed project's
suggestions of organizing things into directories like /controllers, etc., in
favor of organizing the files around specific screens. This reduces friction
when it comes to using things like route resolves, which are a huge pain if
you have the routes in a routes.js and the controllers in
controllers/MyController.js.

~~~
pmaccart
Thanks -- I had tried going down the requirejs route with all controllers
loaded into a 'controllers' module, directives into a 'directives' module,
etc., and felt like I was writing way more boilerplate code than should be
necessary with a framework like Angular. I'll have to revisit using requirejs
with more of a page/functionality-oriented structure.

~~~
smhinsey
Yeah, I don't get that approach at all. I started with that, ran into a case
where I wanted a route resolve, couldn't figure out how to do it without a
huge amount of hassle, and ended up reorganizing around screens. I do still
have global services, directives, and filters, but I define them as close to
screens as I can and only pull them up to a global scope when necessary. The
module-per-screen approach makes a lot of sense from both Angular and
Require's perspective, I think.

We use the optimizer as well, during our build process, so you can use require
to load everything during development and then optimize everything down into a
single file later. The optimizer is pretty powerful and supports several
different scenarios for doing this.

------
andreypopp
If you like directives in Angular.js but use Backbone or simply want something
which is not so much opinionated then you might like to take a look at
Backbone.ViewDSL[1] which provides data-binding and custom directives for
Backbone.View

[1]: <https://github.com/andreypopp/backbone.viewdsl>

------
maaaats
I liked the part about structuring the code/files. As you, I'm not a fan of
the seed-app where you have one js file for controllers, one for directives
etc. Makes it hard to find the stuff I'm looking for, and there _will_ be
merge conflicts.

------
metaphorm
thanks for the post. this was a good read. I'm about to start work on a medium
sized Angular project and this kind of thing is very helpful.

I didn't see any mention of your backend for the project, but I did get the
impression it was something Java (why else would you be using Maven?). I'm
looking to be writing angular templates on top of a django backend (supplying
a RESTful api for data access). I'd love to read more about integrating
Angular with RESTful backends.

~~~
GeneralMaximus
> I'd love to read more about integrating Angular with RESTful backends.

If your backend exposes a textbook REST interface, integrating it with
AngularJS is almost no work at all. $resource is all you need. In case you
have one or two non-RESTful endpoints here and there – and honestly, who
doesn't? – $http is your friend.

In an app I'm working on, I have a front-end built with Angular talking to a
Tastypie back-end. Since Tastypie implements all the boring REST CRUD for you
automagically, integrating the two took about fifteen minutes total.

If there are there any specific questions/issues on your mind, ask away.

~~~
cunninghamd
Do you have an example of TastyPie and AngularJS working together? I've got a
straight-forward CRUD app (mostly) that AngularJS will be great for, but
wrapping my brain around it all and an API has been difficult.

~~~
GeneralMaximus
Unfortunately, I don't know of any such examples.

Here's something I found while Googling around:
<https://github.com/dalcib/angular-phonecat-mongodb-rest>. It doesn't use
Django and Tastypie, but you may find at least the front-end code educational.

I personally completely separate my front-end and back-end code. So while the
API is built with Django, the front-end doesn't go through Django at all. It's
served straight through nginx without doing anything special except maybe some
simple URL rewrites for prettier URLs.

If I'm not too tied up in college work this week, I might do a write up on
Tastypie and Angular integration.

------
Kiro
Can someone explain why I should use any of the tools listed in The Build? Why
do I need to add that layer of complexity?

~~~
joelhooks
I added it based on a comment. Yeoman is interesting because it has "rails
like" generators. This can be nice on a project of size, for consistency and
saving time.

Yeoman uses Grunt, which is nice for building, watching, and packaging.

Not strictly needed, but very useful and recommended.

------
brandonsowers
We learned the same lessons with the chat function Babblr. Structuring the
code/files is highly affective.

------
don_draper
Wow. Strong opinions on both sides of the debate.

------
skype
Hi

