Encore un abandon !

Après l’épreuve de la semaine dernière, j’ai encore abandonné au contest Codingame !

Et cette fois-ci, j’ai au moins la chance d’avoir appris des tonnes de choses.

D’habitude, quand je commence un contest Codingame en Java, j’importe mes librairies classiques : playground, point discret, outillage de debug, j’ai à peu près tout ça. Mais là, en Rust, je n’avais rien (et je n’avais pas non plus le plugin Maven magique qui me permet de composer le fichier final à partir de sources distincts). J’ai donc dû réécrire tout ça.

Réécrire le tableau 2D avec des getters/setters et un visiteur, c’était à peu près facile … sauf que le getter m’a imposé de plonger dans les histoires de lifetime (et ça n’était pas drôle). Regardez un peu l’allure de la méthode :

    fn get<'get_lifetime>(&'get_lifetime self, x:usize, y:usize)-> &'get_lifetime Content {
        let line = self.content
            .get(y as usize)
            .expect(&format!("I tried to read line {} in a playground of height {}", y, self.height));
        // Notice how the ";" implies I need to add a return statement, which I'm not against at all
        return line.into_iter()
            .nth(x)
            .expect(&format!("Cannot read content from ({};{})", x, y));
    }

Vous trouvez ça lisible ? (je parle en particulier de la signature, mais le reste n’est pas non plus bien simple)

En tout cas, je comprend à peu près le sens de cette partie : le pointeur est stocké dans mon tableau, et le fait d’obtenir un nouveau pointeur implique de dire au compilateur Rust quelle durée de vie aura celui-ci (enfin, si je comprend de travers, n’hésitez pas à me le dire).

Dans l’ensemble, ça, c’était facile.

Et puis je me suis convaincu que j’aurais besoin de générer mes tests unitaires (ce qui est vrai, évidement). Donc j’ai attaqué ma fameuse génération de test. J’ai consommé bien trop de temps là-dedans. Mais j’ai également appris beaucoup sur les traits, et les traits génériques.

J’allais continuer tranquillement, quand j’ai été attaqué par « la vraie vie ». Je n’en parlerai pas ici, mais il est question de politique de bureau, et de toutes les horreurs que ça implique. Bon, il est aussi question de DevFest (qui était cool, mais m’a bouffé deux jours de code).

Je reprendrai ce contest plus tard, parce que je vois à peu près ce que je dois faire, et que j’ai bien envie de chercher des solutions Rust. J’ai aussi envie de voir comment je peux réécrire mes outils magiques (et en particulier voir si je peux utiliser les macros pour générer mes tests d’une façon intelligente).

Bravo en tout cas aux auteurs de ce jeu, qui jouent subtilement avec les histoires de coopétition pour créer (à mon avis) des stratégies riches.

Publicités

DevFest Lille 6 : L’open-source à la rescousse de mes API

Dans cette présentation, David et Guillaume mettent en oeuvre un API manager Gravitee sur une application assez simple, qui permet néanmoins de voir la plupart des cas d’utilisation de Gravitee pour sécuriser une API.

Créer une application

David avait déja fait cette présentation au chtijug.

CORS

Il est facile de rajouter les entêtes CORS dans une API avec Gravitee (vraiment facile).

Authentification et autorisation

Ben là, le plus simple, c’est de passer par Keycloak (qui a également été présenté au chtijug !).

Création du realm

Pour le coup, onv a utiliser Keycloak en authentifieur OpenID. Il faut donc créer un CLIENT_ID pour l’application.

Connexion de l’interface web à Keycloak

Pas bien compliqué, puisque Keycloak fournit l’api JS pour s’authentifier auprès du serveur Keycloak. Et on peut évidement utiliser tout un tas de fournisseurs OpenID.

Sécurisation d’API

Identification

Dans ce cas, il faut créer pour le client (l’interface web en l’occurence) une clé d’API qui lui permettra d’accéder aux ressources qui sont protégées par le plan définissant cette clé. Ce qui n’est pas une clé d’autorisation : c’est juste une identification. === Autorisation Pour autoriser l’accès à l’API, on va encore une fois passer par Keycloak, qui sera cette fois le provider OAuth2.

Conclusion

L’un des intérêts du coupe Gravitee + Keycloak, c’est qu’on peut ajouter des fonctionnalités à l’application sans jamais toucher au serveur backend. Et ça, en terme d’évolutivité, c’est top !

DevFest Lille 5 : Les cookies HTTP

Hubert vient tous parler d’un sujet quasi-neuf : les cookies. Et évidement, comme chez les autres showmen de l’informatique, la forme compte autant que le fond.

Revenons en 1994. A cette époque, Lou Montuli travaille chez Netscape. Et le navigateur typique est Lynx (et pas links, sa version avec Javascript et autres). On y invente (un peu à cause de lui) la balise <blink>. Et il y invente également les gifs animés. Et enfin, il y invente les cookies, dont l’objectif était déja de maintenir une session côté client.

C’est un paquet d’information envoyé par le serveur (via l’entête http Set-Cookie). Le navigateur les stocke localement dans un cookie jar (une boîte à cookie). Et lorsqu’il refait une requête au même serveur, il renvoie les cookies que ce serveur a déja positionné (via l’entête cookie).

Par défaut, le cookie expire quand le navigateur est fermé. Sauf évidement quand le serveur envoie l’entête Expiration-Date ou Max-Age qui définit une date de suppression.

La méthode typique est d’envoyer une Expiration-Date dans le passé, ou un Max-Age de 0.

Comment le navigateur sait-il que deux requêtes concernent le même site ?

Attribut Domain=

Avec cette attribut, le cookie est accessible sur tous les domaines dont le nom se termine par ce domaine. Par contre, on ne peut pas positionner un cookie sur un TLD (top level domain). Ces domaines sont tous listés sur http://publicsuffix.org.

On ne peut pas non plus définir comme domaine localhost.

Attribut Path

Si cet attribut est positionné, le cookie est positionné lorsque le path commence par le préfixe défini suivi par un /.

Attribut Secure

Lorsqu’il est positionné, le cookie n’est envoyé que pour les pages servies en https. ATTENTION ! cet attribut peut être positionné par une page non sécurisée (ce qui pourrait ouvrir la porte à toute une série de mauvaises requêtes).

Header HSTS

L’entête HTTP Strict-Transport-Security garantit que toutes les requêtes suivantes seront effectuées en HTTPS, comme une redirection (mais sans aller-retour de la requête auprès du serveur.)

Préfixes __

Deux préfixes de ce type existe : _ sur un nom de cookie et Host. chacun d’entre eux limite et le nombre de cas dans lesquels le cookie est servi.

Choix du port

Deux requêtes sur des ports différents serviront les mêmes ensembles de cookies. Heureusement, les navigateurs implémentent le same origin policy (qui identifie un serveur pour le local-storage, les requêtes Ajax). Malheureusement, celui-ci n’est pas utilisé pour les cookies.

Est-ce que les images utilisent également les cookies ?

Evidement ! Et du coup, c’est ce qui ouvre la porte aux attaques cross-server (CSRF & co). A noter qu’on peut les inclure dans des images. Mais comme le dit Hubert, entre gens de bonne compagnie, on ne fait pas de requêtes GET pour mettre à jour un site web.

Attribut SameSite

Avec cet attribut, les cookies ne sont envoyés que lorsqu’il sont servis par une page issue du même site.

Qui lit les cookies ?

Le navigateur, mais aussi l’API Javascript document.cookie …​ qui est sacrément étrange.

Et c’est la porte ouverte aux attaques XSS

Le sujet est vaste.

Attribut HttpOnly

Quand il est positionné, les Javascript dans la page ne peuvent pas accéder au cookie.

Mon avis

Le tour d’horizon était chouette. Et évidement, Hubert est un sacré showman qui maîtrise (presque) tous ses effets.

DevFest Lille 4 : Tout le monde sait comment utiliser Angular / React / Vue.js …​ Mais savez-vous comment utiliser Javascript ?

Pourquoi aller voir une présentation sur Javascript ? D’abord parce que ce sont des collègues qui présentent, et qu’il sont sympathiques. Ensuite parce que Javascript est suffisament pervasif pour que ça vaille le coup de rester à jour.

Les fonctionnalités cool

J’adore ce premier exemple : 1+1+(1+true+[]+3+[20]+3)-2. Ca donne quoi ? 223201 à cause d’une série de transtypages à la volée.

Un autre exemple utilise des blocs et des labels qui donnent des résultats tout aussi surprenants.

Et comme dans tout langage, il faut les connaître (et malheureusement, la plupart des développeurs Javascript ignorent ce genre de petits détails).

ECMAScript 2015

ECMAScript ajoute le spread operator (la déstructuration comme en Python), les promesses (avec un ) qui réutilisent le contexte de la fonction appelante, les proxys (qui permettent d’initialiser facilement des arborescences d’objet).

Frameworks

Il y en a plein, et ils correspondent souvent à des cas d’utilisation clairs qu’il faut connaître pour les utiliser à bon escient (oui, comme partout, mais en Javascript, il y a beaucoup plus de mode).

Vanilla.js

Le javascript standard contient déja toutes les fonctionnalités nécessaires, et on peut parfaitement développer des applications JS sans utiliser le moindre framework (mais je le savais depuis 18 ans).

Binding

Nathan va nous réaliser un binding simple …​ si la technique le laisse faire (parce que la vidéo semble avoir rendu l’âme d’un coup). Je vous laisse regarder leur dépôt, c’est redoutablement simple.

Templating

Aurélien va maintenant construire un système de templating basé sur la fonction précédement définie par Nathan.

Mon avis

C’était chouette ! En particulier la longue conclusion sur la manière dont on construit le choix d’un framework à partir du problème à résoudre, et pas à partir des buzzwords du moment.

DevFest Lille 3 : L’UX a sauvé mon DevOps

Estelle est PO chez Elium. Et elle fait partie des Duchess (et ça c’est cool !). François est développeur chez Saagie (encore un :-)). Et il faut du Rust (et ça c’est – évidement – très cool).

Les concepts

Devops

Le buzzword du moment (je suis bien d’accord). Mais surtout une façon d’intégrer de nouvelles phases de déploiement dans le périmètre des équipes qui construisent le logiciel. Attention, ça ne veut pas dire NoOps (c’est-à-dire virer les ops des structures). Ca veut plutôt dire les intégrer correctement dans les équipes.

UX

C’est une approche à la croisée du design, de la stratégie et de la technologie. Mais c’est assez différent du design et de l’UI. L’exemple typique, ce sont les raccourcis que prennent les piétons plutôt que de respecter les détourss que font les trottoirs.

L’UX, ça se découpe en plusieurs phases

  • Exploration
  • Idéation
  • Génération
  • Evaluation

(ça me rappelle les bases de la méthode scientifique, c’est fou)

La rencontre

Dans une entreprise commune, l’équipe d’ops est devenue DevOps par le biais d’un renommage magique. Ca n’est pas très facile. Et du coup forcément l’équipe DevOps souffre pour les raisons habituelles (trop de pression, pas assez de moyen).

Donc le management a ramené Estelle pour faciliter la communication avec les autres équipes.

Première étape

D’abord, prioriser correctement (c’est fou, mais c’est évidement parfois oublié). Et évidement tailler dans le gras du backlog de l’enfer. Et constater que la meilleure communication passait auparavant par les soirées bière de François avec les développeurs.

Estelle met ensuite en place les outils agilistes classiques (la rétro du speed boat que je déteste). Le truc amusant, c’est que l’atelier a eu peu de retour effectifs – parce que les ops ne se sont pas vraiment levés pour aller poser des post-its.

Deuxième étape

Maintenant que les équipes dev et ops se connaissent, il faut aller plus loin. La partie ops n’avait pas d’objectifs visibles. Ces objectifs ont donc été intégrés dans la roadmap de ‘léquipe de dev. Par ailleurs, lorsque les développeurs ont besoin de l’équipe ops, ils ont fait en sorte que ça devienne un besoin visible et inscrit dans une roadmap visuelle. Ensuite, Estelle a lancé la fameuse méthode des 5 pourquoi pour trouver les causes des freins au déploiement.

Troisième étape

Le problème qui reste, c’est qu’en fait, quand bien même les équipes se connaissent, ils ne s’intéressent pas spécialememt à ce qui se passe de l’autre côté. Et pour pallier à ça, il est temps de passer aux vrais ateliers UX

Les 6 chapeaux de Bono

Pour trouver une solution à un problème, il faut savoir changer d’angle. Cette méthode propose 6 angles matérialisés par des chapeaux pour adresser un problème

  • Neutralité
  • Emotions
  • Créativité
  • Pessimisme
  • Optimisme
  • Organisation

Donc on l’applique au problème classique de « les dévs n’ont pas assez d’environnements de tests ».

Persona UX

Avec ça, on est capable de construire un utilisateur « virtuel » qui va regrouper des attributs clés, et permettre de savoir si ona servi leur besoins sans avoir à leur demander à chaque fois. C’est un outil qui a été très utile à l’équipe DevOps pour construire le design de leurs solutions.

Bilan

Les différents outils présentés s’intègrent bien à l’approche UX, et ont permis une nette amélioration de la collaboration entre les différentes équipes. Attention à un point important : les développeurs sont formés à penser solution. Par exemple,si on leur demande quel est leur problème, ils répondront « je veux du K8s », alors que son problème est « on n’a pas assez d’environnement ». DevOps a un impact important sur les développeurs. Et ça consomme énormément de temps dans l’équipe.

Enfin, il ne faut pas oublier que ces solutions sont des solutions adaptées à une équipe. Une autre équipe aura d’autres problèmes, qui impliqueront d’autres solutions.

Devfest Lille 2 : gRPC

Ca fait belle lurette que les ordinateurs communiquent entre eux à travers des modes non connectés où on envoie des bouteilles à la mer (UDP) ou connectés où le récepteur et l’émetteur se connaissent (TCP).

gRPC se place au même niveau de protocole qu’HTTP ou SSH.

Je vous passe l’introduction à la communication réseau (avec ouverture de connexion, passage de messages de taille donnée, …​). N’empêche, on a plusieurs fois essayé de simplifier les communications

  • 1990 HTTP/1 pour transférer des fichiers
  • 1992 CORBA pour l’appel RPC
  • 1997 Java/RMI pratique, mais seulement en Java
  • 1999 EJB
  • 1999 SOAP & WSDL intéressant en principe (mais j’aurais bien des choses à en dire)
  • 2000 HTTP/JSON (qui a juste mis 10 ans à sortir de l’ombre de SOAP)
  • 2008 Protocol Buffers
  • 2009 Thrift, RPC
  • 2015 gRPC

Et donc, gRPC est un outil de communication pour appel de méthode distant, qui utilise Protocol Buffers pour limiter la taille du contenu, utilise un IDL pour générer du code dans de multiples langages, et est incubé chez la CNCF.

Le protocole est basé sur HTTP/2, permet le streaming bi-directionnel, et fournit un mode adapté aux environnements réseau difficiles. En bonus, on peut y ajouter des plugins pour permettre le retry (par contre, la configuration des plugins me paraît …​ curieuse).

Le premier point important, c’est l’IDL. Dans ce langage, on va donner une liste des méthodes des services, et on donnera pour chaque méthode la liste des messages utilisables. Chaque message contient une liste de champs qui sont numérotés pour permettre facilement les évolutions.

La démo !

Dans sa démo, Sébastien crée un client et un serveur qui s’envoient des messages parlant de bières (et c’est cool). Malgré tout, gRPC, ça reste du RMI comme en l’an 2000. Pire encore, go et son aspect diesel-punk me rend littéralement malade. Donc forcément, les démos ne m’ont pas spécialement impressioné, puisque j’ai vu des choses équivalentes en Java/RMI dès l’an 2000. Alors effectivement, c’est censé être performant grâce au protocole choisi. Mais si je fais demain du RMI (ou du Corba, pour rester cross-language) over protocol buffers (je ne suis pas sûr que ça existe, mais j’imagine que c’est possible), quel sera le gain de gRPC ?

Par exemple, le fait de pouvoir ajouter et supprimer des champs dans le protocole est vraiment bienvenu dans le cadre d’architectures évolutives. Et le fait que ces champs soient typés est évidement un avantage pour garantir que les clients et les serveurs peuvent se parler correctement.

Cela dit, bravo quand même au speaker qui a affronté un bon paquet de merdes (vidéo, micro, …​).

Mon avis

J’ai l’impression qu’on revient à une architecture définie de façon formelle, comme c’était le cas à l’époque du CORBA et du RMI (voire même des EJB). Est-ce que c’est bien ? Je ne sais pas. En revanche, ça revalorise les interfaces en tant qu’éléments clé dans la définition d’une application, et c’est bien.

Devfest Lille 1 : UX et jeux vidéos

Sarah Coulmont est ingénieur en cognitique, et travaille chez Murex sur …​ l’UX. Alexandra Nemery est docteur en ergonomie, et travaille également chez Murex sur l’UX.

Sarah commence par nous cadrer le sujet : dès qu’une personne utilise un logiciel, c’est de l’expérience utilisateur. La France est assez en retard dans ce domaine, mais peut le rattraper en se posant quelques bonnes questions

Qui sont nos utilisateurs ?

En général, on trouve quatre types de personnalités

  • Combattant
  • Accomplisseur
  • Socialiseur
  • Explorateur

Chacun de ces types de personnalités a des motivations différentes. Et évidement, ces différents profils vont demander des expériences de jeu différentes.

Il me vient à l’esprit d’ailleurs que ces histoires de profil sont applicables également au rôles de développeurs.

D’une façon amusante, Sarah et Alexandra délèguent ensuite une partie de leur présentation à Kahoot.

Ce qui nous permet d’apprendre que l’UX doit être prise en compte tout au long du développement, ou que le profil de joueur le plus rare est l’explorateur.  Malheureusement, la salle se dissipe assez rapidement avec ces questions assez amusantes. Et clairement, 200 bons gros développeurs qui discutent, ben ça fait trop de bruit pour moi (parfois, je suis un vieux con).

Alexandra enchaîne avec des contre-exemples d’interfaces dans Summoner Wars. Certains me paraîssent même être de l’ordre des dark patterns. En tout cas, ces exemples montrent bien le besoin d’une terminologie claire et de chemins de navigation simples dans les interfaces.

De la même manière, Sarah nous montre dans Heavy Rain le risque que provoque une interface inhabituelle avec une manipulation du personnage via des contrôles joystick inhabituels pour les gamers. Ce qui va parfois avec l’envie des créateurs de faire ressentir au joueur l’inconfort du personnage (dans certaines scènes de franchissement d’obstacle), mais peut empêcher l’immersion du joueur.

Par ailleurs, si l’interface est complète, il faudra reposer sur la mémoire des utilisateurs, ce qui peut ne pas être une bonne idée. Voire même une très mauvaise, lorsqu’il y a beaucoup d’éléments à retenir.

Et comme dans Heavy Rain, il est important d’adapter les interactions possibles au device utilisé (comme par exemple la navigation danss les menus d’Assassin’s Creed qui utilisent une pseudo-souris).

En parlant d’interaction, les jeux comme World of Warcraft montrent bien l’importance du choix de la densité informationelle (en particulier avec les mods qui ajoutent des tonnes d’information à un écran déja trop riche).

Comment travailler sur ces éléments ? Avec des tests utilisateurs, tout simplement ! Pour les mener, c’est bien d’avoir des ergonomes. Mais c’est également possible assez simplement en filmant un utilisateur (visage et mains) ainsi que l’écran de l’ordinateur.

Par ailleurs, l’un des éléments importants d’une bonne interface (surtout en jeux vidéos), c’est de raconter une histoire que l’utilisateur va comprendre immédiatement (pour éviter ce que les amateurs de lecture SF nomment les infodumps). Tout ça expliqué grâce au créateur de Mario, qui en un sens est un des premiers UX designers.

Pour conclure, si vous voulez que votre produit soit aussi populaire que Mario, pensez simple et inspirez-vous du monde extérieur.

Mon avis

Le message était clair et la métaphore du jeu vidéo, si elle paraît facile, est néanmoins riche de sens (il n’y a qu’à voir le succès de StackOverflow)

Un abandon nécessaire

La semaine dernière, j’ai appris par des moyens inhabituels que Thalès organisait un concours Codingame. Donc je me suis inscrit, bien sûr.

Et comme d’habitude, je suis parti dans une implémentation basique en Java, avec une machine à états simple et un système multi-agent rudimentaire. Autrement dit, mon algorithme correspondait à ça

  • Tu as le drapeau adversaire ? Rentre dans notre base
  • Tu n’as pas le drapeau ?
    • Tu es le plus proche du drapeau enemi ? Va le chercher
    • Tu es le plus proche de notre drapeau ?
      • Il est sur un adversaire ? Poursuis-le et percute-le
      • Il est dans notre base ? Mets-toi entre lui et les adversaires

C’était naïf, et raisonnablement fonctionnel. Du coup je me suis mis en tête de l’améliorer. Et chaque modification que j’apportais le rendait un peu moins bon. Mais, à cause de l’hubris des développeurs, j’étais convaincu de tenir une solution améliorable. Résultat ? Mercredi soir, alors que j’implémentais un moteur d’évitement (lire un calcul géométrique basique), je me suis rendu compte que j’avais perdu du temps avec des raffinements inutiles alors que j’aurais clairement dû reprendre les choses de zéro et partir sur une solution plus intelligente.

Et je ne l’ai pas fait.

En fait, j’ai arrêté de coder histoire de réfléchir.

Parce que je n’ai de bons résultats à aucun jeu basé sur la géométrie continue, avec des trajectoires, des mobiles à inertie. Alors que quand la géométrie est discrète (façon bomberman ou hypersonic) j’ai des résultats intéressants. Pourquoi ?

Il s’avère que dans le second cas, j’ai un modèle d’implémentation de jeu que je peux « facilement » décliner. Mais je n’ai toujours rien dans le premier. Il me faut donc trouver une bonne intuition. En l’occurrence, j’ai la nette impression que modéliser cet environnement par un champ vectoriel serait une bonne idée. MAIS je ne veux pas discrétiser (c’est-à-dire découper le terrain en petits carrés). Parce que c’est long, et surtout parce que c’est moche.

Et comme je ne mets aucun espoir dans mes possibilités de victoire, je préfère travailler le style. Du coup il me faut quelque chose qui respecte mes envies de style. Et ces histoires de champ vectoriel, ça ressemble d’assez près aux équations de champ magnétique. Il va donc falloir que j’y jette un oeil sérieux. Mais ça, évidement, je ne peux pas le faire pendant un contest. Je vais donc mettre ce hackathon de côté et, quand j’aurais retrouvé la patate, je m’attaquerai de nouveau à un contest dont je ne suis toujours pas satisfait, bien que je sois gold : Coders Strike Back. En attendant, je vais me reconcentrer sur Code of Kutulu, pour deux très bonnes raisons

  1. Je vais le faire (mal sans doute) en Rust
  2. Ce contest sort pour une bonne partie de l’esprit de nmahoude, qui ne peut pas avoir eu une mauvaise idée

Jouons au Rust 4 – Simple fraction to mixed number … partie 3

Parfois, j’en ai marre.

Pas marre de l’informatique, hein, mais marre de buter dans certains problèmes.

Et en l’occrence, j’en ai eu marre de cette histoire de fractions pour lesquelles mon calcul de PGCD par la réduction en facteurs premiers n’était définitivement pas assez rapide. J’ai donc repris le bout de code en Groovy, qui utilisait une stupide recherche exhaustive. Et ça ne suffisait toujours pas : je bloquais à 87% des tests en ayant 100% des tests en succès. J’ai donc cherché sur le web les solutions, et je suis tombé sur cette solution en JS.

J’ai été en particulier choqué par le one-liner de calcul du PGCD :

var gcd = (a, b) => b === 0 ? a : gcd(b, a % b);

Là, franchement, j’ai bloqué. Comme je n’aime pas bloquer, un tour complémentaire m’a amené à la page Wikipedia de l’algorithme d’Euclide, puis sur un exemple de solution en Rust … que j’ai bravement copié/collé.

Vous trouvez ça mal ? Ben pas moi, parce que j’ai encore appris des choses, en particulier en mettant mon implémentation dans un module Rust pour isoler l’appel récursif.

En tout cas, le code final est raisonnablement correct, et vous pouvez y jeter un oeil sur GitHub. Et maintenant, je vais peut-être tenter autre chose … Mais je ne sais pas si je vais me lancer dans mon vrai projet ou faire encore une expérience Codingame ou autre …

Jouons au Rust 3 – Simple fraction to mixed number … partie 2

Dans le dernier article, j’écrivais que j’avais besoin de tests et de débug pour avancer.

Tester, c’est arrêter de douter

Pour le test, j’ai trouvé facilement ce que je cherchais dans cargo test, et c’est bien cool. Il y a toutefois un idiome à maîtriser pour éviter de flanquer des tests dans le code de l’application que j’ai trouvé dans le Reddit Rust. C’est en fait assez simple : dans le code applicatif, je déclare

#[cfg(test)]

mod test;

Et je crée un fichier qui s’appelle test.rs dans le même dossier. Dans ce dossier, le code applicatif correspond au super module (évidement, pour comprendre ça, il faut comprendre la visibilité du super-module Rust).

Et ça marche globalement bien.

Suffisamment en tout cas pour m’avoir permis de comprendre un bug, surtout quand j’ai activé l’affichage des sorties de test (parce que par défaut, Rust n’affiche pas le stdout des tests).

Débugger, c’est pas gagné

Je voulais corriger mes problèmes avec le débuggeur. Mais là, débugger du Rust sous Windows, ça ne semble pas gagné. Plus exactement, j’ai trouvé un paquet de guide pour débugger l’exécutable généré par le build Cargo, mais je n’ai pas trouvé grand chose sur le débuggage de tests. Du coup, j’ai posé la question sur Stackoverflow.

Et quand c’est trop lent ?

Malgré cette absence de débuggeur, j’ai quand même à peu près réussi à résoudre ce problème de réduction de fraction, jusqu’à ce que je me heurte à un problème de performance :

test::big_numerator_works has been running for over 60 seconds

Bon, en fait, il a tourné pendant vingt bonnes minutes sans aboutir à un résultat …

Alors là, j’aurais pu utiliser l’outil de bench de cargo. Ou alors j’aurais pu utiliser Criterion.rs qui évite d’utiliser Rust nightly. Malheureusement je n’ai pas vraiment réussi à les faire marcher. Je vais donc réessayer de configurer tout ça.

Bon, par contre, c’est déja trop tard, puisque j’ai au moins un bout de code qui ne répond pas dans les délais demandés par Codingame. Donc il me faudrait un profiler … Et le seul que je trouve génère des flamegraphs. C’est pas parfait, mais ça pourrait m’aider …

En tout cas, je n’ai pas fini d’apprendre !