Skip to content

TransitApp/javascript

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Writing Javascript at Transit

Javascript style guide we use at Transit.

Content

Airbnb Javascript style guide

Our styles are based on the excellent javascript guide from Airbnb with a few exceptions.

Exceptions

Whitespace

  • Limit your lines to 120 characters. eslint: max-len.

This ensures readability and maintainability.

// Bad.
const promise = Promise.resolve(true).then(Promise.resolve).then(Promise.resolve).then(Promise.resolve).then(Promise.resolve);

// Good.
const promise = Promise.resolve()
  .then(Promise.resolve)
  .then(Promise.resolve)
  .then(Promise.resolve)
  .then(Promise.resolve);

Functions

  • Allow usage before declaration. eslint: no-use-before-define

    doSomething();
    
    function doSomething() {}

Naming conventions

Consistency and disambiguation

As soon as a concept has a name, this name should always be used to refer to that concept, and that name shouldn't be used to refer to anything else.

Example:

  • A globalRouteId is a unique identifier to a route. One should never call it routeId since it is another concept (used in the GTFS, the tGTFS and the bgtfs with different meaning).
  • A feed is an instance of the transit_production.feeds table. An alertFeed is an instance of the service_update.alert_feeds table.

Example: If some external tools/library/api uses the same name for another concept, then at least the foreign name should be prefixed for disambiguation, or even both.

  • When we match the stops from the GTFS to the stop from some real-time API, we call the first one gtfsStop and the second one apiStop even if the first one is usually just called stop.

The name should describe the content

  • An array should have a name that gives clues about its content.

    // Bad.
    const things = ['dog', 'cat', 'mouse'];
    
    // Good.
    const animals = ['dog', 'cat', 'mouse'];
  • An object of thing indexed by some key should be called thingByKey.

    // Bad.
    const routes = {
      2: {
        routeShortName: 'R1',
        routeLongName: 'Awesome Route 1'
      },
    };
    
    // Good.
    const routeByGlobalRouteId = {
      2: {
        routeShortName: 'R1',
        routeLongName: 'Awesome Route 1'
      },
    };
  • When you have different representations of the same thing, apply some disambiguation on the content.

    // Bad.
    let date = '2017-01-01 00:00:00';
    date = moment(date, 'YYYY-MM-DD HH:mm:ss');
    
    // Good.
    const dateAsString = '2017-01-01 00:00:00';
    const dateAsMoment = moment(dateAsString, 'YYYY-MM-DD HH:mm:ss');
    // Bad.
    let stopSequence = '1';
    stopSequence = parseInt(stopSequence);
    
    // Good.
    const stopSequenceAsString = '1';
    const stopSequenceAsInt = parseInt(stopSequenceAsString);

With some reasonable limits, one shouldn't be afraid to have long variable name, and be more afraid of meaningless names. For example:

  • apiStopByStopIdByTripHeadsignByRouteId should be still preferred as dict or apiStops.

ES2015 and beyond

Below are features that are recommended to start using. Although, keep in mind that they are closely related to node versions, so please double check if a feature is available before starting using it.

Promises

Dealing with asynchronous code can be tricky sometimes. To simplify and improve readability, one must try using Promises instead of the classic error-first callback. Here are a few links to understand them and start using them efficiently.

Async/Await

Async/await is part of the ES2017 release. Node 7.6 ships with V8 5.5, which includes async/await natively. So it's time to start use it. Although, one must completely understand how Promises work because both features work together.