Code Style Guide

As a largely open-source project, we like to keep our code as consistent as our Instant Answers. This means all code should be formatted the same way and should look and feel as though it has all been written by the same person.

This document outlines some language specific guidelines for formatting your code and also highlights best practices, and things to avoid. In any large open-source project, maintainability is of utmost importance, so a style guide is necessary to help our contributors write clean, readable and maintainable code.

General

  • Indent with 4 spaces (soft tabs)

    All DuckDuckHack code should be indented with four spaces. Be sure to configure your text editor to insert four spaces when you press the tab button - this is referred to as a "soft-tab". If you are correcting the indentation of a file, please submit that change in a separate pull request. It is important that code reviewers are able to easily differentiate between functional and stylistic changes.

  • Document your code

    Well-documented code helps others understand what you've written. It's likely that someone else will read your code and might even need to change it at some point in the future. Comments should primarily document the intent of the code. Reviewers are much more effective when they know exactly what you were trying to do. Meaningful variable names also help to document your intent.

  • Writing meaningful commits

    Commit messages should be concise and informative. If a commit fixes a particular issue, you should include fixes #X (where X is the issue number) in the body; this will automatically close the issue when your pull request is merged.

    Usually pull requests only deal with a single Instant Answer. If however your pull request modifies more than one Instant Answer, please preface your commit messages with the name of the IA modified by your commit:

    For example, if your pull request updates the Movies, InTheaters and Kwixer IA's:

    • Commit 1: Movies: updated title font color to match mockup.
    • Commit 2: InTheaters: updated title text, typo fix.
    • Commit 3: Movies, InTheaters, Kwixer: change title to h5 tag.

JavaScript

We generally adhere to Crockford's Code Conventions. Most importantly:

  • Use semicolons;

  • Use the "One True Brace Style" (opening brace on the same line)

      // Bad
      if ( ... )
      {
          ...
      }
      else
      {
          ...
      }
    
      // Good
      if ( ... ) {
          ...
      } else {
          ...
      }
    
  • Use {} instead of new Object(), and [] instead of new Array().

      // Bad
      var obj = new Object();
      var arr = new Array();
    
      // Good
      var obj = {};
      var arr = [];
    
  • Use === instead of ==, and !== instead of !=. Why?

      // Bad
      if (foo == bar) { ... }
      if (foo != bar) { ... }
    
      // Good
      if (foo === bar) { ... }
      if (foo !== bar) { ... }
    
  • Declare variables with var, chaining multiple declarations -- one per line:

    
      // Bad
      var foo = 1;
      var bar = true;
      var baz = "string";
    
      // good
      var foo = 1,
          bar = true,
          baz = "string";
    
      // when initializing undefined variables
      var foo, bar, baz;
    

    Note: We're using ECMAScript's strict mode, so you'll need to declare every variable with var.

  • Avoid trailing commas

    We support all modern browsers, including IE 9, which breaks when it reaches a trailing comma in objects. It also treats trailing commas in arrays differently than you might expect.

      // Bad
      var foo = {
          a: 'b',
          c: 42, //<-- trailing comma
      };
    
      // Good
      var foo = {
          a: 'b',
          c: 42 //<-- no trailing comma
      };
    
  • Use $.map() and $.each() instead of Array.prototype.map() and Array.prototype.forEach(), again for IE support.

  • Avoid modifying object prototypes

    Do not modify the prototypes of objects which are defined outside of your code. For example, modifications to Array.prototype or Spice will affect the global scope and may cause problems. In general, we advocate the use of local, private functions instead.

  • Define default properties when the object is created:

      // Bad
      var bar = {};
      bar.a = 'b';
      bar.c = 42;
    
      // Good
      var foo = {
          a: 'b',
          c: 42
      };
    
  • Store jQuery selectors:

    If you need to re-use a jQuery selector (e.g. $('#myDiv')), store it in a variable for speed and efficiency. Otherwise, jQuery will need to traverse the DOM each time you use the same selector.

      // Bad
      // Traverse the DOM and find '#text_element'...
      $('#text_element').show();
      // ... now do all that work again!
      $('#text_element').html('abc');
    
      // Good
      // Traverse the DOM and find '#text_element', then store it in memory
      // Convention is to prefix variables with a '$' when they hold a jQuery object
      var $text_element = $('#text_element');
      $text_element.show();
      $text_element.html('abc');
    
      // Better
      // jQuery supports method chaining!
      $('#text_element').show().html('abc');
    

Handlebars

Handlebars templates and Handlebars helpers should be easy to read and understand. Please:

  • Put nested elements on new lines:

      <!-- bad -->
      <ul>
      <li><a href="#">link text</a></li>
      <li><div><a href="#">other link text</a></div></li>
      </ul>
    
      <!-- good -->
      <ul>
          <li>
              <a href="#">link text</a>
          </li>
          <li>
              <div>
                  <a href="#">other link text</a>
              </div>
          </li>
      </ul>
    
  • Define helper functions with Spice.registerHelper, instead of Handlebars.registerHelper:

     // Bad
     Handlebars.registerHelper("spice_name_do_something", function(){ ... });
    
     // Good
     Spice.registerHelper("spice_name_do_something", function(){ ... });
    
  • Namespace your helper functions:

    Handlebars helpers are all created in the same scope, so any two helpers with the same name will collide (we plan to fix this). This can be avoided by prepending your helpers with the name of your Spice IA.

      // Bad
      Spice.registerHelper("do_something", function(){ ... });
    
      // Good
      Spice.registerHelper("spice_name_do_something", function(){ ... });
    

The easiest way to verify your code meets our style guide is to test it with JSHint.

CSS

  • All CSS should be "namespaced" with the container element.

    For Spices, use .zci--spicename, and for Goodies, use .zci--answer:

      /* Stopwatch Spice */
      .zci--stopwatch .spice-pane {
          ...
      }
    
      /* Calendar Goodie */
      .zci--answer table.calendar {
          ...
      }
    
  • Put multiple selectors on new lines for each rule:

      /* Bad */
      .zci--stopwatch .spice-pane, .zci--stopwatch .spice-pane-right {
          ...
      }
    
      /* Good */
      .zci--stopwatch .spice-pane,
      .zci--stopwatch .spice-pane-right {
          ...
      }
    
  • Avoid the use of vendor prefixes and experimental features. We strive for a uniform experience on all current browsers and your IA must work across them.

    When in doubt, CanIUse is a good resource for determining if prefixes are needed. We support IE 9+, and recent versions of Chrome, Firefox, Safari, and Opera.

      /* Bad */
      .element {
          -webkit-border-radius: 45px;
          -o-border-radius: 45px;
          -moz-border-radius: 45px;
          -khtml-border-radius: 45px;
          border-radius: 45px;
      }
    
      /* Good */
      .element {
          border-radius: 45px;
      }
    
  • Avoid using inline CSS. Custom CSS should be placed in a file (/share/{goodie,spice}/my_ia/my_ia.css) to be automatically included in the Instant Answer response.

Perl

(This section is coming soon! Know what should go here? Then please contribute to the documentation!)

results matching ""

    No results matching ""