Lors de mes premiers jours à Octo, j'ai eu la chance de me voir offrir une formation HumanCoders. JVE avait en effet gagné cette formation en retweetant une annonce des HumanCoders et ne pouvant pas y aller, il m'avait filé sa place.
Débutant en Rails et n'ayant jamais fait de tests, c'est exactement ce qu'il me fallait et ce que je voulais apprendre. La formation a donc eu lieu sur deux jours, dans un sympathique petit appart loué sur AirBnB à coté de République.
Nous étions trois élèves en tout pour un formateur (Jean-Michel Garnier) et Matthieu Segret qui restait dans un coin pour suivre aussi la formation.
Jean-Michel fait normalement cette formation sur une journée, du coup en l'étendant sur deux on avait un peu plus le temps de poser quelques questions et de tester plus profondément certaines parties. La formation était dédiée à des gens qui connaissent bien Rails mais qui n'ont jamais posés de tests, j'étais un peu plus largué que les deux autres, mais ayant déjà un background de cakePHP, je n'étais pas trop perdu dans les concepts.
Types de tests
On a déjà vu les différents types de tests et les noms qui leur sont donnés, pour s'y repérer un peu.
Tests unitaires, ou TU, où on va tester unitairement une classe, en l'isolant complètement de ses dépendances.
Tests d'intégration, où on va tester une classe et ses dépendances
Tests d'Acceptance, où on va tester un scénario utilisateur complet, avec toute la stack depuis le browser jusque la base de donnée.
Petit rappel sur les qualités d'un bon test: lisible, petit, indépendant, sans copié-collé et rapide. Tout ça permet de substituer les tests à la documentations, pouvoir les lancer dans le désordre pour le même résultat, avoir un feedback rapide et pouvoir en ajouter facilement.
On nous présente aussi rapidement le principe du TDD et des baby steps. Red, Green, Refactor. Mais on nous prévient que c'est un peu le Graal des tests et qu'avant d'en arriver là il faut déjà bien comprendre comment s'écrivent des tests. Mais qu'une fois qu'on y arrive, c'est bonheur.
Rspec
Rspec est le framework de TU de Rails. Il peut être utilisé à part aussi sur d'autres projets, mais il s'avère que c'est celui utilisé par Rails. Il y a plein de super magie made in Ruby dans sa syntaxe qui permettent d'écrire des tests qui soient très lisible. Son API a pas mal changée par le passé et évolue encore, mais à l'heure où j'écris ses lignes (2015, soit 2 ans après avoir fait la formation), l'API de la v3 devrait être stable.
Un test Rspec, ça ressemble à ça
describe"Class"doit"has feature"doendend
describe et it permettent de découper les tests en blocks. describe est utiliser comme wrapper pour grouper plusieurs tests ensemble. On groupe généralement par classe, et/ou par méthode selon la complexité des tests. Les describe peuvent s'imbriquer sans problème.
Les it représentent nos tests. À noter qu'on peut utiliser fdescribe et fit pour focus sur un seul describe ou un seul it et donc n'exécuter que celui-ci dans la suite de tests.
Il existe une convention partagée dans le nommage des variables dans les tests. On nomme en général expected la valeur qu'on attends et actual la valeur qu'on génère. Et on vérifie bien souvent que actual est égal à expected.
À noter que eq, eql et equal ont des comportements différents. Il n'y a rien là de spécifique à Rspec, c'est simplement du Ruby, mais un cas un peu particulier.
a.should eq(b) est identique à a.should == b. On teste si la valeur est identique, mais a et b peuvent avoir des types différents.
a.should eql(b) teste que la valeur et le type soient identiques
a.should equal(b) quand à lui vérifie que a et b référencent carrément le même objet.
Rspec expose une syntaxe très proche de l'anglais, à base de should et should_not, ce qui rends les tests très facile à lire et donc très facile à comprendre. En pratique c'est plus facile à lire qu'à écrire car on ne sait jamais trop où placer les _ au début (should_not raise_error et pas should_not_raise error). Il faut un peu de compréhension des rouages internes pour deviner la séparation.
Tips Rspec
Jean-Michel nous a donné quelques tips appris à force de travailler avec Rspec.
Il est possible de définir un subject de nos tests, qui deviendra le sujet par défaut des comparaisons.
Il nous conseille aussi d'utiliser le matcher match_array plutôt que include car son output donne plus d'informations sur les différences en cas d'échec (quelles clés sont communes, lesquelles sont différentes).
let permet de définir une variable dont l'initialisation ne sera exécutée que la première fois que la variable sera utilisée, et qui retournera toujours la même valeur pour un même block. On l'a rapidement abordé théoriquement dans la formation, mais on ne l'a pas utilisé ensuite en pratique dans la formation.
Les callbacks before(:each), before(:all), after(:each) et after(:all) permettent de simplifier les tests en ajoutant un peu de boilerplate avant et après chaque test.
En passant --order à rspec on le force à exécuter les tests de manière aléatoire, nous assurant donc qu'ils soient indépendants. De même, ajouter --backtrace permet d'avoir plus de contexte sur là où les tests fails, ce qui est bien utile pour le debug.
Des gems comme timecop ou delorean permettent de joueur finement avec la notion de temps et de mocker des dates.
WTF Rspec ‽
On a eu un petit moment WTF dans la formation quand la syntaxe un peu magique s'est retournée contre nous.
Le code suivant marchait parfaitement, failant quand l'erreur n'était pas du bon type.
Le problème semble venir de l'absence de parenthèses autour du raise_error qui gène RSpec dans la compréhension du contexte. Pour info, voici le code corrigé qui passe comme prévu :
Du coup, ça nous a bien montré l'intérêt de toujours commencer par un test qui foire, pour être sur que nos tests testent bien les bonnes choses et pas du vide. Avoir des tests qui passent toujours est bien pire que de ne pas avoir de tests du tout.
Outils
Les tests RSpec d'une appli Rails sont quand même assez lents car ils doivent instancier la totalité de l'appli à chaque fois. Et la force des tests c'est quand même d'avoir un feedback rapide. Et si on doit attendre 20s avant d'avoir le résultat, c'est beaucoup trop long.
Pour contrer ça il existe des outils comme Spork, Spring ou Zeus. Après avoir utilisé longuement les trois, Jean-Michel nous a conseillé Zeus. Il suffit de lancer Zeus dans un terminal, puis dans un autre zeus rspec /path/to/file.rb pour lancer des tests qui utilisent la même version de l'appli gardée en mémoire par zeus.
Sur ma machine, mes tests qui s'exécutaient en 7s sont passés à 0.2s. Impressionnant. Attention toutefois, zeus n'est pas bulletproof et nécessite parfois d'être killé et relancé car il ne parvient pas régénérer toutes les modifications de code (notamment l'update du Gemfile, les fichiers d'i18n, etc). Idem, il faut un workaround non expliqué ici pour réussir à le faire fonctionner avec le mode random de rspec.
La question a été posée de la redondance de code entre les règles de validation du modèle qu'on pose en Rails et les tests de validation qui vont avec. Est-ce utilise d'avoir cette info deux fois, et si non, alors lequel garder ?
Jean-Michel nous a suggéré d'utiliser la gem schema_validation qui va générer automatiquement les règles de validation en fonction du schema de la base de donnée. Du coup, c'est la DB qui est la source du schéma.
Par défaut, RSpec efface la DB de test après les tests, ce qui est assez embêtant pour débugguer et traquer les bugs. Pour contrer cela, il est possible de définir use_transactional_fixture et d'ajouter un clean de la DB avant tous les tests, puis entre chaque test, mais pas après tous, pour pouvoir étudier la DB à loisir. Il est aussi possible de définir quelles tables vider et lesquelles garder (inutile de supprimer toute l'immense table d'i18n à chaque test).
Il est aussi possible d'utiliser la gem rspec-set qui permet de définir certains objets en DB qui reviendront toujours au même état entre chaque tests, même après des update et des delete.
On a aussi été mis en garde de ne pas faire des tests sur la DB avec des volumes très différents de ceux de production. Des problèmes peuvent survenir si les données sont tellement importantes que la DB devient un bottleneck. Pour ça, il est intéressant de posséder un dump d'une DB de prod (anonymisé bien sur) pour faire des tests sur des données réelles.
Tester une API
RSpec permet aussi de tester une API, mais ne fait pas réellement appel à la couche réseau. À la place, il se pluggue sur les routes qui ont été définies dans Rails. L'avantage c'est que c'est très rapide, l'inconvénient c'est qu'on ne teste pas réellement en conditions réelles.
Au passage, si son API est bien définie, il est possible de générer automatiquement sa documentation avec la gem rspecapidocumentation qui créé alors automatiquement les tests avec les endpoints, les arguments attendus et quelques exemples de réponse. Ces tests peuvent très facilement servir de documentation.
Tests Full Stack
Les tests d'Acceptance, ou full stack, vont tester l'ensemble de l'application, depuis le point de vue de l'utilisateur. C'est à dire qu'on va tester le navigateur, la couche réseau, les appels au back-end et les mises à jour en base de données.
Ces tests sont très lent à jouer, et très long à écrire. Ils sont aussi sujets à beaucoup d'erreurs et sont très fragiles (la moindre modification à n'importe quel étage de la chaine peut faire foirer le test).
Pour les faire, on utilise Selenium, qui est un driver pour piloter un navigateur. On peut aussi utiliser un service en SaaS comme Saucelabs pour le faire à notre place.
Si on veut le faire nous-mêmes, c'est Capybara qu'on utilise. Celui-ci dispose de méthodes simples pour simuler un comportement utilisateur comme visit, fill_in ou click_on. On peut alors tester des scénarios entiers de remplissage de formulaire et tester qu'une phrase spécifique est alors bien affichée à l'écran. On peut aller plus loin et tester que le record est bien arrivé dans la base de données, mais on teste plutôt généralement que la page qui affiche les records comprends bien celui que l'on vient de rentrer.
Le debug de tests Capybara se fait encore pas mal manuellement à l'aide de la méthode save_and_open_page qui ouvre alors la page en cours dans un navigateur pour que l'on puisse inspecter ce qu'il se passe.
Au final, ce sont des tests très fragiles car très dépendants du markup et du wording. Il n'est pas certain que le temps investi sur ces tests soit rentabilisé, il vaut mieux donc le garder pour les chemins critiques.
Doubles, Stubs, Mocks, etc
On a gardé le meilleur pour la fin. On a eu le droit à une explication sur la différence entre un stub et un mock.
En gros un double est un terme général pour parler des stubs et des mocks. Un double est comme une doublure au cinéma. On dirait que c'est le vrai objet, mais en fait c'est un faux. Il ne fait rien d'intéressant, à part répondre aux méthodes qu'on appelle sur lui.
On peut en créer facilement avec Rspec comme ceci double('name', method1: response1, method2: response2).
On peut aussi créer un stub depuis un objet existant en court-circuitant une des ses méthodes et en hard codant ce qu'il doit retourner. Cela permet par exemple d'éviter des appels couteux en temps vers une API.
Attention toutefois, il est tellement facile de créer des stubs qu'il peut être tentant de stubber un module complet et ses dépendances. Trop de stubs dans un test est un gros code smell. Cela signifie que le code est trop couplé. Il vaut mieux le séparer en plusieurs entités qui sont testables individuellement.
Les mocks de leur coté sont des stubs améliorés. On court-circuite toujours l'appel initial à la méthode pour retourner une réponse sur mesure, mais en plus on peut tester le nombre de fois qu'une méthode a été appelée et avec quels arguments.
On a aussi abordé rapidement les fake objects et les spy objects, mais bien trop rapidement pour que je puisse me souvenir de leur utilité.
Conclusion
J'ai appris beaucoup en deux jours de formation, ça m'a permis d'avoir une vision générale de ce que sont les tests exactement. Il y a beaucoup de nouvelle terminologie et beaucoup d'outils à utiliser.
Je ne me suis pas mis à ajouter des tests tout de suite après la formation, surtout que je n'ai pas fait de rails, mais les concepts m'ont permis de monter rapidement la même chose sur une stack JavaScript. Et aujourd'hui, 2 ans après, j'écris mon premier plugin testé avec RSpec et je me rends compte que cette formation m'a vraiment aidé à y voir clair.
S'il y a un bouquin que je peux vous conseiller aussi c'est Practical Object-Oriented Design in Ruby par Sandy Metz. Du très beau clean code, des patterns clairs, des exemples de séparation of concern très imagés. Chaque phrase de chaque page est bien pensée, il faut le lire à tête reposée mais il expose vraiment les choses clairement.
Et sinon aussi, en vrac, plein de liens que j'avais noté pendant la formation.
La conférence avait lieu dans le grand amphi d'EPITA. Une centaine de personnes. Co-organisé par Etienne Folio et Quentin Raynaud. Organisé tous les 2e mercredis de chaque mois. Centré sur node, mais aussi du js front (Backbone, Ember, Angular, jQuery).
Bien démarrer avec express.js
Première présentation de 10mn sur Express. Surcouche de surcouches. Présentation rapide des convenient methods d'express, et de la batterie de app.set() à définir au début d'un projet express. Explication rapide des middlewares et des templating engines.
Globalement la conférence était plus une présentation ligne par ligne d'un boilerplate express. Assez confus et pas passionnant. Heureusement que FJA m'avait expliqué Express plus tôt dans la journée.
Gérer des processus NodeJS, améliorer leur performance et les monitor avec PM2
pm2 est un process manager en cli pour node qui permet de lancer son appli node sur chaque CPU de la machine hôte et agit comme load-balancer pour renvoyer les requêtes équitablement entre tous les CPU (il faut bien sur une appli stateless pour pouvoir en profiter).
Il permet aussi de relancer ses instances sans downtime. Une nouvelle instance est créée et accepte les nouvelles connections pendant que l'ancienne termine ses connections en cours avant de s'éteindre. Cela utilise le mode cluster de node, mais l'expose selon une API beaucoup plus simple à utiliser par le dev.
Les différentes instances peuvent communiquer par un systeme de pub/sub qui permet de broadcaster des events (mais le dev avoue ne pas avoir trouver de use case intéressant). Fourni avec un monitor en cli qui permet de voir la charge de chaque instance et de reload/restart/etc. Pense faire une version SaaS dans le futur.
Dernière présentation de Bruno Jouhier sur les génerateurs ES6. L'ayant déjà vu à ParisJS je n'y ai pas assisté, mais vous pouvez trouver les slides ici
C'est une librairie graphique qui fonctionne sous Mac, Windows et Linux pour créer des jeux vidéos en 2D simple. Elle peut créer des fenêtres avec une boucle de game play updatée à 60 images par seconde, afficher des images, jouer des sons et intercepter la souris et le clavier. Hyper simple à mettre en place, démo intéressante.
Gem pour activer le support des websockets dans rails. Nécessite un serveur basé sur EventMachine (thin dans l'exemple). Stable, testé sur centaine d'utilisateurs simultanés. Peut être déployé sur plusieurs serveurs synchronisés (utilise Redis pour ça). Démo rapide d'un pub/sub en quelques lignes en écoutant des events sur le serveur. Encore quelques limitations : bugs sur des edge cases, securité et partage des events, serveur ne capte pas les déconnections des clients, mais activement développé.
Présentation de divers gems en rapport avec Redis
redis-objects pour mapper directement des objets ruby dans Redis
redis-rb pour parler à Redis dans une syntaxe rubyiesque
redic pour parler à Redis dans une syntaxe redisesque
nest pour travailler avec des clés structurées (type “user:42:name”)
Heimanu
Présentation du site Heimanu qui utilise Discourse en interne pour proposer des discussions en temps réel entre ses membres. Ils se sont retrouvés bloqués par le système de permissions de Discourse qui ne convenait pas à leur appli, ils ont donc rajouté une surcouche à Discourse (elle aussi en rails + ember) pour régler leur problème. La conf était assez brouillon et très spécifique à leur usage. Il leur a quand même été demandé s'ils n'auraient pas mieux fait de faire à la main plutôt que de modifier Discourse. Réponse : Mauvaise estimation du temps nécessaire à la modif (6 mois plutôt que 4), mais Discourse propose tellement de choses que si c'était à refaire ils le referaient.
Cache Rails 4
Finalement, présentation du caching HTTP dans Rails 4. En fait, plutôt présentation du caching HTTP coté client tout court. Max-Age et ETag/Last-Modified.
Présentation des méthodes expires_in, fresh_when, is_fresh pour tester tout ça. Idée intéressante d'utiliser des ETag custom et de les intercepter coté Rails pour accélérer des traitements (sans pour autant cacher toute la page). Par exemple une clé Redis contenant les infos pertinentes.
Discussion sur l'intérêt de définir ces entêtes private (seul le client final cache la ressource) ou public (tous les proxies sur le chemin peuvent la cacher). Economie de requêtes sur le backend rails, mais moins la main sur l'invalidation du cache). (Pour info, cette page explique très bien les mécanismes de cache client)
Galaxy: async/await grâce aux générateurs "harmony"
Présentation de yield et des function star en javascript. Ce qui existe déjà en python et ruby. Et utilisation de streamline.js et galaxy.js pour l'implémenter.
Semble assez puissant et bien fourni, c'est un préprocesseur qui ajoute ces nouveaux mots-clés (mais qui sont déjà intégrés dans Chrome Canary et dans un Firefox).
L'idée est de réussir à combler le problème des pyramides de callbacks de nodejs pour rendre le code un peu plus simple à lire en lui donnant une allure de code synchrone. Apparemment tout cela intégre un systeme de traceback et pile d'erreur qui permet de remonter la pile des callbacks en donnant le contexte
ExoBrowser
Deuxième présentation sur ExoBrowser un side-project qui s'est transformé en browser complet. Il réutilise le travail fait par chromium en intégrant un thread nodejs à l'intérieur d'une WebView générée par Chromium. Toute l'UI est fabriquée manuellement en HTML/JS/CSS. Le thread node intégré écoute sur les events du navigateur (resize, load, cookie, search, etc).
Cela lui permet de faire de son navigateur exactement ce qu'il veut. L'idée de base étant d'avoir des onglets sous forme de pile plutot que d'onglets. De même, les listeners des cookies permet de pouvoir les stocker et centraliser pour avoir sa session qu'on peut récupérer d'un browser à un autre.
jQuery et TDD
Présentation de comment tester son code jQuery en console. En utilisant json-dom et nodejs pour simuler une page web et tester son code dessus. Le simple fait de ne pas avoir de rendu visuel sous les yeux les force à mieux organiser et présenter leur code.
La démo ne portait que sur du refactoring d'éléments assez simple mais permettait de montrer que oui, c'est possible, de faire du jQuery en TDD.
Le samedi, après les conférences Paris Web, c'est toujours les ateliers. Je conseille à tout le monde d'aller aux ateliers. Même si vous ne venez pas aux conférences, les ateliers sont toujours très instructifs et surtout, c'est vraiment pas cher.
Ce sont des cours moins théoriques et plus pratiques, par petits groupes, et avec une plus forte intéraction avec le speaker.
Apprendre à se servir des Chrome Dev Tools
Thomas Bassetto nous parle des fuites mémoires et de comment on peut les débusquer et les corriger avec les Chrome Dev Tools. Le principe même d'une fuite mémoire, c'est qu'elle n'apparait pas dès le début mais seulement quand on laisse tourner son application pendant un certain temps d'utilisation.
A la fois Chrome Canary et les Nightlies de Firefox proposent des outils de profiling très utiles pour les trouver. Les versions ne sont pas toujours stables, mais elles sont excellent pour débugguer.
Pour Chrome, il est conseillé de se créer un nouveau profil pour débugguer. Pour repartir comme ça sur une base clean, sans extensions, sans cache, sans historique, etc. Idem sous Firefox.
Safari sous Mac a longtemps était une copie-conforme de Chrome, mais aujourd'hui les deux sont bien différents et les outils de débugging de Safari sont très mauvais. À la place, il est conseillé sous Mac d'utliser WebKit.app.
Sous Windows 8.1, les outils de debug de IE11 sont très bon aussi. Si vous devez débugguer d'anciennes versions de IE, c'est une autre histoire...
Thomas nous présente ensuite quelques raccourcis bien utiles et pas forcément connus de l'outil. En sélectionnant un nœud et en appuyant sur h, on le masque, suppr le supprime du DOM (et on peut l'annuler avec Ctrl-Z). Il est aussi possible de déplacer des nœuds du DOM simplement en faisant un drag'n'drop.
Dans la colonne de droite, on peut aussi forcer les états :hover, :active et :focus. Il est possible d'incrémenter les unités CSS en appuyant sur Haut/Bas (en ajoutant Ctrl ou Maj on augmente aussi l'incrément).
Il nous a aussi parlé des fonctions avancées de logging comme console.group, console.groupEnd, console.time et console.timeEnd. Malheureusement, je ne me souviens plus ce qu'elles font...
Il existe de plus des tas d'extensions pour Chrome et Firefox qui ajoutent des fonctionnalités spécifiques pour certains frameworks, comme Ember, Angular, Knockout ou Backbone.
Avec les Chrome Workspaces, on peut même en partie remplacer son IDE. Il est possible de modifier le CSS directement depuis le browser, puis de voir les fichiers modifiés, avec le diff par rapport aux fichiers source. Chrome est même capable d'exporter les fichiers ainsi modifiés pour remplacer les fichiers existants. Ca ne marche par contre pas encore avec les préprocesseurs.
Ces outils proposent plein de petites choses pour rendre la vie du développeur plus facile. Ils ont des fonctionnalités de prettyprint du code (pour indenter correctement un fichier minifié par exemple). Parfois, ces options sont un peu cachées, mais elles existent. Ils proposent aussi bien souvent l'objet $ qui permet de faire des sélections CSS à la jQuery. Si jQuery est chargé alors il l'utilise, sinon il se rabat sur les méthodes natives.
Thomas nous a aussi montré des trucs plus puissants comme des breakpoints en CSS pour voir quand une propriété est modifiée, et par qui (feuille de style, script ?). Je ne me souviens plus de la manip, mais ça m'avait bluffé.
Finalement la dernière feature intéressante sont les possibilités de timeline. On peut voir en temps réel les reflow et les repaints. Ca permet de voir où l'affichage de l'UI prends du temps. A savoir que chaque browser possède ses propres routines pour l'affichage et que donc Firefox et Chrome ne ralentiront pas forcément sur les mêmes choses.
Il est possible de voir le fps général, et donc de détecter ce qui le fait baisser (peut-être un évenement un peu trop poussif bindé sur un onscroll ?). Il est possible de zoomer sur un moment de la timeline en le selectionnant pour aller voir plus profondément, et à partir de là remonter les stacktrace pour voir ce qui a appellé les redraw.
L'outil est vraiment super puissant et je ne me doutais pas qu'il permettait autant. Il est par contre assez complexe à prendre en main, car les fonctionnalités sont légions et parfois cachées.
Thomas a finalement terminé en nous donnant quelques astuces qu'il a apprise au fil de ses débugs. Déjà, le trick d'utiliser -webkit-transform:translateZ(0) sur une animation permet de la faire traiter par le gpu plutot que le cpu. Utiliser un background-fixed sur le body permet d'économiser des repaints. Désactiver les effets de survol quand on scroll est aussi une très bonne idée. Pour ça on peut ajouter par défaut une classe sur le body, qu'on supprime quand on scroll et on n'active les effets :hover que si cette classe est présente.
Finalement il nous a montré les Heap Snapshot de Chrome qui permettent de prendre un snapshot de la mémoire à un moment donné. Vu que ça prends absolument tout en compte il est parfois difficile d'y trouver ce qu'on cherche. Son astuce est de prendre un premier snapshot, puis de faire X fois la même action, qu'il suppose être la cause du problème, puis de reprendre un autre snapshot. Puis il compare les deux, et regarde dans le diffs ceux qui sont multiples de X. Par entropie il a trouvé que X = 7 était un bon chiffre, qui est assez grand pour sortir du lot et assez petit pour ne pas prendre trop de temps. Et surtout, c'est un nombre premier, donc on a moins de faux positifs.
Raphaël Goetter et Nicolas Hoffman nous parlent de frameworks CSS, en prenant comme exemples leurs propres créations. Ils n'étaient pas là pour vendre leur solutions. Ils étaient plutot là pour donner leur retour d'experience, pour qu'on puisse en profiter quand on fait nous-même nos frameworks.
Alors bien sur, on ne fait pas tous des frameworks CSS open-source que d'autres vont utiliser, mais on possède au moins un tas de classes qu'on réutilise d'un projet à un autre. POur faciler la réutilisation, il y a donc quelques bonnes pratiques à prendre en compte.
Déjà, découper ses classes pour les rendre le plus réutilisables possibles. Utiliser une nomenclature cohérente pour nommes les éléments d'interfaces. Toujours garder ses fallbacks pour vieux browsers proches du code de la feature initiale (pas dans une feuille de style supplémentaire). Utiliser normalize pour être sur de partir sur la même base à chaque fois.
Et surtout, une fois que votre nomenclature de nommage est statuée et cohérente, documentez-la et expliquez-là, donnez des exemples.
Il est parfois nécessaire d'aller à l'encontre des bonnes pratiques, comme d'utiliser le sélecteur universel * pour remettre un box-model par défaut, ou utiliser !important pour être sur de ne pas avoir une règle fondamentale écrasée. Bon, là on a le droit, c'est pas une rustine pour un cas particulier.
Finalement comme autres frameworks CSS, ils conseillent de tester Zurb Foundation.
Monitoring
Dernière conférence de la journée et absolument passionante. On a eu un retour d'expérience d'un ops du journal 20 minutes (à moins que ce ne soit Metro ? Je ne me souviens plus).
Il commence par nous dire qu'il est inutile de tout monitorer. Quand on tracke trop d'indicateurs et qu'on se mets trop d'alertes, on recoit plein d'emails et on finit par ne plus les lire et faire des règles de filtrage pour simplement les marquer comme lus.
De la même façon, il faut éviter de créer des dashboards avec des tas de valeurs affichées partout. Le cerveau humain ne process pas cette info aussi vite que si on avait simplement affiché des couleurs, pour voir d'un coup d'œil ce qui cloche.
Il nous a ensuite parlé des outils. Tout d'abord collectd qui collecte des tas d'infos sur le serveur où il tourne (process, RAM, hard drive, etc) et qui les envoie ensuite quelque part.
De l'autre coté, on a Graphite dont le job est d'afficher des données sous forme de graph. Il peut s'installer chez soi ou s'utiliser en SaaS avec Librato. Graphite ne contient pas d'intelligence, il prends des données dans le temps, sous forme de flux, les map et les reduce, garde un historique et les affiche. Les infos ne sont pas stockées telles qu'elles, elles sont compressées au fil du temps pour ne garder qu'un trend.
Graphite fonctionne sous forme de fenetres de temps (Jour, Heure, minutes, etc) sur lesquelles on génére des statistiques génériques. Seuls des valeurs numériques simples peuvent être sauvegardées. Le but est de voir l'évolution d'un "compteur" au fil du temps sur des fenetres plus ou moins grandes. Par défaut pour passer d'une fenetre de temps à une autre Graphite fait une moyenne, mais on peut le configurer pour faire un min, max ou une somme.
Tout ceci est exposé sous forme d'url pour obtenir les valeurs depuis l'exterieur.
Un autre outil à ajouter à sa ceinture est statsd qui permet de collecter des metrics plus personnalisés, applicatives. Cet outil prends des valeurs sous forme de jauge (% de RAM utilisé, jauge de vitesse, etc). Les metrics sont à prendre directement dans le code de l'application, et il existe des SDK pour à peu près tous les langages. L'idée c'est bien sur de lui faire ensuite envoyer ses informations à Graphite pour les tracker.
Graphite n'est pas très performant en cas d'envoie de beaucoup de données. Il est donc possible que des datas soient envoyées, mais ne soient jamais recues. Dans ce cas, on peut faire comme Etsy qui utilise du sampling. C'est à dire qu'ils n'envoient pas toutes leurs données, mais seulement un sur 10, et ils extrapolent ensuite dans Graphite.
Il semble aussi possible d'envoyer des données vers Graphite à partir de munin et awstat mais notre speaker ne l'a pas testé directement.
Ensuite vient logstash, un outil basé sur elasticsearch qui permet de recueillir les logs et les étudier. La bonne pratique est déjà de centraliser ses logs sur un même serveyr, ne pas les laisser pourir les serveurs sur lesquels ils sont créés. Surtout quand on scale, on détruit beaucoup de machines et on risque donc de perdre des logs. Pour ça, on peut utiliser syslogrc ou checksyslog.
Logstash permet de faire des requetes sous forme de regexp, ou de filtrer sur certaines url (pour savoir le nombre de connections à un panier d'achat par exemple). Pour peu que les urls du site soient bien ordonnées, ça permet de faire du tracking à peu de frais en utilisant les logs déjà générés par le serveur.
Un marqueur important à garder dans graphite est les dates des déploiement, de manière à les correler avec les pics possibles d'erreurs et de pouvoir ainsi facilement les isoler. Idéalement chaque commit devrait être présent sur la timeline. Il est important d'avoir des métriques visuelles rapides dès qu'on déploie, pour voir si on a pété quelque chose en production. En intégration ça permet aussi de pouvoir comparer les stats d'un commit sur un autre.
Il nous a aussi parlé de ab ou de thung (pas sur de l'orthographe) qui sont des outils pour tester un serveur, voir à quand il va s'effondrer. Descartes est un dashboard avec un peu plus de classe que le theme de base, pour Graphite.
La fin du talk était surtout l'occasion de lancer quelques noms d'apps qui peuvent aussi aider dans le monitoring, comme logly, logentries, papertrails ou spunk pour l'analyse de logs. sentry pour les logs front, capturer les exceptions, observer les valauers des variables. Il est nécessaire de le configurer abondamment pour l'utiliser en prod car lui demander de logguer toutes les erreurs risque d'en faire beaucoup trop.
Dans la veine de nagios, il nous conseillait riemann ou sensu.