DoneJS StealJS jQuery++ FuncUnit DocumentJS
4.3.0
5.0.0 3.13.1 2.3.35
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
  • Bitovi
    • Bitovi.com
    • Blog
    • Design
    • Development
    • Training
    • Open Source
    • About
    • Contact Us
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
    • Project Organization
    • Reporting Bugs
    • Suggesting Features
    • Finding Ways to Contribute
    • Developing Locally
    • Changing the Code
    • Improving the Docs & Site
    • Making a New Package
    • API Design Guidelines
    • Releasing CanJS
    • Updating the Site
    • Evangelism
  • GitHub
  • Twitter
  • Chat
  • Forum
  • News
Bitovi

API Design Guidelines

  • Edit on GitHub

Learn how to design APIs which are consistent with CanJS.

Overview

CanJS has many goals, one of which is providing a consistent interface and experience for developers using similar functionality or usage patterns across projects. Ideally, a developer should have a rough understanding of how to use something new based on what they have already used in CanJS.

This document is geared towards contributors who are designing new APIs for CanJS and developers of libraries meant to work alongside CanJS projects. Below are useful conventions for designing APIs, which have been adopted by CanJS projects or will be aligned with in future releases.

Conventions

Variable casing

All methods and properties should be camelCase. Class and constructor function names are exclusively PascalCase.

Methods are verbs, properties are nouns

A developer should be able to tell by looking at an identifier whether it is a function that can be called or an object/property that has a value. In JavaScript, functions can be values so be careful to make the distinction between a method (verb) and a function being passed around as data (noun). For example, handleEvent is a method, but if that method were being passed around eventHandler is more appropriate.

Methods which are only verbs such as jump() are discouraged when it is not clear what should be passed to it. A better name jumpOverPerson() provides a hint as to what the method expects.

Private methods and variables

Any method or variable beginning with one or more underscores (_) is private to the project and should not be used externally. Ideally these cases are minimized.

Note: there is a temporary convention for Symbols which is an exception to the above. Documented variables with two leading underscores, for example __keys, are safe to use as they are intentionally exposed for environments where symbols are not supported.

Private modules

Any module file which is prefixed with one or more dashes (-) is private to the project and should not be used externally. Ideally these cases are minimized.

Creating new things

In CanJS, new "things" are created by either calling a constructor or class with the new keyword or calling functions which begin with make. For example, to create a Promise from an existing Promise-like object, can-util provides makePromise. Use of make is more explicit than, for example, getPromise because the underlying implementation is creating a value, not retrieving a value.

Registries

Throughout CanJS we use a registry pattern. A registry, in abstract terms, is an object where named items are added, retrieved, and removed dynamically over the course of a program's life. For example, a component registry is where named components are added, retrieved, and removed. Registries can be implemented with the following interface:

interface Registry<RegistryKey, RegistryItem> {
    add(identifier: RegistryKey, item: RegistryItem): function
    has(identifier: RegistryKey): boolean
    get(identifier: RegistryKey): RegistryItem | undefined
}

Notice that there is no method to remove an item for a given identifier. Instead the add() method returns a function which will remove the added item. The reason we do this is to provide better system analysis and guarantees. Only one item should be associated with any identifier at any point in time. Suppose two independent programs were using the same registry and both added the "foo" item. There is a race condition there, where one would override the other which would lead to breakage or unexpected behavior. If we counter that by exposing a remove() method, someone may remove the existing item and then add their own. This is also a problem because the previous item will have no way of knowing to clean itself up. Thus for registries, we make the guarantees that addition to the registry is first come first serve, throwing if an attempt is made to add an item to existing identifier, and the only way to remove an added item is via the callback returned by the add().

CanJS is part of DoneJS. Created and maintained by the core DoneJS team and Bitovi. Currently 4.3.0.

On this page

Get help

  • Chat with us
  • File an issue
  • Ask questions
  • Read latest news