30

I need advise on designing an AngularJS application with multiple complex modules and based upon the user role the module gets loaded after authentication & authorization. Some users could have access to one simple module and some could have dashboard and some could have access to 2+ modules.

There are lot of directives we have identified which can be reused across different modules. During the design phase we have identified the following things that should exist and we have answers for some of the below items, but we still need advice from experts:

  • A Module could have
    • Partials
    • Controllers
    • Directive
    • Services
  • Exception handling (HTTP Status code or Business errors)
  • Logging (With line number, from which function)
  • May also need to save the logged info in the server
  • Should have the ability to turn on and off logging
  • custom widgets via factory class (Reused in other modules)
  • Shared Directives (isolated scope)
  • Shared Modules
  • Shared Utilities (sorting, filtering, etc.)
  • Enumerators as per master data
  • Constants via singleton
  • Authentication (CSRF)
  • offline storage
  • REST services
  • Event handling for dispatching from one module and handling it in other

UI of the application looks like, a fixed menu bar on the top of the page with a drop down navigation on top left with multiple links depending on the user's role. When the user clicks on a link the corresponding module should get loaded in the page. There has to be an empty project which is manually bootstrapped and loads the other modules at run-time.

Our approach is to have the following folder structure:

  • app
    • assets
      • css
      • lib js
      • images
    • common components
      • directives
      • utilities
      • authentication
      • Service proxy to hold the $resource calls
      • Enums
      • Constants
    • Model
      • entity json (example customer, product, etc.)
    • business Module A
      • Partials
      • Directives
      • Services
      • Controllers
    • business Module B
    • business Module C
    • index.html
    • Requirejs config file

So my questions are:

  • How can a service inside a module talk to other module?
  • Module should be developed and run independently?
  • How the communication between module can be handled with transferring data?
  • How to integrate all the above elements, particularly exception handling, logging?
  • Developers should understand the convention we have defined?
  • What method to call for logging, sending info between module?
Kara
  • 6,115
  • 16
  • 50
  • 57
Sabha B
  • 2,079
  • 3
  • 28
  • 40
  • 1
    I think the full example is here http://ify.io/using-requirejs-with-optimisation-for-lazy-loading-angularjs-artefacts/ – Shohel Sep 16 '14 at 17:21
  • Thanks Shohel , we have handled the lazy-loading. My doubt is more towards how to design a scalable application with 20+ developer can work minimum dependency. And how to bring all the feature together with some convention defined. Trying to draw and architecture diagram. – Sabha B Sep 16 '14 at 17:27
  • No problem. They will work only their page wise javascript file, like controller, service, and directive, you have to create a common service, factory. – Shohel Sep 16 '14 at 17:32
  • If you want I can help you. I am senior developer of angular js. – Shohel Sep 16 '14 at 17:35
  • 1
    I want to learn many thing, you have not pay to me for any suggestion of design of angular large scale application. every day i am free from 7PM to 11 PM (GMT +6). you can try for any help over skype – Shohel Sep 16 '14 at 17:44
  • 1
    RequireJS is not recommended to be used with AngularJS (http://stackoverflow.com/questions/12529083/does-it-make-sense-to-use-require-js-with-angular-js/18615865#18615865), if you are looking for project structure that works well with large teams and large projects, you should read this: https://github.com/toddmotto/angularjs-styleguide (made by Todd Motto, a Developer Expert at Google) – TheSharpieOne Sep 16 '14 at 18:14
  • 3
    Best is john papa https://github.com/johnpapa/angularjs-styleguide – Shohel Sep 17 '14 at 02:57
  • Too much to explain here, but at least I'd recommend the [Angular seed project](https://github.com/angular/angular-seed). Take a look at the dir structure. And also don't forget your tests. You should have unit and E2E tests! – Onur Yıldırım Sep 24 '14 at 20:49

3 Answers3

15

I recommend to include yeoman into your workflow and use a generator for your project, that makes a lot easier the way that you structure your app, specially if you are working in a team.

earlier this year people from angular released a document with best practices for your app structure, I'd recomment you to read it, being said that there's a generator based on those best practices named cg-angular which I totally recommend.

I'll quote from cg-angular site:

All subgenerators prompt the user to specify where to save the new files. Thus you can create any directory structure you desire, including nesting. The generator will create a handful of files in the root of your project including index.html, app.js, and app.less. You determine how the rest of the project will be structured.

regarding to your questions:

  • How can a service inside a module talk to other module?

you can create a folder for directives/ and services/ you are going to reuse in different modules.

  • Module should be developed and run independently?

you can have several modules inside an app (you could load them as needed, maybe using require js but this is offtopic)

  • How the communication between module can be handled with transferring data?

Use services to pass information between controllers, in different modules

  • How to integrate all the above elements , particularly exception handling, logging?

you can do a generic error handler and a generic http interceptor for all the modules

  • Developers should understand the convention we have defined?

use a generator they are opinioated and they give the order and the conventions you need for a team.

Heemanshu Bhalla
  • 3,603
  • 1
  • 27
  • 53
pedrommuller
  • 15,741
  • 10
  • 76
  • 126
9

Lots of good questions to be asking; they appear to be in two major groups -- the first is a question of code structure and the second is about metrics (logs, etc.).

How can a service inside a module talk to other module?

You should ideally be using directives for your modules. This way you can leverage the ability to link controllers via the require property. Here is a page on sharing data between directives and controllers.

Module should be developed and run independently?

I assume you're thinking about unit testing. Yes, your modules should ideally be as tightly-scoped as possible in order to make testing easier.

How the communication between module can be handled with transferring data?

This is where services are typically used. Note: services, factories and providers all mean the same thing in AngularJS, they're just declared in slightly different ways. Pick whichever one you're most comfortable with.

How to integrate all the above elements , particularly exception handling, logging?

Logging is a separate issue. The beauty of AngularJS is that you can very easily augment existing parts of the framework in order to add functionality or behaviors as you see fit. You do this using decorators. Here is an example of exception logging that I think will cover any use cases you might be interested in

Developers should understand the convention we have defined?

The answer to this is always the same: communication is how they know. Developers need to socialize the convention otherwise you'll never get buy-in.

What method to call for logging , sending info between module?

Answered above.

Matt Brock
  • 5,337
  • 1
  • 27
  • 26
7

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 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/ 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 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:

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', RegistrationController]); view rawUserModule.js hosted with ❤ by GitHub 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:

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. 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. 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. 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 fire an event to perform some action and then receive a notification that the action completed. Quick Note on Assets and Tests

I think there's more room for flexibility 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.

Please have a look at the below link,

https://blog.safaribooksonline.com/2014/03/27/13-step-guide-angularjs-modularization/

Archana
  • 387
  • 1
  • 5