Sie sind auf Seite 1von 17

Menu

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.

Piles on the Floor


Let's take a look at angular-seed, the ocial starting point for AngularJS apps. The "app" directory
contains the following structure:
css/
img/
js/
app.js
controllers.js
directives.js
lters.js
services.js
lib/
partials/
The JavaScript directory has one le for every type of object we write. This is much like organizing
your clothes into dierent piles on the oor. You have a pile of socks, underwear, shirts, pants, etc.

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.

The Sock Drawer


The next logical pass at organizing JavaScript involves creating a directory for some of the
archetypes and splitting objects into their own les. To continue the clothing metaphor, we've now
invested in a nice mohaghony dresser and plan to put socks in one drawer, underwear in another,
and neatly fold our pants and shirts in still others.
Let's imagine we're building a simple e-commerce site with a login ow, product catalog and
shopping cart UI's. We've also dened new archetypes for Models (business logic and state) and
Services (proxies to HTTP/JSON endpoints) rather than lumping them into Angular's single "service"
archetype. Our JavaScript directory can now look like this:
controllers/
LoginController.js
RegistrationController.js
ProductDetailController.js
SearchResultsController.js
directives.js
lters.js
models/
CartModel.js
ProductModel.js
SearchResultsModel.js
UserModel.js
services/
CartService.js
UserService.js
ProductService.js

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

var userModule = angular.module('userModule',[]);


userModule.factory('userService', ['$http', function($http) {
return new UserService($http);
}]);
userModule.factory('userModel', ['userService', function(userService) {
return new UserModel(userService);
}]);
userModule.controller('loginController', ['$scope', 'userModel', LoginController]);

userModule.controller('registrationController', ['$scope', 'userModel', RegistrationContro

UserModule.js hosted with by GitHub


1
2

var userModule = angular.module('userModule',[]);

view raw

3
4
5
6
7
8
9
10
11
12
13

userModule.factory('userService', ['$http', function($http) {


return new UserService($http);
}]);
userModule.factory('userModel', ['userService', function(userService) {
return new UserModel(userService);
}]);
userModule.controller('loginController', ['$scope', 'userModel', LoginController]);

userModule.controller('registrationController', ['$scope', 'userModel', RegistrationContro

UserModule.js hosted with by GitHub

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.

Tips for Common Code


Every application has common code that is used by many modules. We just need a place for it
which can be a folder named "common" or "shared" or whatever you like. In really big applications
there tends to be a lot of overlap of functionality and cross-cutting concerns. This can be made
manageable through a few techniques:
1. If your module's objects require direct access to several "common" objects, write one or
more Facades for them. This can help reduce the number of collaborators for each object
since having too many collaborators is typically a code smell.
2. If your "common" module becomes large subdivide it into submodules that address a
particular functional area or concern. Ensure your application modules use only the
"common" modules they need. This is a variant of the "Interface segregation principle" from
SOLID.
3. Add utility methods onto $rootScope so they can be used by child scopes. This can help
prevent having to wire the same dependency (such as "PermissionsModel") into every
controller in the application. Note that this should be done sparingly to avoid cluttering up
the global scope and making dependencies non-obvious.
4. Use events to decouple two components that don't require an explicit reference to one
another. AngularJS makes this possible via the $emit, $broadcast and $on methods on the
Scope object. A controller can re an event to perform some action and then receive a
notication that the action completed.

Quick Note on Assets and Tests


I think there's more room for exibility with respect to organizing HTML, CSS and images. Placing
them in an "assets" subfolder of the module probably strikes the best balance between
encapsulating the module's asset dependencies and not cluttering things up too much. However I
think a separate top-level folder for this content which contains a folder structure that mirrors the
app's package structure is reasonable too. I think it works well for tests as well.

$ Share

! "
100 Likes

$ Share

Newer

Older

Comments (34)

Oldest First

Preview

raul Arabaolaza

Subscribe via e-mail

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

and add it to a module

Phaedryx

A year ago

I think angular-app is a good example of the style: https://github.com/angular-app/angular-app

hcentelles

A year ago

Take a look at ng-boilerplate http://joshdmiller.github.io/ng-boilerplate/#/home by Josh David Miller


a active member of Angular community.

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

A year ago 1 like

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

A year ago 1 like

@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

@nicolas The bootstrapping of a single module is a great way to accelerate development. We


actually did some of that back in the day with Flex applications. If you have nice clean modules and
easily mockable/pluggable dependencies then that bootstrapping process becomes a lot easier. We
aren't currently using this technique on my current project but I'd like to get there. Thanks for
sharing!

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

great tips to organize web apps better, thanks for sharing

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.

Nick Van Weerdenburg

A year ago

Nice article. I'm all for the second organization by function.


I feel strongly that the rails-style controllers/views/models separation is a mistake. It took the Rails
Community 5 - 7 years before they stopped writing poorly structured applications due to the implicit
lack of modularity and abstraction that encouraged. It was funny watching Rails go from the skinnymodel-era to the skinny-controller-era and now to the skinny-model and skinny-controller, lets use
services and design patterns era.
IMHO the concept of a component or package MUST be a top-level abstraction in any sane software
structuring approach. And a directory lls this denition just ne.
I also feel that AngularJS apps should be written to enable a "zip and ship" philosophy. i.e. you can
take your app/ directory, zip its contents, and unzip into /var/www on an Apache, nginx, or Node.js
server and be o and running.
If we follow that strategy we can hopefully hasten the death of PHP.

Jason Yang

A year ago

@nick how does frontend dev related to PHP? :/


@chris Thanks for the article, I'm always struggling to decide on the "perfect" folder structure, your
article helped clear up some things I didn't think about.

Chok Wee Ching

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

Interesting. We take a slightly dierent approach, in our boilerplate http://brandid.github.io/parseangular-demo/

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

Great post. Thanks

Shinu Suresh

2 months ago

Really good post for a newbie like me. Its a good kickstart point for my new app

Nazmul Hasan Sarkar

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.

AngularJS AOP Books Eclipse Flash Flex Git Hibernate HTML5

Java JavaScript jQuery Localization Mac Mustache


OOP Sencha Touch Spring Subversion Testing Tools
On The Twitter

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