AngularJS Abstractions: Organizing Modules

Tuesday, May 7, 2013

imageNow that we know a bit about how modules work at an API level, we can look at questions that will be asked more than once in the lifetime of a project, like when to create a module, how many modules to create, and how to organize source code files for a module.

One thing to recognize early on is how much flexibility is available. Although the term "module" sounds like the JavaScript module design pattern (a single function inside a single file), there is nothing about an AngularJS module that requires all the code for a module to exist in a single file, or in a single function. Your code can use multiple JavaScript modules to add features to a single AngularJS module.

The code below is creating an alerter service to add to the patientApp.Services module, and could be one of many such pieces of code scattered across various files.

(function () {
    var alerter = function () {
        // ...
    };

    angular.module("patientApp.Services")           
           .factory("alerter", alerter);
}());

Given this amount of flexibility, there are no real limitations on the number of modules and files you create.

Use an approach that causes the least amount of friction for you and the team. Factors to evaluate include the test and deployment strategy and the reusability of a module across multiple apps. Managing the dependencies of a large number of modules produces friction. Building large monolithic modules can also produce friction. Somewhere in between is a sweet spot.

Reference Material

There is already some good material out there on organizing file and modules.

The Angular Seed project recommends creating one module for controllers, one for directives, one for filters, and one for services. I'm not a fan of choosing this approach as a default.

Brian Ford has a post on Building Huuuuuuge Apps with AngularJS. Brian suggestion: "Each file should have one "thing" in it, where a "thing" is a controller, directive, filter, or service".

Cliff Meyers also believes in one thing per file in his post "Code Organization in Large AngularJS and JavaScript applications". I like that Cliff uses a dedicated folder for models instead of throwing in models with services or controllers.

Finally, Jim Lavin has "AngularJS Modules for Great Justice" and talks about the concepts of "package by layer" versus "package by feature".

One scenario I haven't found addressed very well is the scenario where multiple apps exist in the same greater web application and require some shared code on the client. I'll try to blog about this one in the future, but we'll visit some of the other AngularJS abstractions first.


Comments
gravatar dtheodor Friday, May 10, 2013
Very nice reference material there. I have a remark though. You keep referencing the example where you add functionality to a module from a different file. This is nice to illustrate what Angular is capable of, but if you actually follow this practise isn't it like shooting yourself in the foot? I mean, instead of having the 'main' module ('patientApp.Services' in this case) 'import' functionality from low level modules ('logger', 'alerter'), you have the 'main' module oblivious to what is imported to it, and you perform the import at the low level modules. So, instead of having the typical importing procedure in the following generic example ============= file: main_module -------------------- import logger logger.log(...) ============ file: logger_module ------------------- define log(...) { ...} What you actually do is ============= file: main_module -------------------- logger.log(...) #where did logger come from? ============ file: logger_module ------------------- import main define log(...) { ...} main.add_module(self) #oh this is where it came from This reminds me of the http://en.wikipedia.org/wiki/COMEFROM control structure.
gravatar dtheodor Friday, May 10, 2013
Slightly cleaner syntax of what I refer to: http://pastebin.com/8EUejEam
gravatar Scott Friday, May 10, 2013
@dtheodor Sorry about the lack of formatting in the comments. I think I understand the question, but if not I apologize. Typically it is the top level module that stitches together the lower level modules. This way the lower level modules don't need to know about each other. I think it is a good idea when defining the module and the dependencies to keep all that in one place so it is easy to see the relationships in a large app.
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!