Professional Documents
Culture Documents
CLIFF MEYERS
Code Organization in Large AngularJS and JavaScript Applications
Many developers struggle with how to organize an application's code base once it grows in size. I've
seen this recently in AngularJS and JavaScript applications but historically it's been a problem
across all technologies including many Java and Flex apps I've worked on in the past.
The general trend is an obsession with organizing things by type. It bears a striking resemblance
to the way people organize their clothing.
You know your black wool socks are in that pile in the corner but it's going to take a while to dig
them out.
This is a mess. People shouldn't live like this and developers shouldn't code like this. Once you get
beyond a half-dozen or so controllers or services these les become unwieldy: objects you're
looking for are hard to nd, le changesets in source control become opaque, etc.
Nice! Objects can now be located easily by browsing the le tree or using IDE shortcuts, changesets
in source control now clearly indicate what was modied, etc. This is a major improvement but still
suers from some limitations.
Imagine you're at the oce and realize you need a few outts dry-cleaned for a business trip
tomorrow morning. You call home and ask your signicant other to take your black charcoal and
blue pinstripe suits to the cleaners. And don't forget the grey shirt with the black paisley tie and the
white shirt with the solid yellow tie. Imagine that your signicant other is completely unfamiliar with
the your dresser and wardrobe. As they sift through your tie drawer they see three yellow ties.
Which one to pick?
Wouldn't it be nice if your clothing was organized by outt? While there are practical constraints like
cost and space that make this dicult with clothing in the real world, something similar can be
done with code at zero cost.
Modularity
Hopefully the trite metaphors haven't been too tedious but here's the recap:
Your signicant other is the new developer on the team who's been asked to x a bug on
one of the many screens in your app.
The developer sifts through the directory structure and sees all the controllers, models and
services neatly organized. Unfortunately it tells him/her nothing about which objects are
related or have dependencies on one another.
If at some point the developer wants to reuse some of the code, they need to collect les
from a bunch of dierent folders and will invariably forget code from another folder
somewhere else.
Believe it or not, you rarely have a need to reuse all of the controllers from the e-commerce app in
the new reporting app you're building. You may however have a need to reuse some of the
authentication logic. Wouldn't it be nice if that was all in one place? Let's reorganize the app based
on functional areas:
cart/
CartModel.js
CartService.js
common/
directives.js
lters.js
product/
search/
SearchResultsController.js
SearchResultsModel.js
ProductDetailController.js
ProductModel.js
ProductService.js
user/
LoginController.js
RegistrationController.js
UserModel.js
UserService.js
Any random developer can now open the top-level folder and immediately gain insight into what
the application does. Objects in the same folder have a relationship and some will have
dependencies on others. Understanding how the login and registration process work is as easy as
browsing the les in that folder. Primitive reuse via copy/paste can at least be accomplished by
copying the folder into another project.
With AngularJS we can take this a step further and create a module of this related code:
1
2
3
4
5
6
7
8
9
10
11
12
13
view raw
3
4
5
6
7
8
9
10
11
12
13
view raw
If we then place UserModule.js into the user folder it becomes a "manifest" of the objects used in
that module. This would also be a reasonable place to add some loader directives for RequireJS or
Browserify.
$ Share
! "
100 Likes
$ Share
Newer
Older
Comments (34)
Oldest First
Preview
raul Arabaolaza
Post Comment
A year ago
Great post, I wonder if you could add some more gists to show how you dene your controllers or
services. Just for all of us that dont know yet all the possible ways to declare a service/controller
Phaedryx
A year ago
hcentelles
A year ago
Nicolas Hery
A year ago
Completely agree! I've been exploring this kind of organization as well for my Backbone app (I use
Browserify). I also have a common or core folder with things shared by all modules.
One of the challenges I still haven't quite solved is the "assets" bit. I'm trying to keep them separated
in each module (vs a global "assets" folder). I have quite a bit of shared styles in the common folder,
notably Sass or LESS variables to dene colors, type, etc. That means the styles in each module will
have to remain in Sass or LESS until the whole application is built.
I'm also exploring making it really easy to work on one piece (module) at a time, and to do so, being
able to boot the app with only "common" and that particular module (let's say "cart"), and maybe
"user" (for me it's part of "common"). Right now I'm doing that at the "debug" build step, where I
have a custom Grunt.js task that allows me to specify a particular module to only build the app with
that module and it's "common/core" dependencies. If I don't, it builds the whole app. Have you
considered that? I guess I'm also trying to make it so I could, if I wanted, put a module in its own
NPM or Bower package.
Thanks for the post!
Cheers,
Nicolas
Aaron Smith
A year ago
You've got "return new UserModel" in your userModel factory. I'm curious to see where UserModel
is dened, and what it looks like.
I usually keep my logic in my controllers, which is probably not the best way of doing it, and would
like to mimic what you've got going. Would be nice to get insight into what's behind that UserModel
object.
Donny V
A year ago
I actually use a combination of Sock Drawer and Modularity. I keep les seprated by type but name
the les by modules.
root
--imgs
----idv.TOC
-------image1.png
-------image2.png
--css
----idv.TOC.css
----SiteFeaturesAddressSearch.css
----SiteFeaturesCustomSearches.css
--js
----idv.TOC.js
----SiteFeaturesAddressSearch.js
----SiteFeaturesCustomSearches.js
This works really well for me because when in debug mode each le for css and js are loaded
separately. Also I can make sure css are loaded at the top of page and js les are at the bottom.
When the site is set to release mode my minication and merging code can nd the les easily and
stream them as only 2 les.
Sean Brookes
A year ago
Thanks for this post. I have been working with backbone for a year or so now but am seriously
thinking it might be time to make the leap to Angular (or even Meteor) but was a little put o by the
suggested structure from the angular-seed project.
the current structure I have migrated to for my backbone/marionette projects (w/require.js) is as
follows:
/mod1/
- mod1.controller.js ( similar to the manifest le above)
- mod1.models.js
- mod1.views.js
- mod1.templates.html
/mod2/
- mod2.controller.js
- mod2.models.js
- mod2.views.js
- mod2.templates.html
with a global 'EventBus' used to facilitate communication between models and the application
'controller'.
So far it's proving to be a pretty solid structure especially in combination with requirejs but it still
doesn't make up for some of the core problems with backbone in general, hence the consideration
of Angular as a next step.
so thanks again for posting about an alternative organization structure that makes a little more
sense to me.
A question I have though is around pub/sub in Angular. I see you mention it in point #4
(emit/broadcast/on) above but I haven't seen it in any examples or tutorials yet. are there any good
examples out there you can point to?
Sean
TJ Holowaychuk
A year ago
Spreading related things into multiple directories isn't really modularity IMO, pros and cons of each
approach I suppose but I denitely found these rails-style approches really annoying in the past,
certainly not what I would call modular.
Thomas Haukland
Nice article. I've always tried to structure code after the domain instead of the techniques used.
What the code does is always more important than HOW it does it.
Cli Meyers
@raul @aaron @sean I'll have a follow-up post soon which will show the tiered architecture we're
using on a large enterprise app plus a few other enhancements I plan to use on my next app.
Cli Meyers
A year ago
Suman Paul
A year ago
I would prefer to have folder for directives and lters as well, with each directive/lters in their own
le.
JavaScriptBank
A year ago
Matt Styles
A year ago
I agree too, just seems logical to group this way. Just made sure that my own little boilerplate for
Angular starts o like this https://github.com/mattstyles/yeoman-angular-express-plus
Joshua Gough
A year ago
This is really nice, and I am interested creating a RequireJS example of what you have done, if
nobody else has already done so.
A year ago
Jason Yang
A year ago
A year ago
Could you explain what should be in service, model and controller? thank in adv
btw, great post
Nick Perkins
A year ago
The fonts and colors on this page make it very hard to read!
Arush
A year ago
praveen vedanth
A year ago
We don't want to load all the controller les on rst load. Could you please throw some light on lazt
loading of controller les only when required. ?
fyjs
A year ago
Curious if you've ever seen, or recommend, adding lters to your individual modular objects. I
denitely can see using a common lters.js, but should you put all of your lters in there, or should
you move your lters specically for the users view to UserFilters.js?
Wesley Overdijk
A year ago
I absolutely loved this post. I've set up a structure like this, and someone pointed me to this article
showing me why I did it. Thank you.
I do, however, have a single question for you.
At the end of "Modularity" you said: "This would also be a reasonable place to add some loader
directives for RequireJS or Browserify."
Would you mind explaining this a bit more? What's a "loader directive"? Because I am, in fact, using
browserify.
Naser Tahery
A year ago
hi
my structure is below :
for example user section
.
.
---user Folder
------ Controller Folder
----------- LoginController.js
----------- RegistrationController.js
------ Model Folder
----------- UserModel.js
------ Service Folder
----------- UserService.js
.
.
Do you accept this structure?
max
A year ago
Great example! Coming from PHP development, it looks to me more or less like Symfony2 Bundle
structure idea.
Cheers
Darryl
A year ago
I was happy to stumble upon your article and see that you organized your les in almost the same
way I did. The one exception is that I consider models to be common. For example you show a
folder for Cart, Product and User, each having their own models, but Cart would use its own model,
plus the Product model and the User model, which in my mind makes them common.
Food for thought...
Joao Grassi
A year ago
Nice post! I'm new to angularJS and It would be nice if you provide a project with this strucure. I'm
very confused on how to "connect" separeted controllers in my app. Thanks!
Jon
A year ago
Hey Cli,
I had a look at your repo on github and nd you need to declare extra namespaces to store class
denition so later you can instantiate those inside manifest.
Do you think in the end, manifest le actually cause more trouble than benet?
anony
7 months ago
Thanks
Cody
6 months ago
Great post. I think your clothing analogy works well and ows with the topic.
Roman Boiko
3 months ago
Have been doing this for a few years. The same idea but with some .NET specics:
http://www.ndepend.com/Res/NDependWhiteBook_Namespace.pdf
Kaushik
3 months ago
Shinu Suresh
2 months ago
Really good post for a newbie like me. Its a good kickstart point for my new app
2 months ago
Wonderful article to have a good idea about best approach of working with ng.
Thanks a lot.
Nazmul Hasan
I'm a Solutions Architect for Universal Mind, a digital solutions agency specializing in applications that deliver a
unied multiscreen customer experience.
RT @StoneBrewingCo: BIG THANKS to all who vied for #StoneEast. We now know our East Coast brewery site.
CHECK IT http://t.co/lFYrVY2eTa #beer #craftbeer #RVA
2 months ago
iOS 8s predictive QuickType keyboard found to suggest parts of your passwords http://t.co/HxTQvul90p
2 months ago
RT @trochette: Friday was my last day @universalmind. 2 years working on amazing projects, traveling and
learning. I'll miss you guys!!
2 months ago
Follow @climeyers
Twitter
Linkedin
Google
Facebook
Github