Q

Quand ton code «parfait» rencontre le réel

Jean David Olekhnovitch 11 min de lecture

Et voilà, le festival du Court-Métrage de Clermont-Ferrand a fermé ses portes, et avec lui une des semaines les plus intenses de mon année professionnelle. Comme chaque année depuis quelque temps, je travaille avec mes collègues à faire en sorte que le festival soit le plus agréable et le plus fluide possible du point de vue des outils numériques.

J’ai essayé cette année de lister les enseignements que je tire de ce dossier. Et je souhaite à tout informaticien d’avoir à gérer ainsi des gros « rushs » car c’est ainsi qu’on apprend la réalité de notre métier !

Pas un cours ni une leçon, pas de règles absolues à suivre : juste des retours d’expérience, des réflexions, un « work in progress » qui est là pour illustrer qu’il faut rester humble et continuer à apprendre tout au long de notre carrière professionnelle.

rester humble et continuer à apprendre tout au long de notre carrière professionnelle

D’ailleurs en me relisant je m’aperçois qu’il n’y a vraiment rien de très haute-technologie dans ce que je raconte. On va causer montée en charge sans parler de Kubernetes ni de répartition de charge, pas parce que ce n’est pas utile, mais parce qu’on a pu s’en passer à l’échelle de ce dossier. Plutôt des vieilles recettes parfois un peu oubliées, et un rappel au bon sens.


Choisir une solution « custom » est un choix courageux, pas toujours pertinent, mais potentiellement très puissant

Le client est arrivé avec un historique énorme de règles de gestion qui, pour certaines, dataient des débuts du festival. Autant dire qu’utiliser une solution toute prête de billetterie revenait à faire rentrer un carré dans un rond. On a longtemps débattu de l’intérêt de faire une solution sur mesure. C’est au final le choix qui a été fait, et, dans ce cas, je pense que c’était la bonne solution. Car ça nous a permis d’avoir une solution qui s’adapte à l’utilisateur, et pas l’inverse.

Mais c’est, sans aucun doute, un choix qui doit être longuement soupesé, car il n’y a pas de bonne façon de faire : il y a des choix adaptés au contexte. À l’heure où le code devient une commodité avec l’IA, on va probablement aller vers des choses plus « custom », plus adaptées au besoin de chacun. Je reste persuadé que c’est un scénario plausible, mais à challenger projet par projet.

Et puis ce n’est certainement un choix « blanc ou noir » : par exemple, pour les commandes en ligne, on n’a jamais cherché à réinventer quoi que ce soit, et un WooCommerce lié à un plugin de paiement existant a parfaitement fait l’affaire.

Gérer un gros flux de données en live est la meilleure école pour forger des qualités techniques de développement

Quand tu te prends 10 000 connexions d’un coup, et que toutes utilisent un workflow complexe, tu n’as aucune possibilité d’influencer les choses. Ça passe ou ça casse. Et c’est très souvent là que tu te rends compte que ton code dont tu étais si fier, que tu avais testé dans tous les sens, est encore bien fragile.

C’est un peu un feeling proche, je crois, de ce que racontent les coureurs : tu crois être arrivé à tes limites, mais ce n’est en fait que la première étape. Et ton code « parfait » va évoluer en une v2, v3, v4… qui te fait bien relativiser l’idée que tu te faisais de la solidité de ta v1. Une vraie école de l’humilité.

L’optimisation est un travail de développeur bien avant que le sysadmin arrive

On a beaucoup trop tendance à balancer un programme fonctionnant, puis à dire à l’hébergeur : « démerde-toi, rajoute des machines ou mets du cache partout s’il le faut, ça doit tourner vite. »

On a complètement perdu les pédales en s’appuyant aveuglément sur des gros frameworks sans plus jamais se poser la question d’être un peu malin dans sa façon de concevoir son code. C’est lorsque j’ai eu à travailler dans un projet lié au trading que j’ai compris que chaque milliseconde comptait. Et qu’on pouvait prendre un vrai plaisir à étudier dans le détail chaque traitement.

La gestion du cache est en particulier un vrai cas passionnant : on a bien trop tendance à balancer un système de cache « global » qui va tout amortir d’un coup en front d’un site ou d’une application, sans aucune subtilité. Mais le meilleur cache est encore celui qui est pensé très finement, au sein même d’un process métier. Par le développeur !

Corollaire à ça : mettre son effort là où c’est utile. Je n’ai aucun problème à optimiser certaines parties du code à l’octet près en y passant des heures, et laisser générer par de l’IA une autre partie sans presque regarder le code. Tant que ces arbitrages sont judicieux.

Rendre asynchrone tout ce qui peut l’être

Peu importe le volume d’activité ou la complexité du workflow, l’utilisateur final n’a jamais à subir la charge d’un traitement. Lorsque j’apprenais à faire du Cobol il y a bien longtemps, on apprenait que les traitements batchs, ces traitements qu’on réservait « pour plus tard » parce qu’ils n’étaient pas indispensables, étaient si importants qu’ils étaient intégrés dans les concepts du langage. À l’époque, c’était parce que les machines étaient tellement poussives qu’on ne pouvait pas faire autrement.

Reproduire cette logique peut s’avérer très précieux. À une condition : penser ses workflows ainsi dès le départ, en négociant chaque règle de gestion pour qu’elle puisse devenir asynchrone. Et peu à peu, ton queuing va se remplir, et ton code live s’alléger.

Keep It Simple, Stupid

Lors de la première année d’exploitation de notre code, un incident majeur est apparu. Le workflow de scan à l’entrée en salle saturait les serveurs, bloquant ainsi des milliers de spectateurs. Et le modèle de fonctionnement du festival exigeait des traitements bien plus complexes qu’une simple gestion d’entrées à un concert.

En catastrophe, on a allégé les règles de vérification des billets pour pouvoir sauver les apparences. Une fois l’orage passé, une nuit douloureuse en choix et refactoring s’imposait.

Un choix classique aurait été d’augmenter le nombre de serveurs. Mais je savais au fond de moi qu’on avait une stack trop lourde. Je me suis souvenu d’une anecdote datant du lancement de Free Mobile. Le jour du lancement, le site d’inscription, fait en Java et probablement peaufiné depuis des mois, s’était effondré. Le lendemain matin, le site avait entièrement changé pour de simples pages PHP sans aucune fioriture. Et les inscriptions étaient délivrées. Je n’ose imaginer la pression et la nuit blanche passée, mais le lancement était sauvé.

On est donc reparti de la base. Lister les requêtes SQL qui faisaient la base du boulot. Les optimiser au mieux. Puis les encapsuler dans une stack la plus légère possible. Aujourd’hui, je le ferais sans doute en Go, à l’époque on avait fait au plus simple avec des scripts PHP qui souvent ne dépassaient pas 10 lignes. Et le lendemain, le serveur chauffé à blanc la veille ronronnait comme un chat endormi sur les genoux de ta mémé.

La base… c’est la base

Même avant ces incidents, on avait décidé de démarrer le projet de manière très classique : en structurant la base de données. Aucune ligne de code tant qu’on n’était pas pleinement satisfait de la structure de base. On a donc passé des heures à batailler pour discuter la moindre liaison relationnelle entre deux tables. Un des membres de l’équipe était dédié à la base de données. On s’est forcé à utiliser des triggers en base le plus loin possible avant d’écrire l’application elle-même.

J’ai toujours été un « pisseur de code » – bon, moins avec l’IA – et j’ai depuis le début de ma carrière considéré la base de données comme un simple outil pour stocker des trucs. Ce projet m’a appris que mettre un maximum d’efforts sur la BDD était un legs précieux pour la solidité et la pérennité du projet. Et avoir un « monsieur SQL » dans l’équipe s’est avéré plus que judicieux.

Pour aller jusqu’au bout des coulisses : les premières années, le M. BDD de l’équipe était également le chef de projet, la personne en frontal du client. Là aussi, ça s’est avéré des plus pertinents, car chaque règle métier discutée et amendée avec le client l’était en ayant la structure de base en tête. Et les fondations du projet ont pu ainsi rester solides au fil des ans.

Optimiser, peaufiner… mais laisser des « fuites contrôlées »

Lorsque j’étais ado, j’avais eu l’occasion de visiter un barrage hydraulique. J’avais été impressionné par l’immensité de la construction, mais surtout par un petit détail : il y avait dans le barrage des « fuites contrôlées », des écoulements d’eau dans la structure qui étaient prévus et surveillés. Ça permettait de détecter les anomalies bien plus qu’en s’obstinant à avoir un ouvrage « parfait » mais qui, dans sa perfection, ne laissait passer aucun signe de faiblesse avant qu’il ne soit trop tard.

Quand on fait un programme qui va être utilisé de manière intensive, on a forcément le souhait de délivrer quelque chose de parfait. Mais, avec le recul, on s’aperçoit souvent que vouloir absolument tout contrôler nous condamne à implémenter des process qui peuvent s’avérer bien trop lourds et disproportionnés.

On retrouve cette philosophie dans d’autres domaines. Prends un moment pour étudier le fonctionnement du Bitcoin, et tu seras surpris par les approximations inhérentes au modèle. Ce que propose le livre blanc n’est pas un truc « parfait », mais un système qui accepte des compromis sur des risques théoriques de collision, par exemple lorsqu’on affecte une clé publique/privée sans s’assurer de son unicité, tellement les chances que cela arrive sont faibles.

À notre modeste échelle, on a été confronté plusieurs fois à ce type de choix : atteindre la perfection était possible, mais aurait parfois trop altéré les performances de l’ensemble, et la simplicité du code. Le premier degré de négociation était fonctionnel : travailler avec le client pour simplifier des règles de gestion inutilement complexes est sans doute le levier le plus puissant. Mais il y a des cas où le bon arbitrage est d’accepter des « fuites contrôlées » : on sait qu’il y a une chance minime de traitement pris en défaut, mais on préfèrera, dans certains cas lourdement soupesés, tolérer l’anomalie et la surveiller, pour éventuellement la rattraper plus tard dans un traitement batch.

Partager cet article :
Jean David Olekhnovitch

Écrit par

Jean David Olekhnovitch

Oldschool developer, Auvergnat & European & Québécois d'adoption. At the crossroad between tech, people and culture. Living on a small Island in Québec

Développement

Quand ton code «parfait» rencontre le réel