JavaScript MVC Style Guide

by Alex MacCaw

Over the years I've come up with a few rules for MVC web apps that have served me well and kept large codebases from descending into chaos. While the terminology may differ, these rules should hold true for most client-side MVC frameworks such as Backbone and Ember.

Some frameworks have different naming MVC conventions, and slightly different takes on separating concerns. In this document, controllers are the glue between models and views, views are HTML templates and models purely deal with data storage, retrieval and decoration. This fits well into the Backbone & Spine terminology. Ember has similar conventions, but goes a step further in separating out DOM access from controller logic.


Controllers

  • Controllers are the glue between views and models. Most of their logic concerns event management. Keep controllers skinny.
  • Any communication between children and parent controllers should use events (do not pass an instance of the parent around).
  • Should only know about sub controllers.
  • Should be scoped to a single element, and not access or alter other parts of the DOM.
  • Should have a unique class name, and all CSS relevant to this controller should be namespaced by this class name.
  • Should work even if their element is not appended to the DOM tree. This is useful for testing and demonstrating the controller is properly scoped.
  • Should be testable by firing events programatically on their sub elements.
  • Should be able to be re-rendered at any time without adverse effects.
  • Should not use the DOM to store state — keep any view specific state stored as instance properties in the controller.

Views

  • Should be logic less except for flow control and helper functions.
  • Should be passed all the data they need to render directly. It should all be available in the current scope.

Models

  • Should purely be concerned with data, manipulating data and decorating data.
  • Should never access controllers or views.
  • Should never access or return DOM nodes.
  • Should only access or require other models at runtime.
  • Should abstract away XHR connections from the rest of the application.
  • Should contain all data validations.

Routers

  • Should be as logic-less as possible.
  • Should not know about or access the DOM.

Global state

  • Should be kept to a minimum as it arguably violates MVC. You can't get around it for some things though, like the current user, current view, CSRF token etc.
  • Should never be stored in global variables.
  • Should all be stored in one place (such as a singleton instance of a model).

Modules

  • You should always use a module system, whether it's CommonJS, AMD, ES6 modules, or something equivalent.
  • Never set or access global variables.

Pull requests accepted

A style guide should be a fluid document and evolve as your team encounters specific problems and gains experience. Its main purpose is to keep the codebase consistant and clean. If you have any suggestions for this document, tweet them to me at @maccaw.