Tag Archive for: best practices

Client Code Structure, Part 1: Model Files

Having good code structure is important to making any project successful.  In order to learn good code structure you first need to know what code structure means.  To me, it means both how you split different pieces of functionality into different files as well as how you organize the code within your files themselves.

Code structure is not something that you can usually find good examples of.  This is because unless the point of the example is to demonstrate good code structure it is usually more effective to get to the point of the functionality instead.  The example code from AngularJS is usually short and has a very limited scope making it a poor candidate for an example of code structure.  Pretty much all functionality in the examples within Angular’s documentation takes place within the controller file and this is how we originally structured our code.


angular.module('ModuleName').controller('ControllerName', 
   [ ...injected dependencies...
      function( ...injected dependencies... ){
         ...Do Stuff...
      }
   ]
);

This structure started off fine, until we needed to share properties across controllers. The solution was actually pretty simple to handle this. We simply created a SharedProperties object and injected it into each controller which needed it. We could even add SharedProperties to scope and any changes to it anywhere would show up in the view in which is was bound.

angular.module('ModuleName').controller('ControllerName', 
   [ '$scope', 'SharedProperties', ...other injected dependencies...
      function( $scope, SharedProperties, ...other injected dependencies... ){
         $scope.SharedProperties = SharedProperties;
         ...Do Stuff...
      }
   ]
);

This worked fine for a while, but as our need for adding shared properties grew, so did our SharedProperties file. Eventually, the file looked like this:

angular.module('Derby.services').service('sharedProperties', [function () {
    return {
        selectedDivisionId: 0,
        divisions: [],
        selectedDivision: null,
        raceYears: [],
        selectedRaceYear: null,
        RaceYearId: 2012,
        RaceYear: 2012,
        isUserLoggedIn: false,
        isUserAdmin: false,
        loggedInUser: null,
        collapseResources: false,
        sharedResourcesURL: "",
        imagePath: "/Derby/Apps/Shared/Assets/Images/",
        attemptingLogin: false,
        collapseChampionshipRound: false,
        drivers: {},
        divisionHeatCache: {},
        isUserLoggedInViaFacebook: false,
        facebookAccessToken: null,
        facebookUser: null,
        selectedHeat: null
    };
}]);

A loose collection of properties thrown together because we couldn’t find a better place to put them. Property files this large makes properties difficult to find, and therefore difficult to debug.

Even though the SharedProperties technique was being abused and was becoming unwieldy, that didn’t mean it was all bad. In fact, it reminded me of a similar technique used in ActionScript. The only difference was that we would create multiple files and each would hold only properties relevant to a single concept. These are known as “Model” files. This way we could inject only the properties we need and not worry about the rest. This methodology is maintainable, much cleaner, and easy to debug.

divisionModule.factory('DivisionModel',
  [
    function () {
      return {
        divisions: [],
        selectedDivision: null,
        manageDivisionInUrl: true

      }
    }
  ]
);

This file is injected and used in the same manner as SharedProperties, just only as needed.

 Next -> Client Code Structure, Part 2: Controller Files

Client Code Structure, Part 2: Controller Files

After separating shared properties into their own Model files, the next thing I ran into was that our controller files were getting large and unwieldy. This was especially the case for our main app.js file. I realized that this was because it contained a loose collection of methods thrown together because we couldn’t find a better place to put them (Sound Familiar?) I thought, “Wouldn’t it be nice if we could conceptually group these methods and separate them into different files just like we did with the models?”

It turns out you can! As I built this file I noticed that it reminded me of a controller file. Then I thought, “Wait, don’t we already have a controller?” It was at this point that I realized that what Angular calls a “Controller” is actually a “ViewModel” and what I was creating was a standard “Controller.” With this in mind, I kept view-specific methods in the ViewModel and created a controller class for non view-specific methods.

divisionModule.factory('DivisionController',
    ['DivisionModel', 'DivisionService',
        function (DivisionModel, DivisionService) {

            function getDivisionsResultHandler(result) {
                //Apply the result
            }

            function getDivisions() {
               DivisionService.query(queryParams, getDivisionsResultHandler);
            }

            getDivisions();

            return{
               getDivisions: getDivisions
            }
        }
    ]
);

I then injected these controller files into the relevant ViewModels (Angular Controllers) and began to invoke their methods directly. Something about this did not seem right, however. Controllers are not supposed to be invoked directly. Instead, they should communicate by registering and dispatching events. Angular has events, but since my controllers were not attached to a view they did not have a $scope and therefore would not propagate events. It was at that point I realized that I could inject the Angular $rootScope and dispatch and listen for events from there.

I went back to my ActionScript roots again and created a controller class as such:

divisionModule.factory('DivisionController',
    ['$rootScope', 'DivisionModel', 'DivisionService',
        function ($rootScope, DivisionModel, DivisionService) {

            function divisionSelectedHandler(event, division) {
                DivisionModel.selectedDivision = division;
            }
            $rootScope.$on('divisionSelected', divisionSelectedHandler);

            function getDivisionsResultHandler(result) {
                //Apply the result
                DivisionModel.divisions = result;

                $rootScope.$emit('divisionSelected', selectedDivision);
            }

            function getDivisions() {
                DivisionService.query(queryParams, getDivisionsResultHandler);
            }

            getDivisions();
        }
    ]
);

With the controller structured this way, I no longer had to inject it everywhere that I wanted to use it. Now generally it is bad practice to use $rootScope but since it is only being used as a conduit for communication I think it is acceptable.

 Next -> Client Code Structure, Part 3: Organization

Client Code Structure, Part 3: Organization

Now that our code is split into Models and Controllers it is much easier to read, maintain, and debug. I thought that I could take it one step further, however. Once again, I pulled from my old ActionScript standards and split each file into the following sections:

  • Model Files
    • Property Initialization
    • That’s all (You expected more?)
  • ViewModel Files
    • Injectables
    • Inheritance
    • Scope Initialization
    • UI Event Handlers (Handles events from the view)
    • Application Event Handlers (Handles events from $rootScope)
    • General helper functions
    • Code that runs when the view is created
  • Controller Files
    • Injectables
    • Application Event Handlers 
    • Result Handlers
    • Fault Handlers
    • General helper functions
    • Code that runs when the app loads

See the example below:

divisionModule.factory('DivisionController',
    [

        /**************************************
        ***
        *** Injectables
        ***
        **************************************/

        '$rootScope',
        'DivisionModel',
        'DivisionService',

        function ($rootScope, DivisionModel, DivisionService) {

            /*********************************
            ***
            *** Application Event Handlers
            ***
            *********************************/

            function divisionSelectedHandler(event, division) {
                DivisionModel.selectedDivision = division;
            }
            $rootScope.$on('divisionSelected', divisionSelectedHandler);

            /********************************
            ***
            *** Result Handlers
            ***
            ********************************/

            function getDivisionsResultHandler(result) {
                //Apply the result
                DivisionModel.divisions = result;

                $rootScope.$emit('divisionSelected', selectedDivision);
            }

            /********************************
            ***
            *** Fault Handlers
            ***
            ********************************/

            function getDivisionsFaultHandler(fault) {
                //Handle faults
            }

            /******************************
            ***
            *** Helper Methods
            ***
            ******************************/

            function getDivisions(){
                DivisionService.query(queryParams, getDivisionsResultHandler, getDivisionsFaultHandler);
            }

            /******************************
            ***
            *** Code that runs on startup
            ***
            ******************************/

            getDivisions();
        }
    ]
);

Now, if there is a problem in the application somewhere, not only do we know exactly which file to look at, we also know which section of the file to look at.

 Next -> Client File Structure

Client File Structure

Now that we have worked out how we will organize code, the next step is to determine how we will structure the source files.  As inexperienced AngularJS developers, we initially decided that instead of coming up with our own file structure, we should start with examples given to us by other developers.  The problem was that suitable examples were hard to come by.  Most examples dealt with small snippets of code instead of looking at file structure.  The only real example that we could find was the AngularJS seed project.  Below is a list of how this project is structured along with what each folder is expected to hold.  I have only drilled down into the “app” folder because that is the only group I propose to reorganize.

  • app – Application specific files
    • css – Style sheets
    • img – Image files
    • js – Source code
      • controllers – Angular controller files.  One per view (partial)
      • directives – Angular directives
      • filters – Angular utilities for sorting, filtering, and formatting
      • services – Other Angular utility files
      • app.js – The main controller for the application.  Relates directly to the index.html file
    • lib – Appears to be framework files (Angular files), but unclear how this differs from “Scripts”
    • partials – HTML view templates
    • index.html – The main view file
  • config – Configuration
  • logs – Log files
  • scripts – External javascript, not specific to this application
  • test – Unit tests

As you can see, these files are organized by file type and abstract functionality.  This works well for basic projects, but for larger projects we run into a problem.  Each of the folders are so general that many files will fit the description.  This means that you will end up with a mountain of files in each folder which makes it difficult to find anything.  Additionally, it is often difficult to organize these files into subfolders because other than abstract functionality (controllers, services, etc) these files are generally unrelated.  Furthermore, because these files are generally unrelated we rarely want to work on more than one of them at the same time (no one says, “I’m going to work on Controllers today”).

After careful consideration (and several meetings) we decided that our best bet was to group the files by business concept first.  After this, we can create additional file structure hierarchy if warranted.  I am using our RaceTracker app as an example below:

  • apps – Still application specific files
    • RaceTrackerApp – If there is more than one app, add this level of Hierarchy to contain files specific to this app
      • heats – code and templates specific to heats
        • directives – directives related to heats in the RaceTracker application
          • heatDirective1
          • heatDirective2
          • …etc
        • HeatController.js – Generic Controller file for heats for the RaceTracker application
        • HeatModel.js – Model file for heats for the RaceTracker application
        • heats.tpl.html – View template (partial) for heats in the RaceTracker app
        • HeatVMController – Controller file tied directly to the heats.tpl.html view
      • drivers – code and templates specific to drivers
        • directives  – Directives related to drivers in the RaceTracker app
        • DriverList – files related to the driver list view
          • DriverListVMController
          • driverList.tpl.html
        • DriverDetails – files related to the driver details view
          • DriverDetailsVMController
          • driverDetails.tpl.html
        • DriverModel
        • DriverController
      • security – code related to security specific to the RaceTracker app
        • SecurityModel
        • SecurityController
      • assets – Non-code related files
        • images – ’nuff said
          • logos
          • icons
          • backgrounds
          • …etc
        • style – Style sheets
          • css – compiled or unchanging css files
          • less – These get compiled into css
        • font – Font files
        • xml – Non-configuration related files for use in the app
        • …etc
      • app.js – Main application file for this app.  Should only contain code related to startup
    • shared – If there is more than one app, files shared between them go here
      • assets – Non-code related files
      • directives – Generic directives
        • directive1 – Folder for the first directive.  Any others will be structured the same way
          • directive1.html – Template for the first directive
          • directive1.js – Code for the first directive
      • security – Security related code shared between apps
        • SecuritySharedModel
        • SecuritySharedController
      • services – Remote data calls
        • services.js – All service call definitions go here.  We have not found a good reason to split them out at this time
      • utilities – General utility files
        • utility1.js
        • utility2.js
  • RaceTracker – This separation exists only to make the URL that the user sees smaller and less confusing
    • index.html – Main application view.  Relates to the app.js file in the corresponding application folder (in this case RaceTrackerApp)
    • config.js – Javascript configuration for this app
  • config – Configuration
  • logs – Log files
  • scripts – External javascript, not specific to this application
  • test – Unit tests

That is kind of a lot to take in at once, but the concept is simple;  Separate the files by business concept first.  Developers generally work on one business concept at a time and this file structure helps facilitate this by keeping the files that they will be looking at in the same location.  For example, if you are working on the Heats screen, you would not need to look very far to find the HeatModel, HeatController, heat view(heats.tpl.html), and view model (HeatVMController ) because they are all in the same folder.

 Next -> Client Code Standards

Client Side Code Structure and Standards – Prologue

AngularJS is a wonderful JavaScript framework which allows developers to quickly create dynamic websites while keeping a maintainable code base. It is not without its quirks, however. The fact that Angular has gained so much traction despite these quirks is a testament to just how amazing of a framework it is.

The quirks that I am referring to can generally be separated into three categories:

  • Documentation
  • Terminology
  • Standards

As you continue reading, bear in mind that these have been my experiences with AngularJS and your experiences may differ.  Also, some of the issues that I describe may now be resolved but were not at the time that this was written.

Documentation

The official documentation on AngularJS is pretty terrible if it exists at all.  Often times many options are available for a specific piece of functionality (api, directive, service, etc) but only a subset are explained leaving the developer to figure out the rest themselves or ask the community.  Also, there is usually only one example per piece of functionality.

Don’t get me wrong, I understand that framework architects are not necessarily good writers and I would rather them focus more on the framework itself than the documentation.  Additionally, whenever a deficiency or inconsistency is found in the documentation and brought up in a public forum, the developers are quick to address it.

Terminology

One of the most confusing things about AngularJS when getting started is getting used to the terminology.  It’s not that it is wrong, it’s just not the standards that are used in practice by many developers.  Below is a list of terms used in Angular along with what I believe their reasoning was and the names that I would normally refer to them as:

  • Angular Scope => View Specific Model – This one is not too bad.  I think they were trying to kill two birds with one stone here.  They were trying to create a view specific model for binding as well as a private scope to handle encapsulation (Something JavaScript does not do well on its own).  The Angular team combined both concepts into one here.
  • Angular Controller => View Model – I have found that often times people misunderstand the term “View Model”.  A View model is a piece of code that models the view and facilitates communication between the view and other parts of an application.  It includes properties that are bound to the view and handlers for UI events that occur on the view.  Additionally, it is created when a view is created and destroyed when the view is destroyed.  It is basically about half controller and half model.  Sound familiar?  This describes the Angular Controller perfectly.
  • Angular Factory => Controller – When I think “Factory” I think about multiple objects being created at a time and then later destroyed.  Angular “Factories” basically create a singleton object used to handle a single piece of functionality.  This object never goes away.  Depending upon implementation, these act a lot like standard Controller classes and nothing like what I would expect from a factory.
  • Angular Resource => Service – In my mind, a resource is any external item which is pulled into the code.  Generally, when I hear “resource” I think external files such as images, templates, etc.  In Angular, it is a way to access data via a REST service.  While this loosely fits the definition of a Resource it wouldn’t be the first name I would come up with.

Once you make the mental connection between the Angular terminology and the standard terminology it makes things a lot easier to understand.  For developers new to Angular, having the terminology mapping above will help with the learning curve significantly.

Standards

Since AngularJS is so new, I’m sure they are still working out their standards.  Standards can be broken into file structure, code structure, and code standards.  The only real example of official standards that I can find for Angular is the seed project.  While it works well for basic projects, when your project grows it quickly can get out of hand.  This is where we are going to make most of our progress.

 Next -> Client Code Structure, Part 1 – Organization