Angular 4.3.0 is here!

Angular logo

This is a fairly big release, with a new HttpClientModule, a complete rewrite of the HttpModule 💅! This should be the last minor release before Angular 5, when we can expect some other exciting stuff!

HttpClientModule

The biggest feature of this release is without a doubt the new HttpClientModule. This module is a complete rewrite of the current HttpModule that had some defaults, like the obligation to extract the JSON from the response for every request, no mechanism to handle requests and responses in a generic fashion, and a quite awful testing API.

The new HttpClientModule is a really cool alternative: it solves all these issues, and we migrated our applications fairly easily. And it was mostly code deletions 💖.

We made a little video to show you the difference, and a complete article to help you to migrate your applications.

It showcases the brand new HttpClient service, how to write unit tests, and how to use the new interceptors!

Check out the article we wrote that explains in deep how to use this new module!

Router

A few events have been added to the router, if you need to know when a resolver or a guard is run:

  • ResolveStart, ResolveEnd
  • GuardsCheckStart, GuardsCheckEnd

Forms

The two new validators min and max released with 4.2 have been temporarily rolled back as they were breaking changes :(. They’ll return in a major release, probably 5.0.0.

Style

You may know that the /deep/ “shadow-piercing” combinator can be used to force a style down to child components. This selector had an alias >>> and now has another one called ::ng-deep.

Be warned though: the /deep/ combinator has been deprecated from the Shadow DOM spec and is being removed from all major browsers. So the support will probably also be dropped by Angular in the future. Until then, it is recommended to use ::ng-deep, and to only use it with emulated view encapsulation.

Compiler

This is not really a new feature, but I think it is interesting to understand how things work under the hood.

TypeScript 2.3 recently introduced the concept of transformers in the compiler API. That means some teams can write custom transformations/plugins that are applied to the code compiled by tsc. This is not really something that we common mortals will write, but Angular has its own compiler called ngc that wraps tsc.

Until now, the process for ngc was to compile your templates to generate TypeScript files, and then call tsc to compile your TypeScript code and the TypeScript files generated to JavaScript. If that sounds strange, you can check out our ebook where we explain all this.

With the introduction of transformers, tsc works slightly differently: it starts by parsing the files, does the type-checking, applies any plugin you want, and then generates JavaScript.

Based on this, ngc is now becoming a plugin called in the TypeScript compilation pipeline, rather than a wrapper of the TypeScript compiler.

As Angular developers, we can expect to have very precise type-checking in our templates, referring to the exact line of the problem in HTML source file!

Summary

That’s all for this release: the next important one will be 5.0!

In the meantime, all our materials (ebook, online training (Pro Pack) and training) are up-to-date with these changes if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Angular 4.3 introduced a new module, HttpClientModule, which is a complete rewrite of the existing HttpModule.

This article will show you how to easily migrate to this new module, and why you should (spoiler: because it’s way better 🦄).

Here is a short video we made to show you what’s new with this HttpClientModule.

The rest of the article focuses on what you have to do to migrate your apps. It assumes an app generated with Angular CLI, but if that’s not your case, you’ll still be able to follow, minus some file names that might differ for you.

Migrate your application

The first step is to remove the @angular/http package from your package.json file. Indeed the new HttpClientModule is in the @angular/common/http package, and @angular/common should already be in your package.json file.

Save your file, and run NPM or Yarn to update the node_modules. You should start to see compilation errors in your application, as all the imports from @angular/http are now breaking. That’s good, because it tells you all the files you’ll have to migrate.

The first obvious one is your app.module.ts file, which contains your main NgModule. Replace HttpModule with HttpClientModule in your module’s imports field, and update the TypeScript import from:

import { HttpModule } from '@angular/http';

to:

import { HttpClientModule } from '@angular/common/http';

The second step is to replace every instance of the service Http with the new service HttpClient. This is will usually be the case in your services. This is where using the new HttpClient will shine: you don’t have to manually extract the JSON anymore \o/!

So a service which was looking like that:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { UserModel } from './user.model';

@Injectable()
export class UserService {

  constructor(private http: Http) {}

  list(): Observable<UserModel> {
    return this.http.get('/api/users')
      .map(response => response.json())
  }
}

can be rewritten as:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { UserModel } from './user.model';

@Injectable()
export class UserService {

  constructor(private http: HttpClient) {}

  list(): Observable<UserModel> {
    return this.http.get('/api/users');
  }
}

Feels good to remove this code, doesn’t it?

Migrate your tests

Now let’s move on to the unit tests.

Testing services with HTTP requests was really verbose with HttpModule… You probably had something like:

describe('UserService', () => {

  beforeEach(() => TestBed.configureTestingModule({
    imports: [HttpModule],
    providers: [
      MockBackend,
      BaseRequestOptions,
      {
        provide: Http,
        useFactory: (backend, defaultOptions) => new Http(backend, defaultOptions),
        deps: [MockBackend, BaseRequestOptions]
      },
      UserService
    ]
  }));

  it('should list the users', async(() => {
    const userService = TestBed.get(UserService);
    const mockBackend = TestBed.get(MockBackend);
    // fake response
    const expectedUsers = [{ name: 'Cédric' }];
    const response = new Response(new ResponseOptions({ body: expectedUsers }));
    // return the response if we have a connection to the MockBackend
    mockBackend.connections.subscribe((connection: MockConnection) => {
      expect(connection.request.url).toBe('/api/users');
      expect(connection.request.method).toBe(RequestMethod.Get);
      connection.mockRespond(response);
    });

    userService.list().subscribe((users: Array<UserModel>) => {
      expect(users).toEqual(expectedUsers);
    });
  }));
});

You can now use the new testing API, which is much, much nicer:

describe('UserService', () => {

  beforeEach(() => TestBed.configureTestingModule({
    imports: [HttpClientTestingModule],
    providers: [UserService]
  }));

  it('should list the users', () => {
    const userService = TestBed.get(UserService);
    const http = TestBed.get(HttpTestingController);
    // fake response
    const expectedUsers = [{ name: 'Cédric' }];

    let actualUsers = [];
    userService.list().subscribe((users: Array<UserModel>) => {
      actualUsers = users;
    });

    http.expectOne('/api/users').flush(expectedUsers);

    expect(actualUsers).toEqual(expectedUsers);
  });
});

That should remove a lot of errors you have or all of them.

Maybe you were also adding headers or params to your requests. The new HttpClient allows it too:

const params = new HttpParams().set('page', '1');
this.http.get('/api/users', { params });

const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`);
this.http.get('/api/users', { headers });

In the example above, I set the JWT token needed in the Authorization header. This is something you probably repeat a lot of times in your services, as every request needs it.

The new module introduces a very interesting feature: interceptors. These interceptors are called for every request and response, and allow to easily handle tasks like adding a header to every request, or handling errors in a generic way for example.

First create your interceptor:

@Injectable()
export class GithubAPIInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req);
  }

}

Then add your custom logic, for example to add an OAUTH token to every Github API request, but not to the other requests:

@Injectable()
export class GithubAPIInterceptor implements HttpInterceptor {

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // if it is a Github API request
    if (req.url.includes('api.github.com')) {
      // we need to add an OAUTH token as a header to access the Github API
      const clone = req.clone({ setHeaders: { 'Authorization': `token ${OAUTH_TOKEN}` } });
      return next.handle(clone);
    }
    // if it's not a Github API request, we just handle it to the next handler
    return next.handle(req);
  }

}

If you want to learn more about this API and Angular in general, you can check out our ebook, online training (Pro Pack) and training!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Né un 4 juillet

La société Ninja Squad a été immatriculée le 4 juillet 2012. Nous célébrons donc notre mi-décennie : 5 glorieuses années d’existence. 🎩🙆🕺

Extrait KBis Ninja Squad

Pour ceux qui ne nous connaîtraient pas, rappelons les principes qui régissent Ninja Squad. On est 4 fondateurs dont 3 salariés développeurs à plein temps. Tous égaux, tous actionnaires, sans lien de subordination (pas de managers, pas de commerciaux). Les salaires sont aussi égaux, quelque soit l’activité ou l’expérience de chaque ninja. On ne compte pas les vacances, et on essaie d’encourager les projets de chacun, qu’ils soient professionnels, dans l’open-source, ou plus personnels (voyage, famille, etc.).

En 5 ans, nous n’avons pas dérogé à un autre principe fondateur : on ne facture que 4 jours par semaine, et nous réservons les vendredis au reste : side projects, administratif, ou… procrastination.

Bref, on s’est juste donné les moyens de faire notre métier/passion dans des conditions correctes, en bonne entente avec nos clients, et en se faisant plaisir.

Et les résultats sont au beau fixe. Nous avons le luxe de choisir nos missions, et d’en refuser bien plus qu’on en accepte (on les refile alors aux copains d’autres NoSSII, ou indépendants). Si nous n’avons pas encore notre dernier bilan annuel (qui vient de se clôturer au 30 juin pour nous), il s’annonce encore meilleur que le précédent, comme chaque année. Nous le publierons ici quand il sera disponible.

En attendant, notre CFO amateur Cédric nous indique les chiffres suivants : 365k€ de chiffre d’affaires, dont :

  • 130k€ de prestations de développement ;
  • 190k€ de formation et conseils, essentiellement sur Angular ;
  • et 60k€ de ventes d’ebooks.

Nous nous distribuerons alors cette année encore une confortable prime annuelle, en plus de nos 2500€ de salaire net. Car comme chaque année, nous nous partageons les bénéfices en fin d’exercice (un peu moins de 20k€ nets chacun à l’issue du précédent). Du moins, tant que nous ne convaincrons pas JB de nous acheter des Tesla de fonction.

Et que faisons-nous au quotidien, ces derniers temps ?

  • Cédric Exbrayat, quand il ne donne pas une formation Angular ou assure un audit à l’autre bout de l’Europe (et il est déjà booké jusqu’à la fin de l’année), ne fait plus de prestations longues de développement, car il se consacre à la maintenance de son ebook Angular et de son ensemble d’exercices, ce qui est très consommateur de temps ;
  • Jean-Baptiste Nizet, quand il n’assure pas une formation Angular en remplacement de Cédric déjà pris ailleurs, fait du développement chez un client lyonnais historique où nous nous sentons bien ;
  • Agnès Crépet, quand elle n’est pas à son travail dans une grande école d’ingénieur stéphanoise, réalise quelques missions de conseil pour Ninja Squad ;
  • et Cyril Lacote (moi), quand ses enfants lui laissent un peu de temps, fait aussi du développement chez ce même client historique lyonnais.

Quelques idées reçues et réflexions

Les éxonérations fiscales

On entend souvent dire : “les trois premières années sont les plus dures”.
Ou son contraire : “les premières années sont faciles, avec les exonérations fiscales, c’est après que ça fait mal”.

Ninja Squad a, dès sa première année, payé des impôts, taxes, et prélèvements sociaux, sans exonération d’aucune sorte. Et on en est plutôt fiers. Ce furent ainsi 92k€ sur le bilan précédent (probablement plus cette année), soit 28% de notre chiffre d’affaires de 323k€. Nous voilà donc plus recommandables et moins evil que des grosses sociétés comme Google, Apple ou Amazon.

On peut donc créer une société pérenne sans aucun financement extérieur, ni emprunt, ni aide privée ou publique, ni apport (au-delà du capital social dont le montant peut être négligeable ; pour nous, il est de 10101€).

Il est l’or, mon trésor

Il faut se constituer une bonne trésorerie, un bon matelas d’avance, parce que tout le monde vous payera en retard.

C’est comme un sport national, mais sans le frisson de la compétition. C’est devenu normal, tout le monde paie en retard, personne ne s’en étonne.
Et ce sont souvent les mêmes entreprises qui respecteront scrupuleusement les contraintes pour toucher illégitimement leur Crédit Impôt Recherche chaque année qui feront tout/rien pour ne pas vous payer à temps.

Les clients en retard de paiement

Mais ces entreprises ne sont même pas les pires. Les pires sont les OPCAs, ces organismes de formation privés qui reçoivent chaque année nos taxes professionnelles, comme le FAFIEC, l’AgefosPME, ou l’AFDAS, et qui fonctionnent encore comme au siècle dernier.
Ils ne se contentent pas de vous payer systématiquement avec plusieurs mois de retard, après vous avoir demandé une tonne de documents : ils vous obligent en plus à passer par du courrier papier, et vous demandent parfois de refaire le travail plusieurs fois parce que leur scanner est en panne (true story, voir tweets ci-dessous) 😅.

Votre produit est votre sous-produit

Avec Ninja Squad, on rêvait (et on rêve encore) de sortir un produit et d’en vivre.

On a sorti un outil open-source qui a son petit succès chez les développeurs Java : DbSetup. Mais comme c’est de l’open-source, il n’est pas question d’en vivre.

On a sorti une plateforme de quiz, Quizzie, qui avait un business model en béton : gratuit pour un quiz public, payant pour un quiz privé. Ca a marché… moyennement : on n’a vendu que deux quiz, un premier au tout début, et un second très récemment 🎉. Soit une croissance organique d’à peu-près… 0% 😅.

En plus d’avoir trois ninjas dans l’organisation de MiXiT à Lyon, on participe toujours à des conférences, que ce soit en tant qu’orateurs :

ou en tant que simples spectateurs, comme SudWeb récemment, où on a pu échanger sur les modèles d’entreprise alternatifs comme le nôtre.

Dernièrement, on aide un centre de santé communautaire stéphanois, en leur réalisant bénévolement une application de gestion, qui préserve l’anonymat des migrants.

De beaux projets, mais rien qui permette d’en vivre.
Zach Holman disait The Product is the Byproduct : votre produit ne sera pas ce que vous imaginiez au départ, mais probablement le sous-produit que votre activité aura généré.

Il faut croire que pour nous, ce fut l’expertise Angular de Cédric. Son premier ebook sur AngularJS 1.x eut déjà un succès respectable : plus de 14k€ de chiffre d’affaires, et encore 1500€ de ventes l’année dernière, sur la France essentiellement, ce qui ferait déjà rêver la majorité des auteurs de livres techniques qui sortent via un circuit d’édition classique.

Et on a bien eu raison de le payer partiellement pendant son tour du monde pour qu’il relise chaque commit de l’équipe Angular 2, alors que le framework était en gestation, et qu’il commence à rédiger son second ebook. Il s’est pour le moment vendu pour plus de 85k€ au total dans le monde entier (dans 105 pays !), dont 60k€ sur cette seule dernière année. Et le Pack Pro, notre plateforme de formation en ligne, est en pleine explosion alors que les entreprises se mettent sérieusement à Angular 2 4 5, donc on n’exclut pas de tutoyer, Inch’Allah, les records de Discover Meteor (même si on s’est interdit de notre côté de vendre des goodies à prix d’or dans un pack Super Premium).

Dernièrement, des auteurs nous contactent même pour bénéficier de cette plateforme qui permet de coder et valider à son rythme des exercices, pour mettre en pratique la théorie apprise dans leur livre. Qui sait, peut-être que d’autres ebooks/formations en ligne préparés avec amour seront bientôt disponibles…

Nos ebooks n’étaient au départ que la mise en forme de nos supports de formation. On a donc peut-être trouvé, finalement, le sous-produit qui constituera notre produit. 🤞

Bisous

Ce nouvel exercice commencera par un nouveau tour du Monde de Cédric (il veut aller en Antarctique depuis qu’il a invité Marie Manceau et ses manchots à MiXiT), alors on n’est pas à l’abri qu’il revienne avec un nouveau master plan décennal.

En attendant, bisous à tous, merci à ceux qu’on croise aux détours de conférence et qui nous disent tout le bien qu’ils pensent de nous 😘, et à dans 5 ans.

Cet article sera mis à jour prochainement avec notre dernier bilan définitif, pour ceux qui ont une appétence ou une curiosité pour les chiffres.

via GIPHY


Cyril Lacôte


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Angular 4.2.0 is here!

Angular logo

Templates

As we explained in our blog post about Angular 4.1, it is now possible to use strictNullChecks in your applications.

The ! post-fix operator is now also available in templates:

<h2>{{ possiblyNullRace!.name }}</h2>

The code generated from the AoT compiler will then include the non-null assertion operator too, allowing to do strict null checking in your templates also!

Forms

Two new validators joins the existing required, minLength, maxLength, email and pattern: min and max help you validate that the input is at least or at most the value specified.

<input type="number" [(ngModel)]="user.age" min="0" max="130">

Update (2017-06-17): The min and max validators have been temporarily removed from Angular in version 4.2.3, as they are a breaking change. They’ll return in a major version, maybe 5.0.0.

Animations

Animations received a lot of love in this release!

A new query function has been introduced in the animation DSL, allowing to query elements in the template. It uses querySelectorAll behind the scene, so you can use an element or a class as parameter for example. It also supports pseudo-selectors, and that opens a few interesting possibilities!

For example, we can now easily animate elements in a NgFor:

<div [@races]="races?.length">
  <button class="btn btn-primary mb-2" (click)="toggle()">Toggle</button>
  <div *ngFor="let race of races | slice:0:4">
    <h2>{{race.name}}</h2>
    <p>{{race.startInstant}}</p>
  </div>
</div>

with the following animation:

trigger('races', [
  transition('* => *', [
    query(':leave', [
      animate(1000, style({ opacity: 0 }))
    ], { optional: true }),
    query(':enter', [
      style({ opacity: 0 }),
      animate(1000, style({ opacity: 1 }))
    ], { optional: true })
  ])
])

Now, every time an element will leave (removed from the races array), it will slowly fade out. And when an element enters, it will slowly fade in.

Query animation

Another function introduced is stagger. it allows to build a staggering animation, where the elements will animate one after the other.

trigger('races', [
  transition('* => *', [
    query(':leave', [
      stagger(500, [
        animate(1000, style({ opacity: 0 }))
      ])
    ], { optional: true }),
    query(':enter', [
      style({ opacity: 0 }),
      animate(1000, style({ opacity: 1 }))
    ], { optional: true })
  ])
])

Stagger animation

animation has also been added to build reusable animations. The syntax allows to have dynamic parameters with default values. When you then need to use a reusable animation, you can call useAnimation, and override the default parameters if you want to.

In our small example, we can for example define a changeOpacity animation:

const changeOpacity = animation(
  [animate(1000, style({ opacity: '{{opacity}}' }))],
  { params: { opacity: 0 } }
);

This animation will slowly transition to the defined opacity (by default 0). Then we can use this animation:

trigger('races', [
  transition('* => *', [
    query(':leave', [
      stagger(500, [
        useAnimation(changeOpacity)
      ])
    ], { optional: true }),
    query(':enter', [
      style({ opacity: 0 }),
      useAnimation(changeOpacity, { params: { opacity: 1 } })
    ], { optional: true })
  ])
])

You can give various options to the useAnimation, like the delay you want to apply or the duration.

Note that when an element is animating, Angular will add a ng-animating class on the element. You can customize your CSS to use it, or you can use the pseudo-selector :animating in a query to style these elements.

It’s now also possible to trigger “child” animations, with the animateChild function. It can be handy to animate the router transitions for example.

Last but not least, we can now inject AnimationBuilder in our components, to programmatically build animations, and trigger them on demand from the code.

Tests

TestBed.overrideProvider()

The team is also working on the internals to bring interesting features, like the possibility to test in AoT mode. This materializes in this release with a new method on TestBed called overrideProvider, that allows to override a provider, no matter where it was defined (whereas you currently have to know the module/component that declared the provider you want to override).

This is a small step to have the same features between tests in JiT mode and in AoT mode. And this is really interesting for developers, as currently you can only test in JiT mode, which can lead to discrepancies. Indeed you can have an app that runs perfectly, and no error in your unit tests, and then try to build the app with the AoT compiler, and see a bunch of errors. In a near future, we will be able to test in AoT mode too, so you’ll be sure that your app runs fine in both modes.

If you want to learn more on this topic, take a look at the official design doc.

The AoT compiler will also become incremental soon, allowing to use it during development. Even if it is possible to use it right now when you’re coding, it’s too slow for most applications, as every change triggers a full rebuild of the application.

flush()

Another utility function called flush has been added. You may know that Angular comes with a built-in support for asynchronous tests.

For example, let’s say you have a component which displays a welcome message after a few seconds:

@Component({
  selector: 'pr-welcome',
  template: '<p>{{ greetings }}</p>'
})
export class WelcomeComponent implements OnInit {

  greetings: string;

  ngOnInit() {
    setTimeout(() => this.greetings = 'Hello there!', 3000);
  }

}

After 3 seconds, the greetings field will be initialized and the template will be updated.

Now how do you test this?

The first time you encounter something like this, you may be tempted to write a naive test, like waiting for 3 seconds before testing the content of the template:

it('should have a greeting message', () => {
  const fixture = TestBed.createComponent(WelcomeComponent);
  const element = fixture.nativeElement;
  fixture.detectChanges();

  setTimeout(() => {
    fixture.detectChanges();
    const message = element.querySelector('p').textContent;
    expect(message).toBe('Hello there!');
  }, 3000);
});

This will succeed… for the wrong reasons! It will indeed always succeed, as Jasmine will simply exit the test without running the assertions inside the setTimeout.

Angular offers the async function to wrap your test and force Jasmine to wait for the asynchronous functions in your test to finish:

it('should have a greeting message', async(() => {
  const fixture = TestBed.createComponent(WelcomeComponent);
  const element = fixture.nativeElement;
  fixture.detectChanges();

  setTimeout(() => {
    fixture.detectChanges();
    const message = element.querySelector('p').textContent;
    expect(message).toBe('Hello there!');
  }, 3000);
}));

This time the test succeeds for the right reasons. But we now have a test that needs 3 seconds to execute…

Angular allows you to do much better by using fakeAsync and tick. fakeAsync is used to wrap your test into a zone where you master the time! And tick can be used to fast-forward the time for as many milliseconds as you want. We can write the same test with these two like this:

it('should have a greeting message', fakeAsync(() => {
  const fixture = TestBed.createComponent(WelcomeComponent);
  const element = fixture.nativeElement;
  fixture.detectChanges();

  tick(3000);
  fixture.detectChanges();
  const message = element.querySelector('p').textContent;
  expect(message).toBe('Hello there!');
}));

The test is now instantaneous and can be read as if everything is synchronous!

You still need to know how long to wait in your test, and that’s where the new flush function can help. You can use flush instead of tick and the test will automatically wait until all macrotask events (like timeout) have been cleared from the event queue:

it('should have a greeting message', fakeAsync(() => {
  const fixture = TestBed.createComponent(WelcomeComponent);
  const element = fixture.nativeElement;
  fixture.detectChanges();

  flush();
  fixture.detectChanges();
  const message = element.querySelector('p').textContent;
  expect(message).toBe('Hello there!');
}));

fixture.whenRenderingDone()

A method called whenRenderingDone has also been added to the ComponentFixture class. It returns a promise and is slightly similar than whenStable but focuses on waiting the animations to be done. As you can imagine, it will be really useful if you need to test components with animations.

Summary

That’s all for this release! The focus was mainly on animations and tests, and the team is also working on reducing the bundle size of our applications, with the help of the Google Closure Compiler. I think we’ll learn more about that very soon!

In the meantime, all our materials (ebook, online training (Pro Pack) and training) are up-to-date with these changes if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Angular 4.1.0 is here!

Angular logo

This will be a short blog post, because there are not a lot of new features…

The most part of the work has been done on the official docs, which are now an Angular CLI app, and this migration takes some time. We can then expect to have nice new content when this will be done.

So, what are the new features? Let’s dive in!

i18n

The internationalization module has a few bugfixes, and a notable new feature: the extracted messages file now has the source file for each message. It will be far easier for developers to know where the messages come from!

<trans-unit id="home.title" datatype="html">
  <source>Welcome to Ponyracer</source>
  <target/>
  <context-group purpose="location">
    <context context-type="sourcefile">src/app.component.ts</context>
    <context context-type="linenumber">10</context>
  </context-group>
</trans-unit>

Core

The main new feature of this release is the support of the brand new TypeScript 2.3 version, and the support of strictNullChecks.

This option allows to check if you won’t run into nullability problems in your app. Angular itself now has correct types. For example, when you try to retrieve a FormControl from a FormGroup with get, the returned type is AbstractControl | null.

That’s because the control you are trying to get might not exist, and, if you are not careful, you are introducing a bug in your application by supposing it does exist.

If you don’t have the strictNullChecks option, you can do:

static passwordMatch(control: FormGroup) {
  const password = control.get('password').value;
}

but when you enable it, the compiler will complain, and may save you by warning you that the control may not exist, and that your code should handle this case.

You have to do something like:

static passwordMatch(control: FormGroup) {
  const passwordCtrl = control.get('password');
  const password = passwordCtrl !== null ? passwordCtrl.value : '';
}

Or you can use the ! post-fix expression operator introduced by TypeScript, to basically say to the compiler “Shut up”:

static passwordMatch(control: FormGroup) {
  const password = control.get('password')!.value;
}

It can also be really interesting for your application models. Let’s say you have a UserModel representing your user, with a surname field that can be null. If you declare it correctly, the type should be:

interface UserModel {
  surname: string|null;
}

Then, with the strictNullChecks option activated, the compiler will help you when you use this model. For example:

this.user.surname.toLowerCase();

will throw a warning as the surname field can be null.

When you have complex entities coming from your server, it can really help you to have this kind of warning to avoid subtle and hard to avoid bugs.

That’s all for this small release!

All our materials (ebook, online training (Pro Pack) and training) are up-to-date with these changes if you want to learn more!

Oh, and our Pro Pack has 3 new exercises about the router! A perfect way to learn about protecting routes with guards, nested routes, resolving data before displaying the component, and how to split your app in small chunks that can be lazy-loaded.


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


🎉 Here we are, Angular 4.0.0 is out, right on schedule ! 🎉

Angular logo

Technically there are some breaking changes, explaining that’s why the major version number has changed. And, if you missed it, there is no Angular 3: the router package was in version 3.x, so instead of bumping everything to 3.0 and the router to 4.0, the team chose to bump everything to 4.0.

The breaking changes are quite limited though, we updated several of our apps in a few minutes: nothing too scary.

TypeScript 2.1+ is now required (it was 1.8+ before), and some interfaces have changed or are deprecated (rarely used in most applications, like OpaqueToken or SimpleChange).

TypeScript 2.1 and 2.2 have brought really nice features you should check out. Angular 4 now supports them (and you will soon be able to activate the new strictNullChecks TypeScript option for example).

So what does this new Angular version bring? Let’s dive in!

Ahead of Time compilation - View Engine

This is probably the biggest change, even if, as a developer, you will not see the difference.

As you may know, in AoT mode, Angular compiles your templates during the build, and generates JavaScript code (by opposition to the Just in Time mode, where this compilation is done at runtime, when the application starts).

AoT has several advantages: it errors if one of your templates is incorrect at build time instead of having to wait at runtime, and the application starts faster (as the code generation is already done). You also don’t have to ship the Angular compiler to your users, so, in theory, the package size should be smaller. In theory, because the downside is that the generated JS is generally bigger than the uncompiled HTML templates. So, in the vast majority of applications, the package is in fact bigger with AoT.

The team worked quite hard to implement a new View Engine, that produces less code when you use the Ahead of Time compilation. The results are quite impressive on large apps, while still conserving the same performances.

To give you a few numbers, on two medium apps we have, the bundle sizes went:

  • from 499Kb to 187Kb (68Kb to 34Kb after gzip)
  • from 192Kb to 82Kb (27Kb to 16Kb after gzip)

That’s quite a big difference!

Interesting to note that in the design doc, the Angular team compares the performance (the execution time of course but also the pressure on the memory) with the baseline implementation (best vanilla JS they could write) Angular 2.x and InfernoJS (a really fast React-like implementation).

Universal

A ton of work has also been done on the Universal project which allows you to do server-side rendering. The project was mainly maintained by the community until now, but, starting with this release, it’s now an official Angular project.

Animations

Animations now have their own package @angular/platform-browser/animations (one of the things you may have to change when you update). This means the bundle you ship to your users will not include useless code if you don’t use animations in your app.

Templates

template is now ng-template

The template tag is now deprecated: you should use the ng-template tag instead. It still works though. It was a bit confusing as template is a real HTML tag that Web Component can use. Now Angular has its own template tag: ng-template. You will have a warning if you use the deprecated template somewhere when you update to Angular 4, so it will be easy to spot them.

ngIf with else

It’s now also possible to use an else syntax in your templates:

<div *ngIf="races.length > 0; else empty"><h2>Races</h2></div>
<ng-template #empty><h2>No races.</h2></ng-template>

as

Another addition to the template syntax is the as keyword, to simplify the let syntax. It allows to store a result in a variable of the template, to use it in the element.

It can be useful to store a sliced collection for example:

<div *ngFor="let pony of ponies | slice:0:2 as total; index as i">
  {{i+1}}/{{total.length}}: {{pony.name}}
</div>

Or even more useful, to subscribe only once to a pipe with async. If race is an observable, instead of the bad and ugly:

<div>
  <h2>{{ (race | async)?.name }}</h2>
  <small>{{ (race | async)?.date }}</small>
</div>

you can now use the good:

<div *ngIf="race | async as raceModel">
  <h2>{{ raceModel.name }}</h2>
  <small>{{ raceModel.date }}</small>
</div>

Pipes

Titlecase

Angular 4 introduced a new titlecase pipe. It changes the first letter of each word into uppercase:

<p>{{ 'ninja squad' | titlecase }}</p>
<!-- will display 'Ninja Squad' -->

Http

Adding search parameters to an HTTP request has been simplified:

http.get(`${baseUrl}/api/races`, { params: { sort: 'ascending' } });

Previously, you had to do:

const params= new URLSearchParams();
params.append('sort', 'ascending');
http.get(`${baseUrl}/api/races`, { search: params });

Test

Overriding a template in a test has also been simplified:

TestBed.overrideTemplate(RaceComponent, '<h2>{{race.name}}</h2>');

Previously, you had to do:

TestBed.overrideComponent(RaceComponent, {
  set: { template: '<h2>{{race.name}}</h2>' }
});

Service

Meta

A new service has been introduced to easily get or update meta tags:

@Component({
  selector: 'ponyracer-app',
  template: `<h1>PonyRacer</h1>`
})
export class PonyRacerAppComponent {

  constructor(meta: Meta) {
    meta.addTag({ name: 'author', content: 'Ninja Squad' });
  }

}

Forms

Validators

One new validator joins the existing required, minLength, maxLength and pattern. email helps you validate that the input is a valid email (good luck finding the correct regular expression by yourself).

Compare select options

A new directive has been added to help you compare options from a select: compareWith.

<select [compareWith]="byId" [(ngModel)]="selectedPony">
   <option *ngFor="let pony of race.ponies" [ngValue]="pony">{{pony.name}}</option>
</select>

byId(p1: PonyModel, p2: PonyModel) {
   return p1.id === p2.id;
}

Router

ParamMap

A new interface has been introduced to represent the parameters of a URL: ParamMap. Instead of using params or queryParams, you should now use paramMap or queryParamMap, because they offer the choice between get() to get a value, or getAll() to get all values (as query parameters can have multiple values for example).

const id = this.route.snapshot.paramMap.get('ponyId');
this.ponyService.get(id).subscribe(pony => this.pony = pony);

or as an Observable:

this.route.paramMap
  .map((params: ParamMap) => params.get('ponyId'))
  .switchMap(id => this.ponyService.get(id))
  .subscribe(pony => this.pony = pony);

CanDeactivate

The CanDeactivate interface now has an extra (optional) parameter, containing the next state (where you are going to navigate). You can now implement clever logic when your user navigates away from the current component, depending on where he/she is going.

I18n

The internationalization is slowly improving with tiny things. For example, ngPlural is now simpler:

<div [ngPlural]="value">
  <ng-template ngPluralCase="0">there is nothing</ng-template>
  <ng-template ngPluralCase="1">there is one</ng-template>
</div>

compared to what we had to write:

<div [ngPlural]="value">
  <ng-template ngPluralCase="=0">there is nothing</ng-template>
  <ng-template ngPluralCase="=1">there is one</ng-template>
</div>

We added a complete chapter on internationalization in our ebook, with several use cases and best practices described if you want to learn more about i18n!

Summary

This release brings some nice features and a really welcome improvement of the generated code size, for the price of very few breaking changes that should not impact you a lot. The migration has been quite smooth for us.

All our materials (ebook, online training (Pro Pack) and training) are up-to-date with these changes if you want to learn more!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


New month, new minor release of Angular! December is the month of the last 2.x releases, because the next one will be… Angular 4! If you missed the official announcement (Igor Minar’s keynote), let me sum it up for you.

We’ll have a major release every six months, according to the plan. The next major release is planned for March 2017. It should have been Angular 3, but the Angular router is already with a version number in 3.x (because it has been rewritten several times during Angular development). So to avoid trouble, everything will be bumped to 4.x! Angular 3 will never exist, Angular 4 is the next one, with Angular 5 just around the corner. And now the framework should be called just “Angular”.

Don’t worry, these releases are not a complete rewrite with no backward compatibility like Angular 2 was. They will maybe contain deprecations and new APIs. Technically Angular 4 is a new major release because it contains a breaking change: the minimum version of TypeScript, if you use it, will be 2.1, whereas the current minimum version is 1.8. Nothing too scary.

Back to our 2.3 and 2.4 releases: what’s new in these small releases?

Language service

One of the most exciting feature is not really in Angular itself, but this release contains a new module that will be reaaaaally handy: a language service module. This is really similar to what TypeScript offers. A language service allows the IDEs to provide great autocompletion. It’s basically an API that the IDE can call to ask “what smart thing can I suggest at this position in this file?”.

That unlocks the possibility to have smart autocompletion in templates for example (something the IDEs are not currently great at).

There is already a VS Code plugin that you can try here, and JetBrains already announced they will include it in their next release (2017.1).

Here is how it works in VS Code:

Inheritance

You can now use inheritance in your apps.

You already could but the decorators from the parent were ignored: now, the “last” decorator (when you list them in the ancestor first order) of each kind will be applied.

@Component({ selector: 'ns-pony'})
export class ParentPony {}

// will use the parent decorator
export class ChildPony extends ParentPony {}

// will use its own decorator
@Component({ selector: 'ns-other'})
export class OtherChildPony extends ParentPony {}

If you define the same decorator on the child, this decorator will be used (there is no fancy property merging from the parent and the child).

If a class inherits from a parent class and does not declare a constructor, it inherits the parent class constructor, meaning that the dependency injection will be properly done in the parent class.

The lifecycle hooks defined in the parent class will also be called properly, unless they are overridden in the child class:

export class ParentPony implements OnInit {
  ngOnInit() {
    console.log('will be called');
  }
}

// the parent `ngOnInit` will be called
@Component({ selector: 'ns-pony'})
export class ChildPony extends ParentPony {}

Route reuse strategy

The Angular router tries to optimize a few things for you, especially when you navigate from a route to itself: when you go from races/12 to races/13, the router will reuse the RaceComponent (instead of destroying it and recreating it). This is powerful, but you then need to subscribe to an observable from the router to know when the parameters change, to display the correct race for example.

This is still the default behavior, but you can now turn it off, and ask the router to destroy and recreate your component every time, by implementing a RouteReuseStrategy.

See you next year to dig in the new releases, and the upcoming Angular 4!

Check out our ebook and Pro Pack if you want to learn more about Angular!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


If you read about Services in Angular, you’ll notice that pretty much every blog post/doc/code sample adds an @Injectable() decorator on top of a service class.

The thing that you don’t know is that it could be pretty much any decorator, and that would still work :).

Let’s take an example:

@Component({
  selector: 'ponyracer-app',
  template: '<h1>PonyRacer</h1>'
})
export class PonyRacerAppComponent {
  constructor(private appService: AppService) {
    console.log(appService);
  }
}

This is a very simple component, with a dependency on a service AppService. The service looks like:

export class AppService {
  constructor() {
    console.log('new app service');
  }
}

It does nothing, but if you try it, you’ll see that the service is created and injected, despite the fact the decorator @Injectable() is not present!

Why does that work? Let’s check the JavaScript generated from these TypeScript classes:

var AppService = (function () {
    function AppService() {
      console.log('new app service');
    }
    return AppService;
}());
exports.AppService = AppService;

I skipped a bit of generated code to focus on the interesting part. The class AppService generates a pretty simple JavaScript. Let’s compare that to the PonyRacerAppComponent class:

var PonyRacerAppComponent = (function () {
    function PonyRacerAppComponent(appService) {
        this.appService = appService;
        console.log(appService);
    }
    PonyRacerAppComponent = __decorate([
        core_1.Component({
            selector: 'ponyracer-app',
            template: '<h1>PonyRacer</h1>'
        }),
        __metadata('design:paramtypes', [app_service_1.AppService])
    ], PonyRacerAppComponent);
    return PonyRacerAppComponent;
}());

Wow! That’s much more code! Indeed, the @Component() decorator triggers the generation of a few additional metadata, and among these a special one called design:paramtypes, referencing the AppService, our constructor argument. That’s how Angular knows what to inject in our Component, cool!

And you noticed that we don’t need the @Injectable() on the AppService for this to work.

But let’s say that now, our AppService has a dependency itself:

export class AppService {
  constructor(http: HttpService) {
    console.log(http);
  }
}

If we launch our app again, we’ll now have an error:

Error: Can't resolve all parameters for AppService: (?).

Hmm… Let’s check the generated JS:

var AppService = (function () {
    function AppService(http) {
        console.log(http);
    }
    return AppService;
}());
exports.AppService = AppService;

Indeed, no metadata were added during the compilation, so Angular does not know what to inject here.

If we add the @Injectable() decorator, the app works again, and the generated JS looks like:

var AppService = (function () {
    function AppService(http) {
        console.log(http);
    }
    AppService = __decorate([
        core_1.Injectable(),
        __metadata('design:paramtypes', [http_service_1.HttpService])
    ], AppService);
    return AppService;
}());
exports.AppService = AppService;

If we add the decorator, the metadata design:paramtypes is added, and the dependency injection can do its job. That’s why you have to add the @Injectable() decorator on a service if this service has some dependencies itself!

But the funny thing is that you could add any decorator. Let’s build our own (useless) decorator:

function Foo() {
  return (constructor: Function) => console.log(constructor);
}

@Foo()
export class AppService {
  constructor(http: HttpService) {
    console.log(http);
  }
}

The @Foo() decorator does not do much, but if we check the generated JS code:

var AppService = (function () {
    function AppService(http) {
        console.log(http);
    }
    AppService = __decorate([
        Foo(),
        __metadata('design:paramtypes', [http_service_1.HttpService])
    ], AppService);
    return AppService;
}());
exports.AppService = AppService;

Wow, the metadata were generated! And indeed, the app still work perfectly!

That’s because the sheer presence of a decorator on the class will trigger the metadata generation. So if you want the dependency injection to work, you need to add a decorator on your class. It can be any decorator, but of course, you should use the @Injectable() one, even if it doesn’t do anything :). The best practice is to add it on every service, even if it doesn’t have any dependencies on its own.

Check out our ebook and Pro Pack if you want to learn more about Angular!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Le jeudi 24 novembre 2016, Agnès Crépet et Cyril Lacote assuraient la keynote d’ouverture de Codeurs en Seine 2016 : Codeurs du Monde.
L’équipe d’organisation leur avait demandé de raconter l’expérience de leur tour du monde.

La vidéo

La vidéo, avec slides synchronisés, est disponible chez InfoQ.

Si vous préférez la lecture, en voici la retranscription complète.



La retranscription

Cette diapositive de titre devient extrèmement cocasse quand on réalise qu’elle montre des développeurs Java sur l’île de Java. Ha ha.

Que racontent Agnès Crépet et Cyril Lacote ?

Agnès Crépet est développeuse, Java Champion, membre active de Duchess France, ex-organistratice du LyonJUG, et co-fondatrice de la conférence Mix-IT à Lyon.

Cyril Lacote est dévelopeur Java. Après 10 ans de prestations en SSII, voulant travailler à l’étranger avec Agnès, il a cru trouver un job de rêve chez Google à Londres. Contre toute attente, il n’y resta qu’un mois, avant de s’enfuir (on en reparlera).

Il participe aussi à l’organisation de la conférence Mix-IT (dont il portait ce jour un t-shirt, en complète indécence et irrespect pour Codeurs en Seine qui les recevait).

Agnès et Cyril se lancent alors dans un jeu de question-réponses pour sortir le public de leur léthargie (et surtout se déstresser un peu en cachette). L’audience est-elle heureuse, dans leur vie personnelle (mais on s’en fout complètement) ou dans leur job ?

Il s’avéra que oui, l’audience était plutôt heureuse.

En 2011, Agnès et Cyril sortaient ainsi d’une dizaine d’années de développement. Même un job dans une boîte de rêve comme Google ne fut pas l’idéal. Alors libres de toute contrainte et attache, ils ont décidé de partir faire un Tour du Monde, pour voir comment c’était ailleurs.

Pourquoi attendre 5 ans pour en parler ? Parce qu’entre temps ils ont essayé de survivre à la naissance de deux enfants rapprochés (et ce n’est pas une mince affaire). Et maintenant, ils ont le recul pour constater combien cela les a marqué, quelles leçons ils en ont tirées, et lesquelles ont été fructueuses.

Est-ce que vous reconnaissez ce minuscule pays de l’Afrique de l’Ouest ? Non, ce n’est pas le Bénin, mais son voisin le Togo.

Togo, Malaisie, Indonésie, USA, Suède. Voici les pays que traversera cette présentation. Dans leur tour du monde, ils sont aussi passés en Thaïlande, à Bali, en Australie, et en Nouvelle-Zélande, mais comme ils n’ont fait que profiter du pays, ils n’en parleront pas (même si ça vaut le coup).

Ils n’avaient pas envie de voyager qu’en touristes. Ils voulaient rencontrer des gens, et notamment des dévelopeurs. Alors ils ont fait ce qu’ils savaient faire : enseigner du Java et partager leur expérience de développeur dans différents meetups. Ils étaient souvent nourris et logés en échange de leurs formations, ce qui leur convenait parfaitement.

Agnès, alors très impliquée dans la communauté Duchess France, n’a pas pu s’empêcher de faire aussi un peu de prosélytisme, en aidant au montage de deux antennes locales : Duchess Africa et Duchess Indonésia.

Quelques faits marquants glanés autour du monde

Nous voilà partis pour un Tour du Monde en 15 minutes (record battu), où l’audience sera emportée dans un maelström d’anecdotes exotiques, tout à la fois savoureuses et pertinentes (espérons-le).

Direction Lomé, la capitale du Togo en Afrique de l’Ouest.

À Lomé, ils ont fait la rencontre d’Horacio, alors leader du TogoJUG, et depuis devenu un ami. Il leur proposait de faire un talk un samedi matin, dans un campus universitaire éloigné de la capitale. C’était à deux heures de taxi, et cela coûtait une journée de salaire local pour venir. Ils pensaient n’y trouver que quelques personnes : une soixantaine firent le déplacement ! On leur racontait alors que ce n’était pas étonnant : JCertif, la grosse conférence Java d’Afrique Centrale (leur Devoxx), accueillait des centaines de personnes faisant jusqu’à 3 jour de voyage pour y assister. Et traversaient parfois à pied l’imposant fleuve baignant le palais des congrès pour ne pas rater de conférence ! Une motivation qu’on aurait bien du mal à retrouver en France.

En France, Agnès et Cyril s’occupaient alors du LyonJUG. S’ils avaient organisé une session un samedi matin à Villeurbanne (la ville d’à-côté), ils n’y auraient probablement vu que 5 personnes maximum.

Sur Lyon, les communautés techniques sont fédérées par LyonTechHub, qui publie un calendrier de tous les meetups. Il y a un meetup chaque jour de la semaine, voir plusieurs. S’il est formidable de constater ce foisonnement des communautés, certaines peinent parfois à trouver leur public. Alors réjouissons-nous de cette richesse, là où d’autres n’ont droit qu’à très peu d’animations.

Agnès et Cyril étaient accueillis par une entreprise au Togo, où ils devaient former au Java de nouveaux embauchés. Ni l’entreprise, ni les élèves, n’étaient togolais : ils étaient tous de la Côte d’Ivoire. Mais l’entreprise les avait exfiltrés pour fuir la guerre civile sanglante qui ravageait le pays après la dernière élection présidentielle (pro-Gbagbo vs pro-Ouattara). Et une vraie guerre civile, avec des individus tués juste parce qu’ils étaient un peu enveloppés, comme le président sortant, qu’ils devaient donc nécessairement soutenir.

Ces élèves se retrouvaient ainsi dans un pays étranger, certes en sécurité, mais avec leur famille restée au pays. Autant dire qu’ils n’étaient pas pleinement sereins et concentrés pour suivre leur formation, jetant régulièrement un œil sur l’actualité de leur pays d’origine et prenant régulièrement des nouvelles de leurs proches.

En France, la plus violente des dernières guerres civiles en date a vu l’affrontement des partisans de l’appellation chocolatine, opposés à l’appellation pain au chocolat (qui est évidemment la bonne).

Encore une fois, réjouissons-nous des conditions de paix et de sérénité dans lesquelles nous avons la chance de pouvoir apprendre et travailler.

Leur copain Horacio leur expliquait aussi que les entreprises IT togolaises et africaines en général ne faisaient confiance qu’aux consultants blancs, et n’écoutaient pas les suggestions de leurs employés locaux. Elles préfèrent ainsi payer 2000€ par jour l’intervention d’un européen, alors que le SMIC mensuel n’est que de 50€ au Togo.

Certains occidentaux n’hésitent donc pas à s’expatrier, jouissant d’un pouvoir d’achat absolument considérable, avec une immense résidence, et 12 domestiques, de la cuisinière au chauffeur. Voilà un bel exemple de néo-colonialisme.

Même les startups africaines recrutent des blancs comme faire-valoir pour que leur proposition commerciale soit simplement écoutée. Leur copain Horacio, qui cherchait alors à créer son entreprise, leur a même demandé de jouer ce rôle pour lui. Malgré l’inconfortable culpabilité de ne pas aider leur ami, ils ont préféré refuser de participer à ce système.

En France, nous ne pouvons pas trop faire les malins : dans de nombreuses grosses entreprises, seuls certains consultants référencés ont leur mot à dire sur la stratégie ou l’architecture applicative, et les équipes de développeurs internes sont ignorées sur ces sujets importants. Plus le costume est cher, plus la voix est importante.

Après Lomé au Togo, nous nous envolons pour Kuala Lumpur en Malaisie (c’est rigolo c’est apparemment à la même latitude, traçant une ligne parfaitement parallèle à l’équateur). Bon, en vrai, ce n’est pas commme ça que le voyage s’est déroulé : entre ces deux destinations, Agnès et Cyril ont profité d’un long moment de détente en Thaïlande. Mais faute d’anecdote liée au développeur, ils n’en parleront pas.

Donc, Kuala Lumpur. À l’époque, ils ne connaissaient absolument rien de cette ville (Mission Impossible III n’était pas encore sorti), et n’avaient aucune image en tête. Et ce nom de Kuala Lumpur leur évoquait un exotisme absolu, genre temple d’Indiana Jones avec des singes dans la jungle.

Il s’est avéré que ce n’était pas tout à fait le cas.

Kuala Lumpur s’est révélée être une copie asiatique (et musulmane) de Londres, où les temples sont des tours de verre au service des dieux de la finance et du commerce.

Donnant une session au MalaysiaJUG, ils ont pu observé la richesse de l’université, et les conditions exceptionnelles auxquelles avaient droit les étudiants.

Bien loin de celles qu’ils avaient connues en France…

Voici l’INSA de Lyon, école d’ingénieur au top de leur région. Comme toute université française : murs décrépis, bancs cassés et moyens dérisoires.

Autre anecdote plus personnelle : Agnès et Cyril viennent de faire entrer leur plus grand fils Marius, 3 ans, à l’école maternelle. Alors qu’ils pensaient que Marius faisait ses premiers pas sur le long chemin serein de la vie, ils découvrent qu’ils seront plus de trente enfants entassés par classe, avec des peintures écaillées, des morceaux de plafond qui tombent, et un sol amianté (conseil de la mairie : “s’il ne frottent pas trop leurs pieds c’est sans danger”). Voici les moyens assignés à l’éducation publique en France. C’est assez pathétique, et peu rassurant sur l’avenir de la République.

Plus petit trajet de notre histoire : direction Jakarta, en Indonésie. Un véritable enfer urbain (plus de 25 millions de personnes en 2012), pollué par un trafic routier cauchemardesque.

Dans cet enfer, Agnès et Cyril ont rencontré deux jeunes femmes, Nety et Mila. Elles n’avaient pas 20 ans et menaient de front leurs études universitaires, une création d’entreprise, et quatre heures de transport quotidiennes. Régulièrement, elles prenaient leur scooter pour sillonner l’île de Java, dans des road trips pédagogiques où elles initiaient des jeunes au code.

Impressionnantes de motivation et d’énergie.

En France, les étudiants de 20 ans semblent moins préoccupés par leur avenir. Et consacrent en général leur temps libre à d’autres loisirs moins constructifs. N’est-ce pas Agnès ? (elle écumait alors les bars et les concerts).

Voici les élèves à qui ils donnaient des cours à l’Université de Jakarta. Et si vous regardez bien cette photo, vous y observerez une autre surprenante caractéristique de l’IT en Indonésie : une parité homme/femme exemplaire. Sans connaître les statistiques exactes, c’est bien ce qu’Agnès et Cyril ont constaté partout où ils sont allés.

Alors qu’en France, vous avez dû faire le même constat : c’est plutôt la bromance.

Cyril fait de la prestation informatique depuis 15 ans, et a dû travailler avec 150 personnes. Et probablement que 139 étaient des mâles trentenaires, blancs et hétéro. En gros, la seule développeuse qu’il a rencontrée, il lui a fait deux enfants…
C’est un peu exagéré, mais les développeuses qu’il a croisées doivent se compter sur les doigts d’une main (coucou Pierrette, coucou Daphné).

On a donc dans l’IT français un sacré problème de diversité. Et encore, le terme de diversité est mal choisi. “Diversité” sonne comme un luxe facultatif qui apporterait une petite touche d’exotisme charmant à l’équipe. Non, c’est juste un put*in de problème de représentativité : l’IT n’est pas à l’image de la France.

Voilà maintenant qu’on s’envole pour San Francisco, Californie, USA, capitale de l’informatique mondiale, siège des Google, Twitter, Facebook, Uber et AirBnb.

Agnès et Cyril y ont rencontré quelques stars qu’ils interviewaient pour un podcast (depuis abandonné) :

  • Romain Guy, un googler d’origine lyonnaise, qui a codé l’essentiel de l’UI de vos téléphones Android 
  • Pamela Fox, ancienne developer advocate de Google, alors chez Coursera, qu’ils ont fait venir à Mix-IT 
  • Malte Ubl, depuis devenu le tech lead de AMP, la technologie de Google pour rendre instantané le rendu des pages web sur mobile.

Ces gens travaillent dans un cadre merveilleux, pour des sociétés financièrement généreuses, et impactent des milliards de personnes. Pourtant, tout n’est pas idéal. C’était l’époque où les navettes Google (qui transportent leurs employés de San Francisco au siège de Mountain View à une heure de route) commençaient à se faire caillasser par la population qui leur reprochait la terrible gentrification de la ville.

Même avec une très bonne rémunération, Romain Guy a eu du mal à trouver une maison dans la Silicon Valley pour loger sa famille agrandie, il lui a fallu trois ans : quand une annonce paraît, des chinois débarquent dans l’heure qui suit avec des valises de liquide, contenant 500.000$ de plus que l’exorbitant prix demandé, et achètent sans visiter…

À Saint-Etienne, il n’y a peut-être pas Twitter ni Google, mais ça ne saurait tarder grâce à la French Tech. Non j’déconne. On n’est pas là pour troller sur la French Tech.

A Saint-Etienne, il n’y a peut-être pas Twitter ni Google, mais au moins l’immobilier n’est pas aussi tendu : moins de 1000€ le mètre carré. Quand Agnès et Cyril sont revenus de leur voyage sans aucune possession, et qu’ils prévoyaient la création de leur entreprise sans garantie de succès, et la procréation d’enfants dont ils ignoraient tout du coût de gestion, ils se sont alors installés à Saint-Etienne pour éviter d’ajouter la pression immobilière à leurs projets. L’aventure était alors financièrement plus sereine.

Direction Stockholm, en Suède. Ce n’était pas vraiment dans le cadre de leur tour du Monde, mais ils y sont allés récemment (en repérage pour peut-être s’y installer avec leurs enfants).

À Stockholm, Agnès et Cyril ont croisé un expatrié français depuis 8 ans (il travaille depuis chez Spotify, la boîte cool du coin). Il avait débarqué en Suède avec un enfant en très bas âge. Lors de son premier jour de travail, son manager passe près de son bureau à 17H, et lui demande ce qu’il est en train de faire.

— Et bien je travaille.
— Je croyais que tu avais un bébé à la maison.
— Heu oui, c’est ça.
— Et bien tu ne devrais pas être là. Rentre vite t’en occuper.

En Suède, on ne rigole pas avec la parité. Le partage des tâches domestiques et familiales n’est pas seulement conseillé, c’est surtout très mal vu que le père ne s’occupe pas suffisamment de ses enfants. Au point de se faire engueuler par son manager si un jeune papa reste après 17H au travail.

En France, et dans la plupart des pays occidentaux semble-t-il, ce n’est pas vraiment cet esprit.

Ce dessin (qui a été piqué à un inconnu sur Internet) représente assez bien l’état d’esprit traditionnel :

  • Tu peux avoir de l’argent et du temps libre, mais il ne faut pas avoir d’enfant, ou ne pas s’en occuper.
  • Tu peux avoir de l’argent et des enfants, mais tu n’auras alors pas de temps libre.
  • Tu peux avoir du temps et des enfants, mais tu n’auras probablement pas trop d’argent, avec un temps partiel.

OK, et après ?

Montrons combien les présentateurs ont fait preuve d’une clairvoyance éclairée pour forger leur destin.

S’ils avaient flippé de partir en long voyage sans salaire, Agnès et Cyril ont finalement réalisé que c’était très facile sans enfants. Alors, profitez-en tant qu’il est encore temps pour vous !

Le tour du Monde terminé, la question était maintenant de savoir quelles leçons ils allaient en tirer pour leur retour à la réalité professionnelle.

Agnès et Cyril ne voulaient plus être salariés, et encore moins en SSII, où on leur expliquait que le développement était une tâche à faible valeur ajoutée, et qu’il fallait penser à faire un vrai métier rentable : remplir des chiffres dans des cases Excel. :’(

Une des premières phrases du droit du travail indique qu’il s’applique uniquement s’il y a un rapport de subordination entre l’employé et l’employeur. Ainsi, le travail, après lequel court toute la société depuis des décennies (pour réduire le chômage et retrouver le plein-emploi), est fondamentalement une relation de subordination. Un employeur fera du chantage à l’employé : tu n’auras ton salaire que si tu fais cette tâche ingrate. Agnès et Cyril ne voulaient plus de cette subordination, et voulaient rester libres de choisir leur travail, et pour qui ils travaillaient.

Les entreprises libérées sont d’ailleurs à la mode. Mais aussi libérée que soit une entreprise, la relation de subordination fait qu’aucun salarié non actionnaire n’a un droit de regard sur le destin de l’entreprise. Un exemple récent est celui d’Octo. Si Agnès et Cyril ne connaissaient pas vraiment Octo, elle semblait une SSII plutôt cool, avec des employés pointus et reconnus. Mais du jour au lendemain, elle fut rachetée par Accenture. Reste à voir comment cela évoluera, mais il est fortement probabable que l’ambiance change du tout au tout, et que la stratégie d’Octo ne soit plus vraiment la même. Ainsi, ce n’est pas parce que tu adhères aux valeurs de ton entreprise que tu seras maître de son destin.

Agnès et Cyril ne veulent pas non plus dire que travailler dans une grosse société est forcément un échec. Mais eux-mêmes avaient du mal à imaginer des alternatives satisfaisantes. Alors ils veulent aussi présenter celle à laquelle ils sont arrivés.

Ils cherchaient donc une alternative au salariat. L’évidence est de se lancer en freelance. Mais cela ne leur convenait pas vraiment. Ils voulaient construire un projet collectif. Tout en sachant qu’ils n’étaient que des développeurs sans aucune autre compétence, perdus vers Saint-Etienne, et qu’ils ne voulaient ni locaux, ni managers, ni commerciaux.

Avec deux autres développeurs (bisous Cédric, bisous JB), ils se sont alors lancés dans une société coopérative : un homme = une voix, tous égaux, tous actionnaires. La transparence était aussi une valeur qui leur tenait à cœur. Malgré des écarts d’âge prononcés, ils ont décidé d’adopté un modèle de salaire encore plus simple que la fameuse grille de Buffer : tous le même salaire (2500€ net, et ils se partagent le reste à la fin de l’année, ce qui représenta quand même un bonus de 18 000€ nets pour chaque ninja l’année dernière). La grille de salaire de Ninja Squad est d’ailleurs aussi publique :)

Avec le recul, quatre ans après, est-ce que cela a fonctionné ?

Déjà, ils cherchaient une alternative au salariat. Le problème n’était pas tant le salariat que la relation de subordination induite. Ainsi, dans Ninja Squad, ils ont volontairement choisis d’être salariés, car leur statut de SAS le permettait, et ils voulaient par conviction participer au système social par répartition.

Au début, les commerciaux de leurs précédentes SSIIs ricanaient : “vous allez vous planter en beauté”.
Et certains leur prophétisaient une déconvenue : “avec un nom comme Ninja Squad, vous allez vraiment passer pour des guignols”. Avec le recul, bien qu’ils étaient loin de l’avoir calculé, le nom et l’esprit débridé assurent un excellent filtre. Si les grosses entreprises scélérosées (banque, assurance, grande distribution) ne veulent pas travailler avec ces guignols, c’est finalement tant mieux : ils ne veulent pas non plus travailler pour eux. Les quelques clients qui font la démarche de venir les voir sont déjà probablement des gens avec qui ils auront des affinités.

Le plus grand luxe d’avoir sa propre société c’est aussi de choisir ses clients, et refuser de travailler pour ceux dont on ne partage pas l’éthique. Après avoir éprouvé de l’empathie pour certains parcours de vie autour du monde, et après avoir fait des enfants, il y a certaines activités qu’on a encore moins envie d’encourager.

Quand on travaille en SSII, la SSII d’à côté est une concurrente, à qui il faut plutôt faire des croche-pieds que des bisous. Sans avoir d’explication formelle, il s’avère que dans leur petit monde des sociétés coopératives, l’entre-aide est plutôt de mise. En 2013, avec leurs amis de Scopyleft et de Lateral Thoughts, ils avaient animé un BoF à Devoxx sur les NoSSII (NoSSII : Not Only SSII). Depuis, ils se retrouvent sur un Slack. Et l’échange de tuyaux, de bons plans, et de missions, est toujours d’actualité.

Être libre dans sa société, c’est aussi maîtriser complètement son temps de travail, et définir l’équilibre avec la vie personnelle qui convient à chacun. Google est célèbre pour ses 20% de temps libre, et Ninja Squad fait vraiment pareil : ils ne facturent que 4 jours par semaine, et se gardent le vendredi pour travailler sur ce qu’ils veulent. Ce n’est pas toujours très sexy (il y a parfois de l’administratif, notamment la gestion des formations avec nos chers dinosaures du FAFIEC), mais au moins ont-ils du temps réservé pour cela.

Un autre avantage peut-être anecdotique d’avoir sa propre société est que cela résout un bête problème d’image. Quand vous avez votre entreprise, unipersonnelle ou non, il faut en assurer la promotion. Si les clients ne savent pas que vous existez, ils ne viendront pas vers vous. Ainsi, si vous êtes freelance, c’est en votre nom propre qu’il vous faut faire du marketing : “Oh la la qu’est-ce que je suis fort, j’ai encore fait ce projet, je parle encore à cette conférence”. Si vous avez une vraie société, avec son image, il suffit alors d’en dire tout le bien que vous voulez : votre humilité est sauve, vous ne parlez pas de vous. Vous avez transformé le personal branling en corporate branding !

Comment faire alors pour se lancer ? Est-ce compliqué ?

Et bien non ! Agnès, Cyril, et leurs collègues ninja Cédric et JB n’y connaissaient rien. Il leur a suffit de payer 1500€ un cabinet prestataire pour se faire interviewer sur la teneur des statuts qui leur convenaient, et assurer la création de la société.

La vraie difficulté, la plus importante, est de trouver les bonnes personnes qui feront les bons associés. Les gens qui resteront vos copains quand le sujet de l’argent arrivera sur la table. Il faut donc trouver les gens avec qui vous partagez vraiment les bonnes valeurs, et qui sont aussi vos complémentaires. Facile à dire, bien plus difficile à trouver.

Dans Ninja Squad, ils ont eu beaucoup de chance. Agnès et Cyril avaient rencontré Cédric dans l’associatif, et avaient travaillé avec lui dans ce cadre (LyonJUG, Mix-IT). Comme quoi, participer à la vie des communautés techniques est important ;). Ils avaient travaillé avec JB dans le cadre professionnel. Mais JB et Cédric ne se connaissaient pas. Ce dernier dit d’ailleurs : “ça n’avait aucun sens de monter une boîte avec un mec avec qui j’avais juste bu une bière en 5 minutes”. Mais ils ont finalement eu la chance incroyable d’être à la fois complémentaires et compatibles.

Un dernier point important avant de se lancer : trouver un bon comptable, parce vous allez passer beaucoup de temps avec lui. Alors mieux vaut trouver quelqu’un avec qui vous vous entendez bien, et qui vous mâchera le travail si la comptabilité n’est pas votre passion… Mais vous pourrez toujours changer par la suite.

Avec tout ça, dans le monde du développement où il y a tellement de travail insatisfait, il n’y a aucune raison que cela ne fonctionne pas, si vous travaillez correctement. Et avec peu de charges (pas de locaux, pas de commerciaux, pas de managers à payer), il est probable que vous viviez très bien.

Une conclusion subtile et inspirante

Voici, enfin, la conclusion, où apparaît soudainement, après un moment de flou, combien cette présentation est finalement bien construite et inspirante (normalement).

Donc, pour reboucler avec l’introduction, pourquoi est-on heureux ?

Agnès et Cyril sont tombés sur un TEDx de Jérome Bonaldi sur le bonheur. Il présentait différentes études statistiques qui ont permis de discriminer les facteurs influants sur le bonheur. Et le facteur le plus influent n’est pas celui qu’on pourrait croire.

Est-ce que les enfants et la famille contribuent au bonheur comme on le croit instinctivement ? Pas du tout !

On peut être parfaitement heureux ou malheureux avec ou sans enfant.

Est-ce que la religion aide ? Non plus !

Après, il y a les facteurs évidents, comme la santé. On sera évidemment plus heureux si on est en bonne santé.

Le cadre de vie joue aussi. On sera plus heureux dans un joli endroit qu’en vivant au bord d’une décharge.

Le niveau de vie contribue aussi : on sera évidemment plus heureux si on a les moyens de manger ce qui nous plaît, et de s’offrir quelques loisirs.

Mais enfin, le facteur le plus universel qui contribue le plus au bonheur est le sentiment d’avoir le contrôle de sa vie (empowerment, comme disent les américains).

Quelqu’un qui pense que sa vie est la faute du gouvernement ou de ce salaud de patron sera fondamentalement moins heureux que celui qui pense qu’il est maître de son destin. Il n’est même pas question de pouvoir vraiment, factuellement, changer sa vie, il est juste question de le penser !

Alors, vous qui êtes développeurs, dans ce monde où vous êtes tant recherchés, il est temps de prendre en main votre destin pour construire votre bonheur.

Les feedbacks

Un article suite à une interview paru dans le journal régional Paris-Normandie : Codeurs en Seine à Rouen : le métier de développeur web a de beaux jours devant lui.

Les tweets :


Cyril Lacôte


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Angular is moving fast, and we already have a minor release: 2.2! This contains the changes from Angular 2.1.x releases and Angular 2.2.0 various betas and RCs.

Upgrade

The most significant work has been done on the Ahead of Time compilation, and especially on the ngUpgrade support. That means you’ll be able to optimize your application going under migration. The router has received some love for those who want to migrate their ng1 apps to ng2: it’s now possible to use the Angular Router with the ngUpgrade!

Forms

One of the new features of this release is a modest contribution from me :) When you were using a template-driven form, the syntax was a bit painful to access some methods like hasError or getError:

<label>Username</label>
<input name="username" ngModel required #username="ngModel">
<div *ngIf="username.control.hasError('required')">Username is required</div>

Now with Angular 2.2+ we can directly access these methods on the local variable, without the need of accessing the control property:

<label>Username</label>
<input name="username" ngModel required #username="ngModel">
<div *ngIf="username.hasError('required')">Username is required</div>

Another feature introduced adds a ng-pending class on fields under pending async validations. In Angular, you can add validators on every field or group of fields. Such validators can be synchronous or asynchronous (for example asking the server if the chosen username is available). When an asynchronous validation is pending (the HTTP request is not completed yet for example), the ng-pending class is added to the field. You can use it to add some style or a spinner for example.

Router

The Router Module offers a very handy directive called RouterLinkActive, allowing us to add a specific class if a link is active. This directive is now exported, and can be used in our templates via a local variable:

<a routerLink="/races/1" routerLinkActive #route="routerLinkActive">
 Race 1 {{ route.isActive ? '(here)' : ''}}
</a>

That’s all for this small release. Check out our ebook and Pro Pack if you want to learn more about Angular!


Cédric Exbrayat


Ninja Squad books


Become a ninja with Angular
Cover of ebook Become a ninja with Angular

Pay what you want and support charity!


Devenez un Ninja avec AngularJS
Couverture du livre Devenez un Ninja avec AngularJS

Passez de débutant à ninja en AngularJS 1.4 avec un ebook à prix libre et pour une bonne cause !


Ninja Squad books



Formations

Angular

22-24 aout à Lyon
12-14 sept. à Paris
14-16 nov. à Lyon
12-14 dec. à Paris


Suivez-nous


Posts plus anciens