Code Organization in Large AngularJS and JavaScrip

6476 단어 AngularJSorganization
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 official starting point for AngularJS apps. The "app"directory contains the following structure:
  • css/
  • img/
  • js/
  • app.js
  • controllers.js
  • directives.js
  • filters.js
  • services.js
  • lib/
  • partials/

  • The JavaScript directory has one file for every type of object we write. This is much like organizing your clothes into different piles on the floor. 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 files become unwieldy: objects you're looking for are hard to find, file 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 files. 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 flow, product catalog and shopping cart UI's. We've also defined 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
  • filters.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 file tree or using IDE shortcuts, changesets in source control now clearly indicate what was modified, etc. This is a major improvement but still suffers from some limitations.
    Imagine you're at the office and realize you need a few outfits dry-cleaned for a business trip tomorrow morning. You call home and ask your significant 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 significant 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 outfit? While there are practical constraints like cost and space that make this difficult 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 significant other is the new developer on the team who's been asked to fix 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 files from a bunch of different 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
  • filters.js
  • product/
  • SearchResultsController.js
  • SearchResultsModel.js
  • search/
  • 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 files 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:
    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', RegistrationController]);

    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.

    좋은 웹페이지 즐겨찾기