Skip to content

Instantly share code, notes, and snippets.

@justinbmeyer
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinbmeyer/8812069 to your computer and use it in GitHub Desktop.
Save justinbmeyer/8812069 to your computer and use it in GitHub Desktop.
CanJS Infrastructure Improvements

CanJS makes it easy to make better apps, faster. But, what about making a better CanJS faster?

Two weeks ago, the CanJS core team spent time improving our CanJS dev/test/build/doc infrastructure to make it easier to add new features faster.

Backwards Compatibility

One of the most difficult challenges in making improvements to a library is dealing with breaking changes. We want people using CanJS and to keep using it.

Most people understand that APIs change, but they hate it when it happens unexpectedly. We've taken the following steps to strengthen backwards compatibility without slowing down active development.

Semver

CanJS will now strictly follow semantic versioning. Our declared API is what is documented on CanJS.com. Methods that are not documented should be considered unsafe. For example, there's a can.Mustache.get method, but it's not documented, so don't rely on it.

Semantic versioning means you can upgrade CanJS 2.0.5 to any 2.X release. When 2.1 comes out, you will be able to upgrade without problem. In fact, you'll be able to upgrade 2.0.5 to anything less than 3.0.

Old Tests

Maintaining CanJS's 700 tests is hard work. When we deprecate an old API, we typically update all tests to use the new API. For example, if can.view.mustache becomes can.mustache, we replace can.view.mustache in tests like:

test("trailing text", function () {
  can.view.mustache("count", "There are {{ length }} todos")
  var div = document.createElement('div');
  div.appendChild(can.view("count", new can.List([{}, {}])));
  ok(/There are 2 todos/.test(div.innerHTML), "got all text");
});

with:

test("trailing text", function () {
  var template = can.mustache( "There are {{ length }} todos")
  var div = document.createElement('div');
  div.appendChild( template( new can.List([{}, {}]) ) );
  ok(/There are 2 todos/.test(div.innerHTML), "got all text");
});

But after the change, we are no longer testing the deprecated API. We could easily break our promise of semantic versioning.

To make that unavoidable, we made it possible (and easy) to run new releases against old release's tests. In master, we've checked in 2.0.5's tests. Now checking new versions against old tests is as easy as running:

grunt test:compatibility

Dev Build

Starting with 2.0.5, you can download a development version of CanJS that gives warnings about deprecated API changes and common errors. For example, if a template finds something that looks like a custom element, but there is no can.Component for it like:

can.Component.extend({
  tag: "my-tabs",
  scope: { ... }
})

var template = can.view.mustache("<my-tab></my-tab>");

The console will warn you with:

can/view/scanner.js: No custom element found for my-tab.

We'll be adding more warnings in future versions. Let us know other useful warnings and messages by submitting an issue similar to this.

Beta (pre) Downloads

A better CanJS means getting out new features faster. Traditionally, we experiment with new features at Bitovi prior to releasing them in production. But this means only about 20 people are using these features.

Going forward, we are maintaining a minor branch with the tested and document features for the next minor release.

Currently, the minor branch represents 2.1.0-pre. It includes:

  • "attributes" events
  • can.view.tag and can.view.attr template hooks
  • List deferred methods
  • Deprecating can.Model.models and .model in favor of can.Model.parseModels and .parseModel
  • can.Mustache performance improvements

And because we are testing against old versions, 2.1.0-pre is backwards compatible with 2.0.5. You can use it in near-production environments.

We hope that teams wanting these new features will develop against the minor branch and pre-releases. This will help us perfect and harden the API earlier, which allows us to add new features faster.

Download 2.1.0-pre here.

Past, Current, and Future Documentation

You can now easily switch between documentation for past, current, and future releases.

Documentation Select

We've also started adding version numbers to signatures:

Version on a signature

And deprecation warnings:

Deprecation Warning

Other

CanJS is now linted:

Linted code

And docco is back:

docco link

docco image

A Better CanJS

It's our hope that these changes will help us release better features more often. We've got a bright roadmap ahead. Help us get there by using the pre releases, submitting bugs, and implementing features.

Thanks!

@andykant
Copy link

andykant commented Feb 5, 2014

Re: Semantic versioning means you can upgrade CanJS 2.0.5 to any 2.X release. When 2.1 comes out, you will be able to upgrade without problem.

Is that intended to be 2.0.5 to any 2.0.x release? Or are we supporting 2.0.x APIs all the way up to anything < 3.0?

@matthewp
Copy link

matthewp commented Feb 5, 2014

Great article idea, I think knowing these types of things will get more people wanting to contribute. Couple of minor points:

Methods that are not documented should be considered unsafe.

It's unclear to me what this means. Are you saying that an undocumented method is experimental (new?), that's it's rarely used, or that it's deprecated (or a combination of the 3)? I would clarify this with another sentence.

Also, in the conclusion I would touch on how these changes will benefit users of can. You touched on it briefly earlier in the article when you said A better CanJS means getting out new features faster.. I would reiterate this in the conclusion.

@shcarrico
Copy link

"We'll be adding more warnings in future versions. " Can we amend to "We'll be adding more warnings and informational messaging in future versions."

@daffl
Copy link

daffl commented Feb 5, 2014

Can we link the list items from

  • "attributes" events
  • can.view.tag and can.view.attr template hooks
  • List deferred methods
  • Deprecating can.Model.models and .model in favor of can.Model.parseModels and .parseModel
  • can.Mustache performance improvements

To their respective pull requests/commits/documentation?

@justinbmeyer
Copy link
Author

@andy - we are supporting everything up to < 3.0

@matthewcp - I mean, that non documented methods, for example can.Mustache.get is available to be called, but not documented so it's unsafe.

I tried to talk about how this will benefit by brining up the roadmap, I will make the link clearer.

@shcarrico - I had something like that in my first draft, but felt like it made it too wordy. Maybe "more warnings and messages".

@daffl - I mentioned that it did not include these links immediately after I posted the link in hipchat :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment