← Javascript Development

JS Code Style Guide

General Guidelines

John Papa’s Angular Style Guide should be used as the basis for our Angular conventions. Todd Motto’s style guide is mostly the same as John Papa’s, but includes some additional tips.

Third-party resources that are not Banno-specific but generally offer good advice:

File Format

It is recommended to specify an .editorconfig file for each project and use an editor plugin to automate the formatting (see the sample project file and sample front-end library file). The EditorConfig website has more information and plugins for popular editors.

  • Files should be saved as UTF-8 with Unix line endings.

    Why? UTF-8 is the most compatible encoding across editors, browsers, and other clients.

  • Spaces should be used for indentation, usually at 2 spaces per indent.

    Why? A convention needs to be set, and this is preferred by the majority of developers (both in the JavaScript team, and the Banno organization and community at large). Spaces also work/look better across a variety of environments. But as long as project defines an .editorconfig, it doesn’t really matter what style is used.

Filesystem Structure

  • File names should be in all lowercase, using hyphens to separate words. Periods are used for nested extensions or typing (e.g., file.min.js or feature.directive.js).

    Why? All-lowercase prevents issues when using them on filesystems that don’t strictly distinguish case (Windows, OSX).

    Why? Hyphens are the preferred separator in URL paths, so use them in the filesystem too.

  • Source code should be contained in src folder and organized according to John Papa’s Application Structure guidelines. For example:

    [src]
        [feature-name]          example of feature folder
            feature-name.css            feature-specific CSS
            feature-name.directive.js   directive
            feature-name.html           directive's partial
        [filters]               project-wide filters
        [layout]                container/page/overview components
        [services]              project-wide services
        app.config.js           Angular config() blocks, and similar startup config
        app.constants.js        Angular constant() blocks, either immutable project values or vendor globals
        app.mocks.js            Mocks and other code used only during development
        app.module.js           Angular module definition
        app.routes.js           Routing definitions
    

    An app.module.js should always exist in Angular projects; don’t name it app.js or module.js, even if there is only 1 module. If there are multiple modules, use an appropriate prefix for each one.

    Why? Always using the same prefix & name for the main module makes it easy to find and prevents future renaming if additional modules are added.

  • Contrary to John Papa’s guidelines on organizing tests, tests should be separated from source code in a test folder:

    [test]
        [e2e]                               end-to-end tests
            protractor.conf.js              Protractor config
            workflow1.spec.js               test suite
            workflow2.spec.js
        [unit]                              unit tests
            feature-name.directive.spec.js  test suite
            karma.conf.js                   Karma config
            requirejs.conf.js               RequireJS config
    

    If there are no E2E tests (e.g., the project is an API library), then all the files can be kept in the test root folder, without a unit subfolder.

    Why? Traditionally (with Banno and the developer community), tests are kept in a separate folder.

    Why? We also typically have E2E tests, which don’t follow the one-to-one file ratio of unit tests.

Naming

  • In general, variable names should be camel-cased.

    Example: var eachWordExceptFirstIsCapitalized = true;

    Example: var acronymsLikeJsAreAlsoCamelCased = true;

    Why? A convention needs to be set, and this is the most common practice in the Javascript community.

  • Constructors (function intended to be invoked with new) – which includes Angular services – should begin with a capital.

    Example:

      ```javascript
      function Person() {
        this.name = 'John';
      }
    
      var person = new Person();
      ```
    

    Why? Capitalizing the name indicates at a glance that the function is intended to be used as a constructor.

  • Variables that should not be changed can be written in UPPER_CASE_WITH_UNDERSCORES. But whenever possible, the const keyword should be used instead.

    Example: var DONT_CHANGE_ME = 'some value';

    Why? Until ES6 is widely used, this naming style indicates that the variable’s value should not be changed.

  • Angular components (services, constants, values, directives, etc.) must be given unique names. Ideally they should be universally unique, but at the very least they should be unique to the Banno ecosystem. A project prefix is usually a good idea (e.g. sentrySomeService and mobileSomeService).

    Why? Angular’s module system does not use namespacing, so if 2 modules each have a component with the same name, one of them will be replaced by the other.

Angular Modules

  • Angular modules should be named banno.projectName, where projectName is a short, camel-cased name of the project. Related projects that encompass multiple modules can use “submodules” – for example, banno.sentry.api and banno.sentry.ui.

    Example: angular.module('banno.session', []);

    Why? Modules should have a namespace prefix (here banno) to prevent naming conflicts.

    Why? Separating names with periods seems to be the most common practice in the Angular community.

  • If you have multiple modules defined in a project, consider splitting them out into separate projects, especially if they are reusable.

Angular Dependency Injection

  • Use a build tool such as ng-annotate to automatically annotate the dependencies for minification-safe code.

    Example:

    /** @ngInject */
    function AvengersController(storage, avengerService) { /* ... */ }
    

    Why? Manually annotating the code requires duplication of the dependencies in the code – more typing and more chance of error.

Directives

  • Use isolate scope if a directive is considered a self-contained component/widget. This is accomplished by explicitly setting the scope property to the desired local bindings. Isolate scope can be accessed in unit tests with the isolateScope() method.

    Do not use isolate scope if the directive simply decorates an element with a extra styling or functionality (e.g. a directive for the <a> tag). In these cases isolate scope is more likely to conflict with other directives.

Testing

Check out our testing guidelines & tips page for details.

  • Contrary to John Papa’s guidelines on stubbing and spying, we do not use Sinon (though you are free to use it in a project if you wish).

    Why? Jasmine’s spies usually have the functionality that we need, and Sinon has never been part of our process.

Linting

  • Use ux-lint to lint your code.

    Why? ux-lint provides the same linting as ESLint, JSHint, and JSCS, but uses the Banno JS settings by default.