Commit da57eb39 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'google-singletons-are' into 'master'

Decide on and document a convention for singletons

> The singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. 

The simplest implementation uses an object literal to contain the logic.

```javascript
gl.MyThing = {
  prop1: 'hello',
  method1: () => {}
};
```
A live example of this is [GfmAutoComplete](https://gitlab.com/gitlab-org/gitlab-ce/blob/172aab108b875e8dc9a5f1d3c2d53018eff76ea1/app/assets/javascripts/gfm_auto_complete.js.es6)

Another approach makes use of ES6 `class` syntax.
```javascript
let singleton;

class MyThing {
  constructor() {
    if (!singleton) {
       singleton = this;
       singleton.init();
     }
      return singleton;
  }

  init() {
    this.prop1 = 'hello';
  }

  method1() {}
}

gl.MyThing = MyThing;
```
A live example of this is [Sidebar](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/sidebar.js.es6)

Another functional approach to define Singleton using `Javascript Revealing Module Pattern` is like below
```javascript
/**
  *  1. It instantiates only a single object
  *  2. It is safe – it keeps the reference to the singleton inside a variable, which lives inside a lexical closure, so it is not accessible by the outside world
  *  3. It allows privacy – you can define all private methods of your singleton inside the lexical closure of the first module pattern
  *  4. No this keyword trap (no wrong context referring)
  *  5. No use of new keyword
  *  6. Easy to write test code
  */
//
const Singleton = (function () {
  // Instance stores a reference to the Singleton
  var instance;
  function init() {
    // Singleton
    // Private methods and variables
    function privateMethod(){
        console.log( "I am private" );
    }
    var privateVariable = "Im also private";
    var privateRandomNumber = Math.random();
    return {
      // Public methods and variables
      publicMethod: function () {
        console.log( "The public can see me!" );
      },
      publicProperty: "I am also public",
      getRandomNumber: function() {
        return privateRandomNumber;
      }
    };
  };
  return {
    // Get the Singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {
      if ( !instance ) {
        instance = init();
      }
      return instance;
    }
  };
})();

const singletonObj = Singleton.getInstance()

```

## Are there points in the code the reviewer needs to double check?

## What does this MR do? 

Creates a space for discussion and contribution for interested devs.

## Why was this MR needed?

## Screenshots (if relevant)

## Does this MR meet the acceptance criteria?

- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [x] All builds are passing
(http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

## What are the relevant issue numbers?

See merge request !6620
parents 0b21a71a 2159c879
......@@ -205,6 +205,57 @@ command line.
Please note: Not all of the frontend fixtures are generated. Some are still static
files. These will not be touched by `rake teaspoon:fixtures`.
## Design Patterns
### Singletons
When exactly one object is needed for a given task, prefer to define it as a
`class` rather than as an object literal. Prefer also to explicitly restrict
instantiation, unless flexibility is important (e.g. for testing).
```
// bad
gl.MyThing = {
prop1: 'hello',
method1: () => {}
};
// good
class MyThing {
constructor() {
this.prop1 = 'hello';
}
method1() {}
}
gl.MyThing = new MyThing();
// best
let singleton;
class MyThing {
constructor() {
if (!singleton) {
singleton = this;
singleton.init();
}
return singleton;
}
init() {
this.prop1 = 'hello';
}
method1() {}
}
gl.MyThing = MyThing;
```
## Supported browsers
For our currently-supported browsers, see our [requirements][requirements].
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment