Skip to content

JavaScript/CoffeeScript coding style guide in use at Skroutz SA

Notifications You must be signed in to change notification settings

skroutz/javascript-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 

Repository files navigation

Skroutz JavaScript Style Guide

Rationale

  • 80% of the lifetime cost of software goes to maintenance.

  • Hardly any software is maintained for its whole life by the original author.

  • Code conventions improve readability, allowing engineers to understand new code more quickly and thoroughly.

Conventions

Code conventions

  • Write new code in CoffeeScript.

  • Use soft-tabs with a 2-space indent (this means pressing the tab key once should produce 2 space characters).

  • Try to keep line length 80-90 characters at most.

  • Make sure you do not accidentally include trailing whitespace.

Naming conventions

  • Use CamelCaps for class names and constructors.

  • Use camelCase for functions/methods.

  • Use snake_case for variable names.

  • Use a leading underscore (e.g. _foo) only for variables and methods that are intended to be "private".

  • Use CAPS for constants.

  • Prefix jQuery object variables with a $:

    sidebar = $('.sidebar') # bad
    
    $sidebar = $('.sidebar') # good

CoffeeScript

Literals

  • Prefer literals (arr = []) over native constructors (arr = new Array()). Array, Object, etc constructors are ambiguous in how they deal with their paramameters and they can be overriden. Also, literals are shorter and lint tools like them.

Strings

  • Prefer string interpolation over concatenation:

      name = 'Maria'
    
      console.log 'Ase mas re ' + name + '!' # avoid
    
      console.log "Ase mas re #{name}!" # good
  • Use single quotes for strings when not interpolating:

      name = "Bob Parr" # bad
    
      name = 'Bob Parr' # good
  • Use block strings when it improves readability:

      my_msg = 'Password too short!'
      msg_div = """
                <div class="warning_message">
                  <p>
                    <span>Warning:</span>
                    #{my_msg}
                  </p>
                </div>
                """

Conditionals

  • To break a long if statement in multiple lines remember to end each line with an operator

    # bad, actually an error
    if foo is bar and taco
    is mecca
    
    # good
    if foo is bar and
    taco is mecca
    

Objects

  • Prefer dot notation when accessing properties:

      luke =
        jedi: true
        age: 28
    
      isJedi = luke['jedi'] # bad
    
      isJedi = luke.jedi # good
  • Use subscript notation [] when accessing properties dynamically (with a variable) or when that property name is a language keyword:

      options =
        'default':
          bacon: 'nomnom'
      my_key = 'default'
    
      default_food = options['default']
      default_food = options[my_key] # same
  • When defining an object in many lines, do not use commas:

      # good (no commas)
      luke =
        jedi:  true
        age:   28
        human: true
    
      # bad (commas)
      luke =
        jedi:  true,
        age:   28,
        human: true
    
      # bad bad bad (mixed)
      luke =
        jedi:  true,  # comma
        age:   28     # no comma
        human: true

Functions

  • Do not use parentheses when defining functions that take no arguments:

      # bad
      foo = () ->
        console.log('aha!')
    
      # good
      foo = ->
        console.log('aha!')
  • Parentheses in function calls may be omitted with respect to readability and clarity. Some examples:

    foo() # you cannot omit () if there are no arguments!
    
    foo 4
    
    foo(4).bar(5)
    
    foo.getSize(5, 6) / foo.getSize(6, 5)
  • Avoid "function grouping":

    (foo 4).bar 8 # bad
    
    foo(4).bar 8 # good
  • Avoid creating functions inside loops since it's bad for performance:

      # bad
      for i in [1..100]
        doSomething = ->
          console.log(i)
    
        doSomething()
    
      # good
      doSomething = (i) ->
        console.log(i)
    
      for i in [1..100]
        doSomething(i)
  • Avoid explicit return statements unless it's for an "early return". For example:

    browser = getBrowser()
    return 'oh no!' if 'ie6'
    
    # ...cool stuff ie6 doesn't support...
  • Class methods should return this to enable method chaining. For example:

      Jedi = ->
        @jumping = false
        @yelling = false
    
      Jedi::jump = ->
        @jumping = true
        return this
    
      Jedi::yell = ->
        @yelling = true
        return this
    
      first = new Jedi
      first.jump().yell()

Classes

  • Try to incorporate OOP methodologies when applicable.

    class Magician
      # public class property
      @DISTRACTION_DURATION: '2mins'
    
      # private instance function
      distractAudience = (duration) ->
        "I will distract them for #{duration}"
    
      # public instance function
      doTrick: ->
        # call the instance function with a public class property
        distractAudience(@constructor.DISTRACTION_DURATION)
    

Variables

  • Initialize variables at the top of their scope, preferably in a grouped block.

  • Prefix with _ unused function parameters and local variables. It's also acceptable to use just _ (although it's a bit less descriptive).

Whitespace

  • Place an empty newline at the end of the file (most modern editors will do this automatically for you).

  • Place one space before arrows:

    test =-> print 'test' # bad
    
    test = -> print 'test' # good
    
    test2 = (arg)-> print arg # bad
    
    test2 = (arg) -> print arg # good
  • Insert an extra space before and after operators:

    foo='bar' # bad
    
    foo = 'bar' # good
    
    c = a+b # bad
    
    c = a + b # good
  • Insert an extra space after , and ::

    foo: [1,2,3] # bad
    
    foo: [1, 2, 3] # good
    
    foo:'bar' # bad
    
    foo: 'bar' # good
  • Avoid spaces around arguments and before a comma ,:

    foo( options, 'bar' ) # bad
    foo(options , 'bar') # bad
    
    foo(options, 'bar') # good
  • Avoid spaces around conditional constructs, loops, etc..

    if(true) #bad
    
    if (true) #better
    
    if true #good
  • Assignments should be vertically aligned unless they differ a lot in length or they are less than 3:

    # bad
    a = 'once'
    little = 'little'
    bird = 'bird'
    told = 'told'
    me = 'me'
    
    # good
    a      = 'once'
    little = 'little'
    bird   = 'bird'
    told   = 'told'
    me     = 'me'
    
    # bad
    a                        = 'once'
    little                   = 'little'
    bird_told_me_some_things = 'foo'
    
    # bad (this is too much)
    a      = 'once'
    little = 'little'
  • Break long method chains into many lines, keeping the dot at the beginning of each line:

      # bad
      $('#items').find('.selected').highlight().end().find('.open').updateCount()
    
      # good
      $('#items')
        .find('.selected')
        .highlight()
        .end()
        .find('.open')
        .updateCount()
    
      # even better
      $('#items')
        .find('.selected')
          .highlight()
          .end()
        .find('.open')
          .updateCount()

Comments

  • Do not write comments to state the obvious.

  • When modifying code, don't forget to update the corresponding comment. Ideally, improve the code to obviate the need for the comment and delete the comment entirely.

  • Do not write comments in CAPS (TODO, FIXME, etc are notable exceptions).

  • Short comments should be placed exactly above the code they document, unless they are short enough to be placed on the same line (inline comment).

  • You are free to write block comments using either the triple # syntax (###) or by prefixing each line with a #:

    # This
    # is
    # a
    # block
    # comment
    
    ###
    And another one.
    This style helps the maintainance of documentation.
    Each time I want to add or remove a line, I don't have to mess with any #.
    I also want this comment to be passed to the generated JavaScript.
    ###

Type casting & coercion

  • Use parseInt with a radix for type casting to integers. If, for whatever reason, you are doing something wild and parseInt is your bottleneck and need to use bitshift for performance reasons, leave a comment explaining why and what you're doing.

    inputValue = '4'
    
    # bad
    val = parseInt inputValue
    
    # good
    val = parseInt(inputValue, 10)
    
    # good
    val = ~~inputValue # comment here
  • Converting to a boolean:

    age = 0
    
    # bad
    hasAge = Boolean age
    
    # good
    hasAge = !!age
    
    # good (ternary operator equivalent)
    hasAge = if age then true else false

DOM manipulation

  • You should be able to tell a presentational class attribute from a functional one:

    $my_carousel = $('.carousel') # bad
    
    $my_carousel = $('.js-carousel') # good
  • Assumption is the mother of all fckups. Do not code with assumptions about DOM hierarchy/state.

  • Cache DOM lookups:

      # bad
      setSidebar = ->
        $('.sidebar').hide()
        # ...stuff...
        $('.sidebar').css({'background-color': 'pink'})
    
      # good
      setSidebar = ->
        $sidebar = $('.sidebar')
        $sidebar.hide()
        # ...stuff...
        $sidebar.css({'background-color': 'pink'})
  • Think about performance when writing DOM queries. Try to make the selector engine use the browser's querySelectorAll method. Also a good read: w3c selectors-api

    # slow
    # uses $.sibling internally to find nodes following other nodes in the same tree
    $('.sidebar').children('ul').hide()
    
    # faster
    $('.sidebar').find('ul').hide()

Common pitfalls

  • Have a look at the full list of CoffeeScript aliases. Some are notorious for causing confusion to CoffeeScript n00bs.

  • Avoid == and != as they compile to === and !== that may be confusing/unwanted.

  • Use @ instead of this.

  • Use fat arrows => in a function definition when you need to bind to the function the current context (this).

  • Learn about the Existential Operator ? and use it.

  • Do not confuse the existential operator ? with the JavaScript ternary operator. The ternary operator in CoffeeScript is a single-line if:

    my_state = if 6 then 'go!' else 'work!'
  • Use the more explicit if foo? (will execute unless foo is undefined or null) instead of if foo.

Other

  • Do not use unless since it's really confusing. Use if ! or if not instead.

  • When a .coffee file is to be preprocessed by let's say erb avoid nesting quotes of the same type, as it breaks linting and may make it unparseable by other preprocessors.

    Example

    message = '<%= _('ΣΜΣ') %>' # bad
    
    message = '<%= _("ΣΜΣ") %>' # good
    

Tools

Editors

Vim

Set soft-tabs and rulers according to conventions.

In your ~/.vimrc add:

set expandtab
set tabstop=2
set shiftwidth=2
set smarttab
set colorcolumn=80,90

Sublime Text

Set soft-tabs and rulers according to conventions.

Go to "Preferences -> Settings - User" and add:

"translate_tabs_to_spaces": true,
"tab_size": 2,
"rulers": [ 80, 90 ]

Essential plugins

Vim

Sublime Text

Lint

Debugging

Resources

Docs & guides

Inspiring styleguides

Books

JavaScript

CoffeeScript

News

Podcasts

Compatibility

Performance

Remember: When in doubt, benchmark.

About

JavaScript/CoffeeScript coding style guide in use at Skroutz SA

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published