AngularJS, Angular and Angular v4

March 12, 2017    angular

A lot is happening in the Angular world. A few years ago Angular split into the “Old World” of Angular v.1.x and the “New World” of Angular v.2. Both worlds carry the “Angular” label, which is almost as confusing today as it was when the split happened.

What’s up with the re-branding of Angular v.2 as “Angular”? What is SemVer? And just as we were getting used to Angular v.1 and Angular v.2, along comes Angular v.4. Is that a third “New World”? What happened to Angular v.3?

Yikes, all of this is really confusing!

This article aims to bring clairity to the confusion. At the end, you’ll understand what’s going on, why, and how these changes affect you.

Two Angular Worlds

There are two “Angulars” … and only two “Angulars”.

Angular v.2 was a decisive break from Angular v.1. It’s a new architecture, a new platform, a completely different product with its own approach to building a web client.

Every Angular version from v.2 forward is a step in the evolution of this new product. There will never again be a completely new product called “Angular”.

It might have been better to give the new product an entirely new name. But the Angular team wanted it to inherit the market position, momentum, and fantastic community of the original Angular. To be fair, the same Google team was building the new platform and there is enough conceptual continuity to justify keeping “Angular” in the name.

We were getting used to the idea of calling the old product “Angular 1” and the new product “Angular 2”. But there is a problem. The new product must evolve. Each new release needs a version number. For valid reasons to be explained, for certain releases, the team wants to be able to change the first digit in the version number.

It’s impossibly confusing to refer to the product as “Angular 2” when its version numbers become v.4, v.5, v.6, etc.

The old and new Angular products need names that are fixed and independent of the version number. So they’ve been re-branded.

AngularJS is the official name of the “Old World” product, once known as “Angular 1”.

Angular is the official name of the “New World” product, briefly known as “Angular 2”.

No more “Angular 1” or “Angular 2”.

To understand what’s behind the version numbering scheme that drove this re-branding effort, let’s look at the old product, AngularJS.

AngularJS

AngularJS remains a great product with over a million developers. There are hundreds of thousands of applications written in AngularJS. They aren’t going away overnight, nor should they.

However, AngularJS is essentially frozen. The Angular team won’t add new capabilities. New web client applications should be built in Angular.

Some AngularJS development continues in order to fix bugs and make it easier to migrate to “New World” Angular. The new release with these changes will all have version numbers that begin with 1. You refer to a concrete version by saying, “I’m using AngularJS 1.x.y”.

As I write this, the latest version of AngularJS is 1.6.3.

Breaking changes

I’ve been watching Angular evolve, release to release, since at least version 1.2. It was never obvious if it was safe to update my application to a new release.

There is no clear convention that governs the AngularJS version numbering scheme. Any update can break your application (more on breaking changes below). You must read the change log, understand what it says, and hope for the best.

Suppose your app is on AngularJS v.1.4.4. You see the next one is called AngularJS v.1.4.5. That seems like a minor update. You install it and, boom, you get unexpected errors in unexpected places.

That is so wrong. Updates should be clear and predictable. We should know at a glance if an update can break our code.

Today’s applications can have hundreds of dependencies. No one can be an expert in every dependency. No one has time to read all of the change-logs. We need a simple way to quickly identify which updates are safe and which could be dangerous.

Here’s a painful example from my personal experience working on ui-bootstrap. Our package.json was configured so that npm would install any AngularJS 1.x.x (more on how npm works later). One day, while processing a pull request to fix a typo, our Travis continuous integration system produced 200~ failing tests.

How can a typo cause 200 failing tests? After one hour, we discovered the problem. A new version of AngularJS had been released a few hours ago. The update contained an unexpected (and undocumented) breaking change related to animation. Here is the proof.

Things like that happened quite a few times. It happens less frequently now because (a) the AngularJS team is better at documenting breaking changes and (b) AngularJS has fewer breaking changes because it isn’t evolving.

It’s still a significant risk for an application with dependencies on other libraries that are more volatile and less carefully documented.

AngularJS isn’t the only library with this problem. Hundreds of other libraries release updates with breaking changes every day.

Angular and semantic versioning

The new Angular library escapes this problem by adopting semantic versioning.

With semantic versioning, you can tell if a new Angular release is an easy install, with no breaking changes, simply by looking at the version number. If the first digit is unchanged, there are no breaking changes. If the first digit changes (say from 2 to 4), the release contains a breaking change. You have to investigate what has changed and decide when the time is ripe to upgrade.

That kind of clarity is great news. The downside is that breaking changes are inevitable and, therefore, new releases of Angular are bound to have version numbers like v.4, v.5, v.6, etc.

This realization forced the Angular team to re-brand the product so that it would be crystal clear: Angular is still Angular even as its version number rises to 4, 5, 6 and beyond.

What is semantic versioning and how does it work?

Introducing Semantic Versioning

Semantic Versioning (SemVer) is a convention that dictates how the version number changes for each new release of a library. The version number of a library that conforms to SemVer tells you how each release differs from its predecessor.

A SemVer version has three parts.

We say that a release is a major, minor or patch release when the most significant (left-most) changed number is the major, minor, or patch digit.

Patch release

Imagine we are maintaining a bootstrap library. We give our proud, first the version number, 1.0.0. Suddenly we discover that there is a bug on the datepicker. We forgot about leap years, so February 2016 didn’t have 29 days.

Sounds like a pretty big issue, so we want to make a fix-it release right now. What kind of change will this be?

The release contains only a single bug fix. We assume that no one wanted the datepicker to give the wrong date and we’re confident that the mistake hasn’t been in the wild long enough for anyone to have relied upon that mistake in some perverse way. So this should be a patch release with version 1.0.1.

When someone says: Hey, new ng-bootstrap release, it is 1.0.1. We know beforehand that the release only contains bug fixes so it is safe to update. That is what we call, a predicatable release.

More bugs of this kind? We release 1.0.2, 1.0.3, and so on.

Feature release

When an update only contains fixes, we release a patch version, but when an update contains at least one new feature, it should increment the version’s minor digit, making it a minor release. A minor version can optionally, contains bug fixes as well.

Our datepicker is hugely popular and people have requested additional features such as the ability to add custom themes. We cut a new release with a bunch of these features, as well as some more bug fixes. Because we added new features, we must increment the minor version digit. You typically re-set the patch digit to zero at the same time. Accordingly, we release the 1.1.0 version of the datepicker.

Major release

Updating your app with a patch or a minor version should not break the application. It may fix bugs or introduce new features that you can exploit while updating your app. But the new release shouldn’t cause your app to fail or behave differently than you intended.

You should be able to upgrade to the 1.23.15 datepicker a year from now without making any changes to your app.

Sometimes to fix a bug or add an important feature, we have to make a breaking change. A breaking change means that upgrading to the new version of the library might cause your application to behave in an unexpected way that contradicts previously documented behavior or fail outright.

So… what is exactly a Breaking Change?

Let’s return to our datepicker example. Imagine that the 1.1.0 API allows you to configure the theme with a binding that maps to an @Input property like this:

<datepicker theme="dark"></datepicker>
@Component{
  selector: 'datepicker',
  templateUrl: 'Datepicker.html'
}
export class Datepicker {
  @Input() theme = ''; // default theme
  ...
}

One day, after a couple of beers, we decided that it would be cool to have a blink option that is true by default. The datepicker would flash annoyingly when the date changes.

If you don’t like it, you can disable blink by configuring with another @Input property. Here’s version 1.2.0:

<datepicker theme="dark" blink="false"></datepicker>
@Component{
  selector: 'datepicker',
  templateUrl: 'Datepicker.html'
}
export class Datepicker {
  @Input() theme = ''; // default theme
  @Input() blink = true;
  ...
}

Among the one million datepicker users only one person like the option option. Man, I should go out for beers with that person because obviously we like the same stuff. Was it a bad idea? Probably, but there it is.

The datepicker continues to evolve with more and more options, each implemented as a separate element attribute paired with its own @Input property. We’re up to ten of these by version 1.4.5. The list of options, the implementation, and the effort to configure a datepicker is getting way out of hand:

<datepicker theme="dark" blink="false" closeBoxPostion="top-left" 
   foo="..." bar="..." baz="..." class="...">
</datepicker>
@Component{
  selector: 'datepicker',
  templateUrl: 'Datepicker.html'
}
export class Datepicker {
  @Input() theme = ''; // default theme
  @Input() blink = true;
  @Input() closeBoxPosition = 'top-right'; // default position
  @Input() ... more of these ...
  ...
}

This has to stop. It’s hard for developers to databind to this component because it has so many separate hooks. The code is becoming a mess. Change detection is working overtime. If current trends continue it will only get worse.

You decide to consolidate the customizations into a single DatepickerOptions object that works like this:

<datepicker options="datepickerOptions" class="..."></datepicker>
@Component{
  selector: 'datepicker',
  templateUrl: 'Datepicker.html'
}
export class Datepicker implements OnChange {
  @Input() options: DatepickerOptions;

  ngOnChange() {
    this.options = { ...DefaultDatepickerOptions, ...this.options };
  }
  ...
}

Now the application component that displays the Datepicker exposes a single datepickerOptions property with the desired custom settings.

That’s a vast improvement for everyone.

Unfortunately, it’s a breaking change. The 99% of users who never set an option because they liked the defaults aren’t affected.

But you’ve broken the apps of the 1% who set the theme, or the blink, or any of the other options. When they upgrade to the new Datepicker they’ll get an Angular compilation error complaining about unknown properties.

A broken app should be easy to fix. But it still has to be fixed. The 1% who set any option will have to change the way they interact with the DatePicker, perhaps like this:

@Component{
  selector: 'my-component',
  template: `
    <label>Order Date:
      <datepicker options="datepickerOptions"></datepicker>
    </label>
    ...`
}
export class MyComponent {
  datepickerOptions = {
    blink: false
    closeBoxPosition: 'top-left'
  };
}

A Breaking Change is a change that forces a user to update an application when upgrading to the new library. It doesn’t matter how few users are affected. It’s a breaking change if it affect anyone.

According to SemVer, the new release with this change must increment the major version digit. The revised Datepicker library version becomes 2.0.0.

Because we follow SemVer, users of the Datepicker know, simply by looking at the version number, that this new release might break their apps.

They shouldn’t be surprised. They can read the change log, find the breaking change, and decide if and when to upgrade to the new Datepicker.

You do have a change log, don’t you?

Identify breaking changes in the change log

SemVer doesn’t require a change log but every library should have one. The conventional change log is a Markdown file called CHANGELOG.md.

Your change log should have a new entry for each release, whether patch, minor, or major. The release entry identifies what changed in that release.

It’s especially important to highlight the breaking changes of a major release. The change log entry for Datepicker v.2.0.0 could be as simple as:

Features

  • Can visually display blackout days which the user cannot select by setting the blackoutDays array. See API documentation.

BREAKING CHANGES

  • All datepicker options have been consolidated into a single DatepickerOptions object. You may have to change Datepicker bindings to use the new options object. See the API documentation.

  • The blink option is now false by default.

NPM and SemVer

NPM helps us manage libraries that conform to SemVer. I’ll give you the short story here. You can get the official story on the web

We tell npm which libraries (“packages”) to install by configuring a project.json file. We have different ways of specifying the library version. We can install a specific version of a library by supplying the exact version number:

"cool-library": "1.3.5"

The ~ prefix lets npm install a patch version equal to or greater than specified but not a higher minor or major version:

"cool-library": "~1.3.5"

The ^ prefix lets npm install the latest minor and patch versions but not a higher major version:

"cool-library": "^1.3.5"

This should be your default npm version format because it allows you to stay current without risk of installing a major version with a breaking change.

Consider this history of recent cool library releases

  • 2.1.2
  • 2.0.0
  • 1.4.3
  • 1.3.7
  • 1.3.5

Then npm install delivers cool-library v.1.3.5 with the first specification, v.1.3.7 with the second specification, and v.1.4.3 with the third.

It won’t install either of the 2.x versions until you manually update the version number in package.json so there should be no risk of accidentally installing a cool-library release that breaks your app — if the library author followed the rules.

Remember that AngularJS doesn’t follow SemVer so npm can’t protect us. That is why I stumbled into an error when I installed dependencies for my ui-bootstrap library. The package.json allowed npm to install the latest version of AngularJS (greater than 1.4.0):

"angular": "^1.4.0"

The Travis CI system — which always installs fresh packages when it runs a build — installed the newly released v.1.4.5 which contained a breaking change.

That hurt. It took a long time for me to figure out what was wrong.

That won’t happen again with Angular which does follow SemVer.

The new Angular

Many of us feel that calling the new framework, Angular was a bad idea. The new Angular wasn’t the old Angular with some breaking changes. It was complete rewrite of the framework from the ground up. It deserved a new product name, not a new version number.

Keeping the “Angular” name was confusing enough. But we compounded the confusion by calling the new product Angular 2. The moment we adopted semantic versioning, we knew that the major version number would keep growing.

Imagine having to differentiate

  • Angular 1
  • Angular 2
  • Angular 2, v.2
  • Angular 2. v.4
  • Angular 2. v.5

… forever.

This confusion had to be addressed, first by re-branding and then by separating the product name from the version number.

Henceforth we expect to see …

  • AngularJS 1
  • AngularJS 1.4.x
  • AngularJS 1.6.x

and …

  • Angular v.2.4.9
  • Angular v.4.x.y
  • Angular v.5.x.y

All new Angular releases of the form, 2.x.y, contain new features and bug fixes to the major release that began as Angular 2.

If we created an application using 2.0.0, we can update it to the latest minor version (2.4.9 at the time of this article) and be 100% sure that our application will continue working as it did before.

During the v.2 era, we’ve gained access to i18n stuff, better animations and so on. But there have been no breaking changes.

Angular, like every other living library, must evolve and evolution entails breaking changes.

There are many sources of breaking change.

Sometimes there’s a much better way to doing something that requires a minimal breaking change that affects a few people. How few doesn’t matter.

Sometimes the only way to fix a critical fix is a breaking change.

Sometimes the cause is Angular’s reliance on an upgraded dependency that itself imposes a breaking change. Angular v.4 is built with TypeScript and you’ll have to upgrade to at least TypeScript v.2.2 to use all of Angular’s capabilities.

You can see other examples of Angular breaking changes in the change log for the Angular v.4 release candidates.

Scheduling breaking changes

The Angular team understands that updating a big application is not a casual or easy task. No one wants breaking changes. But it they must happen, they should be predictable.

Most organizations need to plan and find resources for an upgrade effort. They want to know, in advance, how often Angular will change and, most importantly, when an Angular release will contain breaking changes.

Accordingly, the Angular team decided on a release schedule that allows the product to take small steps forward — patch and feature releases — every few weeks and to take big steps forward — with possible breaking changes — every six months.

The schedule for 2016-2017 looks like this:

Optional upgrade

The schedule helps you plan. Upgrading is always optional. You do not have to upgrade every six months just because Angular does.

What happened to Angular v.3?

You did not miss it! The Angular version number is jumping from v.2 to v.4. There is no and never will be a v.3.

They’re skipping v.3 to re-align library version numbers that got out of sync in the initial Angular v.2 release.

Angular is composed of several semi-independent module libraries: core, http, upgrade, router. etc. You can install only those modules that you actually need in your app.

During the development of Angular v.2, the router module went through several iterations. At one point there was a router v.2. It was replaced at the last moment by a completely different implementation which required its own version number and became router v.3.

When you look at the package.json for an Angular v.2 app, you see:

"@angular/core": "2.4.9",
"@angular/http": "2.4.9",
"@angular/router": "3.4.9"

You see the problem? All packages have the same version except the router, so if the next Angular release became v3, what should happen?

"@angular/core": "3.0.0",
"@angular/http": "3.0.0",
"@angular/router": "?"

No one wants to perpetuate the router-off-by-one scheme. The simple solution was to skip v.3 and jump all modules to 4.0.0.

How different is Angular v.4?

Angular 2.0 was released September 14, 2016, about seven months ago. Angular v.4 is primarily a maintenance release with a few breaking changes.

The most notable breaking change is that lifecycle hooks are no longer abstract classes. They’re interfaces now. Most applications treated them as interfaces anyway but some app classes inherited from these classes like this:

@Component()
class SomeComponent extends OnInit {}

You’ll have to change the word extends to implements like this:

@Component()
class SomeComponent implements OnInit {}

That’s not a big deal, is it? You can fix your entire application with a simple search-and-replace in a few minutes..

Angular v4 requires Typescript 2.2. That is a one-line change to the package.json. Animations are now an independent module library, requiring another one-line package.json change and some additional import statements.

There are others breaking changes, but they will only affect a minimal number of applications, if any.

Be sure to check the change log before upgrading.

There are many bug fixes and improvements under the hood, particularly to the size and performance of production builds. There are some new features too such as “Angular Universal” (experimental), *ngFor micro-syntax enhancements, and i18n extensions. More features are in the pipeline for 4.x such as http interceptors.

Angular v.4 is a worthy upgrade that shouldn’t be too difficult to install.

Conclusion

There’s been a lot of understandable concern about Angular v4. Some folks were afraid that Angular v4 is yet another complete rewrite. They wondered if they should wait to explore Angular until v4 landed.

We hope you can see now that the reality is much more pleasant. Angular is great today and steadily evolving along a predictable path to a productive future. Angular v4 is an incremental step forward.

If you haven’t tried Angular yet, start today. Most of you can update your v2 applications to v4 in an afternoon. You’ll be glad you did.

This article has been written by Jesús Rodríguez and Ward Bell.

comments powered by Disqus