L'entrée dans l'ère du Cloud Computing et du DevOps a permis de nombreuses choses: fluidifier l'innovation, faciliter l'industrialisation du logiciel, diminuer les investissements et accélérer l'arrivée sur le marché (TTM). Pour les développeurs, elle symbolise aussi un vrai changement dans nos manières de coder au quotidien.

Autrefois, on aurait pu faire notre carrière en tant que dev COBOL. Aujourd'hui, on vit dans un monde où chaque jour, un nouveau framework sort. On s'appuie de plus en plus sur des tiers pour bâtir nos services. Et bien que le développeur fullstack qui sait-tout-faire soit un mythe (et doit le rester), on constate qu'il se doit de plus en plus d'être technology-agnostic et cloud-aware.

Expert ET Transverse

Le beurre et l'argent du beurre? Oui, c'est un peu ça.
Ces dix dernières années, nous avons réveillé l'éternel débat du "tout savoir sur rien vs rien savoir sur tout".
Ces débats influent jusque dans la manière dont on enseigne aujourd'hui dans nos Universités. Les entreprises demandent des ingénieurs multi-tâches, qui connaissent Android, React, HTML, PHP, Java, Node.js, Python, CSS3, Angular et iOS.

==> Génial.

Ainsi, on troque l'apprentissage du C++ pour des langages monothreadés et plutôt haut niveau.
Les conséquences à court-terme sont plutôt positives: On sait de mieux en mieux chercher des ressources sur internet, on devient plus flexible et transverse sur les technologies, on est plus rapidement opérationnel, on apprend plus vite, et la technologie semble plus facile et abordable, donc attrayante pour les étudiant(e)s. Cela permet aussi de s'ouvrir à un marché beaucoup moins exclusif.

Bien que ce soit intéressant, ces tendances ont néanmoins leur côté obscur. Nous sommes en train de créer des consommateurs de technologie. Force est de constater que la plupart des équipes tech arrivent aujourd'hui avec une connaissance de surface. Ils recherchent davantage à explorer d'autres choses plutôt que d'aller en profondeur. Parfois, souvent, ça suffit. Mais quand les choses s'écartent de la normale, cela ne marche plus.

En pratique, la technologie est devenue "magique".
On ne sait plus comment la mémoire est gérée, la concurrence et le multithreading sont des notions dont on ne cherche plus à s'occuper, les frameworks font tout le heavy lifting et le rêve : n'avoir qu'à coder. Et honnêtement, c'est un beau rêve!
Le cloud fait disparaitre la machine, la ressource CPU n'est plus qu'un curseur sur une interface web, peu de gens connaissent ou utilisent des profilers, et ainsi s'éteint la maîtrise de nos applications.

A travers la lentille

Imaginez un objectif d'appareil photo :
Au centre, l'image est cristalline, nette, les blancs sont parfaitements balancés car la lumière frappe le plein centre du capteur pour un rendu optimal. Plus on s'éloigne du centre, plus on a de chances d'observer des anomalies: aberrations chromatiques, flare, vignettage, distortions, etc...

Nos applications fonctionnent exactement de la même manière!
Si vous êtes en train de réaliser une application interne pour une dizaine d'utilisateurs par mois, vous n'aurez probablement pas à vous inquiéter de la suite (encore que...).
Si par contre votre application est destinée à être utilisée par de nombreux usagers, la confrontation avec ces conditions et les limites de celle-ci seront inéluctables.
De la même manière, l'explosion du nombre de micro-services moyen par personne crée une augmentation du nombre de pannes, de goulots d'étranglements, et sûrement de l'entropie de l'univers.

The Billion dollar question

Connaissez-vous aujourd'hui la capacité de votre API (sur un scénario donné)?
Est-ce de 10 utilisateurs concurrents? 1000? 100 000?
Quel est le goulot d'étranglement qui ne lui permet pas d'aller plus loin?

Quoi... Aucune idée?

L'aiguille dans la peau de l'ours de mémé

Trouver des bugs, on sait faire. Une stacktrace, des logs, la plupart des bugs sont assortis d'un fil qu'on pourra remonter pour trouver son origine.
Quand on évolue dans un système applicatif "lent", ou qu'on cherche un bottleneck c'est différent. Il n'y a pas de bug. Votre application fonctionne normalement.

Ce qu'il faut trouver? Votre ou vos bottlenecks. Mais comment?

Load Testing

Quel est le moyen que vous préférez pour pousser votre application dans ses retranchements?
A - Attendre que les usagers arrivent à l'ouverture de ma billeterie en ligne pour le concert des Red Hot (plus gros CA de l'année)
B - Louer 133 700 stagiaires pendant 1h pour faire une campagne de tests à grande échelle
C - Faire des tests de charge
D - La réponse D

Une seule réponse est bonne: une vous coûtera cher, une autre risque de faire couler votre boite, et une ne sert à rien.

Le test de charges, c'est le seul moyen safe de voir comment votre système se comporte aux limites.

Mais d'ailleurs, ça sert à quoi un test de charges?

Small Scale, Large Scale

On peut faire du test de charges pour de nombreuses raisons, en voici certaines :

  • Optimiser nos temps de réponse
  • Maitriser l'évolution de nos développements
  • Eprouver notre application dans sa globalité
  • Détecter, repousser nos bottlenecks pour admettre plus de trafic

Les deux premières servent en général à tester un bout de notre système (un micro-service par exemple ou un petit ensemble de la stack) sur un ensemble de scénarios. Ces types de campagnes que je qualifie de "micro"-test, ou "small-scale", doivent se faire aussi régulièrement que possible (voire de manière automatisée en CI). Elles permettent à la fois de tester les limites "isolées" d'un bout d'une application, et de vérifier que vos futurs développements ne la dégradent pas.

Wait What?
Eh bien oui, on prône tous le software craftmanship, le test unitaire, les tests d'intégration, parce qu'on cherche à garantir l'absence de régressions fonctionnelles. Ca c'est normal non?
Et si votre nouvelle feature rallonge de 70% le temps de réponse de votre service... C'est une régression ou pas?

Par analogie, imaginez que je suis un constructeur de roues de voitures.
Pour tester sa résistance, je la fais rouler très vite (800, 900km/h) sur un rouleau et je vais voir jusqu'où elle tient, et ce qui se cassera le plus vite. Puis je cherche à améliorer ma conception. Ensuite, je recommence mon test pour vérifier que mes nouvelles modifications permettent bien à ma roue de conserver sa robustesse initiale.

Les deux suivantes elles sont en général plus grandes. Ici, on parle de campagnes grande échelle sur notre production (ou une infra analogue). L'objectif n'est plus de tester notre service tout seul, mais plutôt d'étudier le comportement du système lorsque cette partie est soumise à une haute charge. Ici, le contexte est beaucoup plus macroscopique.

Si on reprend la métaphore précédente, ces campagnes "macroscopiques" ou "large-scale" correspondent au test de la roue une fois montée sur le véhicule. Cette fois, j'étudie plutôt l'influence de ma roue sur le reste du véhicule. Elle n'ira sûrement plus jusqu'à 800km/h, mais je veux regarder comment se comportent les essieus, les freins à disque, etc...

Ces types de campagnes sont donc plus onéreuses, bien plus complexes à mettre en oeuvre, mais sont absolument indispensables pour maitriser son système.

Mais en vrai ça marche comment?

Ca tombe bien... On a donné un talk pile sur ce sujet il y a quelques semaines au Devoxx France.
Tu y trouveras un retour d'expérience et largement plus de détails sur le pourquoi du comment.