ngParis #17

Meetup angular, organisé par le bon coin. J'avais un peu arreté d'aller aux meetups angular (trop peu de contenu), mais là le programme annonçait un REX sur comment mélanger React et Angular, du coup, j'étais curieux.

Le bon coin, derrière leurs airs de sites des années 80 mis en ligne dans un garage possède en fait de formidables bureaux en plein Paris. Le premier site date de 2006 et est Norvégien, puis la France a été la première filiale en 2007 avant que le système ne s'implante dans plus de 35 pays.

La technologie sous-jacente est un moteur custom codé en C nommé blocket et réutilisé par toutes les filliales (qui peuvent donc faire des mises à jour de leur moteur facilement) avec quelques petites différences culturelles pour chaque pays.

D'un seul dev au départ, ils sont maintenant 250 dans la boite avec un objectif à 350 pour la fin de l'année. Le bon coin, c'est des chiffres de consultations extraordinaires. 90 millions de pages vues par mois, essentiellement des résultats de recherche, donc sans possibilité de mise en cache.

Ils parviennent quand même à un startRender moyen de 0.7s. 6e site le plus visité de France, 700.000 nouvelles annonces chaque jour, 2 datacenters de 400 serveurs. En terme de charge, c'est du très lourd, leur conso normale correspondant aux pics de charge de ce qu'on connait habituellement.

Au dela du cœur de l'appli, il y a toutes les applications de gestion (modération, monitoring, etc) qui sont développés dans des tas de langages différents. Il y en a pour tous les gouts : PostgreSQL, Python, Ruby, Go, Shell, PHP, des apps natives, du big data, de l'hadoop, du capybara.

Ah, et la question qu'on se pose tous. Non, le compte @TopBonCoin n'est pas officiel, le bon coin ne faisant actuellement aucune publicité ou community management.

Bon, assez parlé de l'hôte, place aux talks.

React et Angular

Julien Bouquillon, alias @revolunet viens nous faire un retour d'expérience sur l'intégration de React dans Angular. Il a entendu beaucoup de bien de React et a voulu voir si ça se plugguait facilement.

Ça fait deux ans qu'il fait de l'Angular, sur du mobile et sur du desktop et le problème récurrent pour lui, ce sont les perfs. Essentiellement sur mobile d'ailleurs. Les problèmes de perf sont les mêmes sur les deux plateformes, mais les desktop étant plus puissants, il faut vraiment de grosses apps pour ressentir les ralentissement.

Vu que React mets en avant sa rapidité, il a décidé de troquer les directives d'Angular par des composants React pour voir la différence. Pour lui le reste d'Angular est très bon. On gagne en productivité et en réusabilité, le framework fournit plein de choses de base et tout ça se teste facilement. Globalement, super framework... sauf pour les perfs.

What's wrong with Angular ?

Parce que le gros problème d'Angular se trouve dans le data-binding, bête et méchant. C'est le coté magique qui nous attire au début dans le framework, mais c'est aussi le goulot de performances. Quand on inclue une variable dans un template pour qu'elle soit bindée, l'algo simpliste d'Angular va simplement ré-évaluer chaque variable à chaque événement de l'utilisateur. C'est à dire au clic, au scroll, au touch, au keypress. Voire même sur des events qui ne viennent pas du user, comme le retour d'une requete HTTP.

Et ce, même si les éléments en questions sont en dehors du viewport, ou qu'ils n'ont aucun rapport avec l'élément actuellement modifié. Bête et méchant on vous dit.

Bon, sur une appli desktop, on voit pas trop le problème, ça va super vite. Mais sur mobile, on peut commencer à percevoir la lenteur, voir à la subir. À chaque interaction, la totalité du DOM est réevalué, c'est pas rien. C'est vraiment du dirty checking.

Si on veut fournir un expérience smooth, il nous faut viser du 60 fps, ce qui corresponds à 16ms pour un refresh. 16ms pour un refresh de tout le DOM, c'est pas énorme.

Malheureusement, Angular ne nous donne pas beaucoup de points d'actions pour pouvoir influencer ou améliorer ce rendering, le processus fait plus ou moins partie intégrante du core du méchanisme.

La version 1.3 a fait de grosses améliorations à ce sujet, d'au moins 50% de gain. Elle introduit aussi le principe des bind-once, et des filters stateful, qui peuvent n'être executés qu'une seule fois pour chaque valeur passée. On peut aussi éviter de mettre des méthodes à évaluer dans les templates mais simplement des variables, utiliser la syntax track by des ng-repeat et toujours essayer de mettre ses event handler sur les éléments les plus hauts.

Malheureusement, il reste le cas des keypress. Si j'ai un input, la totalité de mon DOM est réévalué pour chaque touche que va taper mon utilisateur.

Et React ?

React de son coté fonctionne avec un système intermédiaire entre ses data et le DOM, il y intercale un concept qui lui est propre : le virtual DOM. Les modifications de data influent directement sur le vDOM (qui n'est pas rendu directement), et seulement le diff entre le DOM actuel et le vDOM sont reportés dans le DOM. Ça marche très bien, et du coup seul ce qui a changé est modifié.

React intègre aussi par défaut un système d'event delegation intelligent. Plutôt que d'ajouter des handler sur plusieurs éléments, il ajoute un handler général sur la page et renvoie l'event au bon élément cliqué. On arrete comme ça de dupliquer les handlers.

Et surtout, React est explicite. Plus de magie. Chaque composant possède sa méthode render qui va retourner du HTML. On peut comme ça tester unitairement le rendu, mais surtout chaque composant est isolé et ses données ne fuitent plus vers l'extérieur. Seul le contenu du composant est modifié, sans que cela n'induise un rechargement de la totalité du DOM de la page.

Sans compter que React s'intègre parfaitement dans l'écosystem npm et browserify.

Benchmarks

Il nous a fait une démo d'un même composant codé une fois en Angular et une fois en React pour voir la différence de perfs. C'était un tableau de 100 éléments et de 5-6 colonnes. En cochant la première colonne de chaque ligne, on pouvait "barrer" l'élément.

En React comme en Angular, le chargement initial du composant prends environ autant de temps. Pas de gain à attendre de ce coté là. Par contre, si on coche une ligne du tableau Angular, les 1000 éléments sont ré-évalués alors que si on coche celle de React, seule la ligne cliquée est modifiée.

Là où c'est pire, c'est qu'en ajoutant un champ d'input au dessus du tableau Angular, chaque keypress ré-évaluait la totalité du tableau. Et pire que tout, on a ajouté un bouton qui ne faisait rien (pas de ng-click, rien). Et bien cliquer dessus rechargeait encore tout le DOM Angular.

Je crois que toute la beauté de React peut se résumer dans la phrase suivante de Julien :

En React, un bouton qui ne fait rien, ne fait rien.

Bon, et mon React il va rentrer dans mon Angular ?

Oui. Il est tout à fait possible de mettre un composant React au beau milieu d'une appli Angular. Il va vivre sa vie en isolation, sans générer de reflow Angular, et sans se modifier quand Angular se modifie.

Par contre si on veut l'introduire dans notre cycle Angular normal, il faut le wrapper lui-même dans une directive. Par contre, à partir du code de la directive, on entre dans un mode explicit > implicit où on va définir des callbacks à notre composant qu'il sera chargé d'appeller quand il voudra communiquer son état vers l'extérieur, et on ajoutera aussi des méthodes au composant pour pouvoir lui passer de nouvelles data depuis Angular.

C'est un peu plus de plomberie, mais on est alors certain qu'il ne se mettra pas à jour sans raison, et il pourra agir en isolation complète.

Il existe un projet, ngReact qui défini justement ce type de directive, mais ils vont trop loin et ajoutent des watchers automatiques pour passer les infos d'Angular vers React et vice-versa, ce qui nous fait revenir au problème de dirty checking du départ.

Conclusion

React peut s'intégrer correctement dans Angular et vivre sa vie correctement en profitant de manière isolée de ses avantages. La plomberie reste un peu manuelle, mais permet une belle isolation. Néanmoins, la philosophie de l'un et de l'autre étant tellement différentes, je ne suis pas sur qu'on tire vraiment le meilleur des deux mondes.

KillrChat

Duy Hai Doan, tech évangéliste chez Datastax nous a parlé d'un pet project de chat à base d'Angular, Spring Boot et Cassandra. C'est cool, il est payé pour faire des meetups et présenter Cassandra, du coup avec trois technos cools comme ça il peut réutiliser le même talk :)

L'idée de faire une appli de chat vient de sa frustration de faire des ateliers pour faire découvrir Cassandra et que les élèves ne repartent qu'avec un énième "Hello World" qui ne sert pas à grand chose. Là, il a une vraie appli qui touche à toutes les couches.

Et surtout, elle peut profiter des possibilités de scaling de Cassandra. En gros, quand le nombre de user se mets à grossir, il suffit d'augmenter le nombre de nœuds sur lesquels les données sont stockées dans Cassandra. Cassandra s'occupe de répartir les nouvelles données uniformément sur chaque nœud de manière à ce qu'aucun ne soit particulièrement submergé. Pour plus d'infos sur le fonctionne de Cassandra, je vous invite à relire mon compte-rendu du meetup nodejs paris.

Le chat qu'il a développé communique avec le back-end Spring Boot en websocket, avec SockJS. Entre les deux, il suffit de mettre un broker qui sait scaler (RabbitMQ, ZeroMQ, Kafka) qui implémente un simple système de pub/sub et front et back peuvent communiquer sans soucis, même avec une forte charge.

Et Angular dans tout ça ?

Duy Hai vient surtout du monde Java, le front c'est pas forcément son domaine. Mais il a kiffé Angular, il s'y est bien retrouvé. Il a aussi apprécié le fait qu'il y ait des outils pour se plugguer facilement avec Bootstrap (car comme il le dit lui-même, si on lui laisse le design d'un site ça sera horrible, avec bootstrap au moins c'est pas trop moche).

Il a quand même très rapidement implémenté des tas de bonnes pratiques en Angular (je ne sais pas si ce sont des bonnes pratiques issues de Java ou non). Par exemple, toute sa logique est distribuéed dans des services stateless, ses controllers se chargeant simplement d'un rôle de passe-plat.

Par contre, comme beaucoup, il s'est fait avoir par les $resources. Déjà, selon qu'on utilise les ressources avec des méthodes d'instances ou des méthodes de classe, ce n'est pas la même type d'objet qui est retourné et le chaining des promises en devient d'autant plus complexe (sans parler des promises angular qui ont leurs propres quirks).

Ce qu'il regrette dans Angular c'est qu'il faille une bonne connaissance de Javascript pour comprendre réellement ce qu'il se passe sous le capot. Heureusement pour lui, il a découvert angular-from-scratch qui se propose de recoder les mécaniques principales d'Angular depuis rien pour bien assimiler petit à petit chacun des concepts.

Globalement une présentation assez chouette, un REX avec des technos sympas.

Typescript

Pour finir, Paul Souche, de Sfeir nous parle de Typescript.

Bon, je vais la faire assez vite pour le coup. Typescript est une surcouche à Javascript, un peu comme Coffeescript, qui compile en Javascript. Le truc qu'apporte Typescript, c'est un typage fort des variables.

On peut désormais définir le type de chacun de nos arguments de fonctions et définir des interfaces de classe. Et si jamais le compilateur s'aperçoit qu'on essaie de faire rentrer des ronds dans des carrés, il nous balance une exception et il compile pas.

On peut aussi définir "facilement" des variables privées et publiques et même génerer automatiquement des getters et des setters. Ouais, ouais, comme un vrai javaiste.

Bon, à part ça y a des linters et ça génère des sourcemaps.

J'ai vraiment beaucoup de mal à voir l'intéret du truc, mais j'imagine que ça va encore plus plaire aux javaistes qui se mettent au front.

Buffet

Et comme souvent, le buffet qui suit les talks est toujours l'occasion de discuter et de rencontrer des gens très intéressants. Hésitez pas à venir taper la discut' si vous êtes dans un meetup la prochaine fois.


Tags : #ngparis

Want to add something ? Feel free to get in touch on Twitter : @pixelastic