Tron ou la tesselation de Voronoi

Je vais vous raconter un peu ma vie.

J’ai une fille qui va rentrer en septembre en classe prépa. Je trouve ça bien, parce que je suis passé par là, et que j’ai trouvé que c’était peut-être la meilleure période de mon éducation. Depuis que j’y suis passé, le monde a un peu changé, et on y fait maintenant des sciences de l’ingénieur, dont un peu de programmation. Or j’ai également un neveu en prépa, qui a reçu comme devoir de participer à un jeu Codingame multijoueur (bon, il a dû le faire en OCaml, que je ne connais pas du tout, mais là n’est pas le sujet). En l’occurence, il s’est inscrit à la tron battle. Comme le confinement, c’est un peu long, j’ai proposé à ma fille qu’on réfléchisse ensemble à ce problème. Avec toutefois un twist : je ne voulais pas spécialement lui apprendre un langage de programmation, mais plutôt comment retourner son cerveau et penser algorithmiquement. Parce que l’être humain, de base, ne pense pas algorithmiquement. Il pense via des heuristiques à la noix qui marchent dans les cas simples. Bref …

Nous nous sommes donc attaqués ensemble à ce problème.

D’abord, comprendre

Parce qu’il s’avère que la première difficulté de l’informatique, c’est de traduire un problème du monde physique en modèle informatique. En l’occurrence, transformer des coordonnées (parce que la grille de jeu de Codingame n’est pas indexée comme un graphique mathématique) lui a un peu fait mal au crâne. Par contre, une fois que c’était fait, nous avons pu implémenter une solution très naïve qui se contentait de ne pas rentrer dans les obstacles, ni d’ailleurs dans les traces laissées par les adversaires (et pour ça, il nous fallait maintenir une mémoire des cases déjà utilisées, ce qui nous a permis d’aborder les tableaux, les types de données, …). Et avec ça, nous avons déjà pu franchir les premiers niveaux.

Mais comment implémenter ?

Soyons clairs : ma fille n’est pas informaticienne, et il n’est actuellement pas prévu qu’elle le devienne. Je n’allais donc pas lui montrer du code Rust, mais plutôt celui d’un langage simple, compréhensible facilement … donc évidement du Python. Ce qui est bien, parce que ça m’a permis d’approfondir mes connaissances de ce langage.

Ensuite, faire parler le métier

Parce que finalement, ça n’était pas mon premier Codingame.

Je lui ai alors expliqué l’importance de pouvoir comprendre ce qui se passait. Une compréhension qui va au-delà de fournir simplement une ligne de debug pour atteindre le territoire magique des programmes auto-reproductibles. Autrement dit, j’ai implémenté dans le code de notre bot le mécanisme me permettant d’avoir le test correspondant sans effort. Ca m’a permis de découvrir le monde des tests en Python. Un monde plutôt sympa, en fait. Ecrire des tests, c’est facile avec pytest (encore plus quand vous l’utilisez pour lancer des tests unittest), il y a un mot-clé assert qui fonctionne bien, et vous pouvez aller plus loin

Enfin, améliorer les choses

Nous étions donc en bronze avec un code … trivial. Mais comment aller plus loin ?

En y réfléchissant un peu, l’objectif dans ce jeu, c’est quoi ? C’est de donner au bot une direction dans laquelle il reste encore beaucoup de cases disponibles. Autrement dit, de compter les cases disponibles dans chaque direction pour choisir la meilleure. Pour l’anecdote, nous avons compris ça simplement parce que notre bot, quand il arrivait contre un mur, choisissait la première direction disponible (le haut ou la gauche), ce qui le faisait parfois perdre très bêtement. En changeant ça, nous avons pu atteindre le bronze.

Ne pas trop en faire, c’est mieux

Bon, l’informatique, c’est une passion dévorante, pour ceux que ça passionne. C’est mon cas, mais ce n’est pas celui de ma fille. Et on l’a bien compris ensemble. C’est donc au moment du bronze que nous avons suspendu la collaboration.

Et maintenant, on réfléchit

Je ne vais pas dire que je n’ai pas réfléchi avant, mais c’était sur un autre axe : je cherchais à communiquer au mieux la nécessité de réfléchir sur un algorithme avant de penser à des lignes de code. Une fois seul, j’ai pu réfléchir en termes algorithmiques. Et je dois dire que j’ai passé 4-5 jours devant What are Voronoi Diagrams?, proposé dans les liens de Codingame. En fait, je ne voyais pas comment implémenter la chose. Quand enfin c’est devenu clair, j’ai codé, j’ai utilisé mes tests, et le résultat s’est fait sentir

A l’heure actuelle, ce n’est pas seulement le boss silver que j’ai battu, mais aussi le gold.

Je ne vais pas vous livrer une explication de la tesselation via l’algorithme de Voronoï, ni sur mon code, mais sachez que c’est puissant et rapide.

Conclusion

Je tire de cette petite expérience plusieurs enseignements

  • Communiquer, dialoguer sur un algorithme est invraisemblablement complexe. On a dû revenir à la méthode de la feuille de papier sur laquelle on gribouille nos idées. Mais c’est aussi très stimulant. Ma fille et moi avons beaucoup apprécié ces échanges.
  • Cette histoire de Voronoï me hante : je suis sûr que c’est une bonne solution au récent Spring challenge sur lequel je me suis brutalement cassé les dents
  • Coder en Python, c’est franchement facile tant qu’il y a peu de lignes de code. C’est à mon avis pour ça que cette solution en 78 lignes de code fait rêver.
  • Il ne faut pas oublier une chose : bien coder un bot codingame est une technique qui, comme toute autre, nécessite un apprentissage. Je ne suis pas arrivé Legend par hasard, mais plutôt parce que ce problème n’est pas mon premier : j’ai l’outillage technique et intellectuel nécessaire pour avancer vite et bien (même si je peux aussi me faire avoir)

Si vous voulez aller plus loin, le code est sur mon repository GitHub, et je suis sûr qu’il a bien des éléments critiquables.

Les réseaux sociaux sont-ils le cimetière de la pensée

(notez que je ne parle même pas de pensée critique, juste de pensée)

Ca n’est pas l’article le plus facile à écrire, mais c’est comme ça que c’est drôle, non ?

Bon, je vais faire un peu mon vieux con cinq minutes. Je fréquente internet depuis avant l’an 2000. A cette époque, il n’y avait pas de télé-réalité (c’est un peu loin du sujet, mais à mon sens connexe), il n’y avait pas non plus de Twitter/Facebook/Instagram/… Pourtant, tout le vocabulaire de la netiquette existait déja. On parlait déja de trolls, de flamewars, de bans, et autres. Le café du commerce se trouvait alors dans les newsgroups NNTP, qui ne servent maintenant plus qu’à télécharger des films (alors que c’est précisément un usage pour lequel ils sont atrocement mauvais), ou dans des forums phpBB. Mais ces outils restaient de l’ordre de la communauté privée.

Vers 2005, Twitter et Facebook ont été créés, et pour paraphraser Douglas Adams, je dirai qu’on peut commencer à imaginer que c’était globalement une mauvaise idée. Pourquoi ?

Pendant la bulle internet, on avait commencé à comprendre les concepts d’économie de l’attention, que le monde magique de la télévision monopolisait depuis sa création. Et on peut dire que ces réseaux sociaux ont donné, avec tout le talent qu’on connaît aux « petits génies de l’informatique » (ce terme me fait maintenant vomir), la vision la plus purement capitaliste de cette économie. En effet, ces réseaux sociaux ont fait partie des premières entreprises à être valorisées en fonction du nombre de leurs utilisateurs. Et vous connaissez cet adage qui dit que si vous définissez une métrique, quelqu’un essayera d’optimiser selon cette métrique ? Eh bien Twitter et Facebook, eux, le connaissent, et ont sciemment optimisé leurs algorithmes pour augmenter les utilisateurs en utilisant le meilleur des carburants : l’indignation. Parce que chacun de ses réseaux, et Youtube ensuite, manipulent la page d’accueil pour vous présenter un ensemble de contenus vous indignant, afin de renforcer la seule métrique qui compte : votre engagement.

Autrement dit, les « petits génies » sociopathes de la Silicon Valley ont utilisé la tendance naturelle de l’esprit humain à agir d’abord stupidement avant de réfléchir dans le but, tout-à-fait capitaliste de s’enrichir à titre personnel. Mais évidement, il y a des effets de bord. Le premier d’entre eux est de radicaliser les opinions. Le deuxième est de simplifier et de limiter la pensée : si la parole de votre cousin pratiquant de l’homéopathie a plus de poids que la consultation chez le médecin, comment pouvez-vous continuer à penser à l’intérêt d’une médecine basée sur la science ? Et si le monde entier s’intéresse à la fusée que lance un platiste (mouvement qui était inexistant avant l’arrivée d’internet), à un moment, il est normal que cette théorie reprenne du poil de la bête. J’ai pris les exemples typiques du dénigrement d’internet. Mais d’autres feront aussi bien l’affaire :

  • Une comédienne dit que la police est raciste, et paf les réseaux sociaux servent de caisse de résonance à la fachosphère.
  • Chaque raciste télévisuel a maintenant une seconde vie sur internet au nom de « la liberté d’expression »
  • Les états-unis élisent un troll, et personne n’est capable de le faire taire

Que faire ? Avant tout, je crois qu’il faut faire le ménage devant notre porte. Le mot « engagement » est une façon classique de renommer la volonté d’esclavagiser les utilisateurs. Et si vous pensez qu’il est important que vos utilisateurs restent sur votre site, vous avez tord. Ce qui compte, c’est que leur vie soit facilitée par votre logiciel. Et ça veut très rarement dire (sauf par exemple pour un contrôleur aérien) que votre utilisateur doit passer son temps devant son écran. En fait, je suis à peu près convaincu qu’il s’agit d’une anti-métrique : viser plus d’engagement, c’est forcément viser à rendre les utilisateurs captifs. Et si ça intéresse les investisseurs (parce que ça veut dire des données, ce nouveau plutonium), ça n’est sûrement pas intéressant pour la qualité des données métier de votre application.

Ensuite, ça veut aussi dire de changer ses modes de communication (ce que je ne trouve pas facile, mais néanmoins intéressant) pour arrêter de toxifier le monde : si vous voyez quelque chose qui vous indigne, mais que vous ne pouvez rien en faire d’autre que partager cette indignation, ne le faites pas.

Enfin, il faut sans doute commencer à réfléchir au monde qu’on veut, mais ça, ça dépend de vous.

Comment bien débugger ?

Comme Julia Evans écrit en ce moment un zine qui sera sans doute très chouette sur le debugging, je profite de l’opportunité pour communiquer ma vision de ce qu’est, ou plutôt de ce que doit être le debug. Et pour les collègues, cet article est issu d’une présentation que j’ai donné avec Elya il y a quelques années.

Commençons sereinement

La première chose à savoir au sujet des bugs, c’est qu’il n’existe pas de code sans bug. Parce que dans le fond, un bug, c’est quoi ? Le wikipedia (évidement que je vais citer la wikipedia, vous croyez quoi ?) nous dit que c’est un dysfonctionnement. La définition est parfaite, parce que dès le départ, elle se place du point de vue de l’utilisateur. Et c’est normal parce que, (retenez bien, c’est important pour moi), un logiciel est fait pour être utilisé. Et c’est l’utilisateur qui voit apparaître le bug.

Le fait que l’utilisateur voit le bug en premier n’est pas anodin, parce qu’un bug, en fait, c’est conceptuellement un effet de bord non maîtrisé du code que le développeur a écrit. En effet, si le développeur sait exactement et entièrement ce qu’il fait, le bug ne pourra pas apparaître (c’est, figurez-vous, l’argument de base des méthodes formelles et des langages qui en dérivent). Les bugs apparaissent donc toujours dans les creux du logiciel, les cas limite, les parties plus ou moins bien comprises. Les franges du système logiciel, en fait.

Nous allons donc maintenant voir ensemble comment résoudre les bugs, en appliquant les leçons des séries télé, mais pas que. Parce que souvenez-vous

La vie n’imite pas l’art, elle imite la mauvaise télévision

Woody Allen, Maris et femmes

Quels modèles choisir ?

Ou plus exactement, de qui s’inspirer pour résoudre un bug ? Un bug, avant tout, est un mystère. Il nous faut donc des personnes habiles à résoudre les mystères … comme Sherlock, ou House, … ou Marie Curie (croyez-moi, je ne peux pas ne pas parler de Marie Curie – vous saviez qu’elle est la seule personne … au monde … à avoir deux prix Nobel dans deux disciplines différentes ? – écoutez donc PodcastScience).

Mais pourquoi ces modèles ? Parce que nous utiliser des méthodes inspirées de ces modèles pour résoudre nos bugs.

Histoire de clarifier un peu, je pense qu’on doit utiliser les méthodes de l’enquête policière, de la recherche scientifique et du diagnostic médical pour identifier et corriger les bugs.

C’est quoi le processus de correction d’un bug ?

D’une manière assez classique, on peut distinguer ce processus en plusieurs phases

  • Découverte du bug par un utilisateur, par un log, ou même par un autre moyen
  • Identification du bug, cette phase où on passe de l’impression que ça ne marche pas à l’identification précise du composant, du code qui ne marche pas
  • Correction du bug , la modification du système logiciel pour qu’il n’expose plus ce comportement

Nous allons essayer de voir comment les méthodes citées précédemment peuvent nous aider dans chacune de ces phases.

Découverte d’un bug

Comment savez-vous qu’un bug est apparu dans votre système ? Vous ne le savez souvent pas, en fait. Si vous avez de la chance, vous aurez une erreur, une exception qui vous mettra sur la piste. Mais comme les bugs viennent des zones « creuses » de votre système logiciel, vous n’avez généralement pas de logs d’erreur et vous devez attendre qu’un utilisateur vous rapporte ce bug.

Votre utilisateur, généralement, se contentera de vous dire que « ça ne marche pas ». Et c’est là que les méthodes de l’enquêteur peuvent vous aider. En effet, recueillir un témoignage, comme c’est le cas ici, n’est pas aussi simple que de demander à l’utilisateur « qu’est-ce qui ne marche pas ? ». Il vous faut généralement reconstruire la séquence d’événements menant à ce bug. D’où la grande question « qu’est-ce que vous avez fait avant ? ». D’ailleurs, c’est l’étape durant laquelle nous avons la chance de bénéficier de spécialistes. En effet, chez les éditeurs de logiciels pour lesquels j’ai bossé, il y a toujours au moins un « responsable QA » (Geoffrey, Mélanie, des bisous) dont une partie du métier est précisément l’interrogatoire de ces utilisateurs pour n’en tirer qu’une chose : un cas reproductible minimal. Ce cas reproductible minimal, c’est le livrable de cette étape. Parce que c’est ce qui permettra ensuite aux développeurs de travailler sereinement

Mais que faire si les témoignages sont incohérents ?

D’abord, il ne faut jamais oublier ce que dit Gregory House

Tout le monde ment

Grégory House

Vos utilisateurs ne vous disent que rarement toute la vérité. Souvent, échouer à reproduire le bug indique que l’utilisateur ne racontait pas tout. Et c’est là qu’il faut s’appuyer sur les autres sources d’information (les logs, où qu’ils soient, l’état interne du système). A ce sujet, je me permets de vous rappeler que la seule raison d’exister des logs est précisément de vous aider à comprendre l’état de votre système au moment des bugs, quelle que soit la source de ces bugs. Si vous n’avez pas de bugs pour une partie du système et qu’un utilisateur rencontre un bug dans cette partie du logiciel, vous risquez fort de devoir ajouter ces logs rapidement pour comprendre ce que veut votre utilisateur (et c’est le moment où une intégration continue et un déploiement continu seront vraiment utiles). Donc, si votre utilisateur ne vous dit pas tout, lisez les logs …

Evidement, ça n’est même pas aussi simple. J’ai souvenir d’avoir déjà cherché un bug pendant quinze jours parce qu’il était faiblement reproductible. C’est-à-dire qu’il arrivait une fois sur dix.

Un enquêteur n’est pas un constructeur

C’est le moment idéal pour vous rappeler cette notion de base. Lorsque vous corrigez un bug (que vous cherchiez à le débusquer, à l’identifier où à implémenter une correction), vous n’êtes plus un développeur.

Un développeur, avant tout, c’est quelqu’un qui cherche à construire un logiciel. En ce sens, c’est un peu un maçon : il assemble des briques pour produire des fonctionnalités. Ca exige de la rigueur, de l’imagination, de la capacité à se projeter dans un état idéal du système.

Corriger un bug, c’est une enquête. Les qualités d’un enquêteur doivent être toutes autres. A mon sens, la première, c’est la pugnacité. C’est-à-dire l’envie de corriger le bug, quels que soient le temps, l’énergie et les moyens qu’il faudra y consacrer. Se questionner sur le fait d’abandonner la correction d’un bug ne doit pas être une option. C’est dur, parce que la personnalité des développeurs qui vise avant tout l’implémentation de nouvelles choses pousse parfois à choisir la voie de la facilité, du contournement. Lorsque vous corrigez un bug, vous ne devez jamais renoncer. L’abandon de la correction devrait à mon sens ne jamais être décidé par la personne en charge du bug, mais pas un arbitre différent.

Maintenant que je vous ai regonflé (ou pas), revenons-en à notre bug.

Un peu de paperasse

Lorsque votre utilisateur vous a rapporté ce bug, vous avez naturellement créé un ticket dans votre bug tracker (à mon avis l’outil le plus important du processus de développement d’un produit logiciel). Quel que soit le nom de cet outil, la fonction est la même : tracer les bugs rencontré, ainsi que la façon dont ils ont été corrigés (ou pas). Que les bugs soient corrigés ou pas n’est pas si important, en fait. Ca dépend de la nature du produit, de la philosophie de l’équipe concernant la qualité perçue, de la qualité des rapports de bugs. En revanche, il est essentiel d’y mémoriser tous les bugs du logiciels et ce qui en a été fait. Il faut juste, à mon avis, un peu de méthode. Dans un rapport de bug, on doit trouver

  • Ce que l’utilisateur a constaté, clairement identifié
  • Le contexte dans lequel le bug s’est produit (version de l’application, informations pertinentes sur l’utilisateur)
  • Les différentes théories, expériences, approches, qui ont été testées
  • L’approche de correction sélectionnée
  • Eventuellement la liste des nouveaux tests
  • L’impact de cette approche.

Vous avez vu comme ça ressemble aux ADR ? J’espère que ça aide à éclairer un peu mon propos à leur sujet. Normalement, à la fin de cette première phase de découverte, votre rapport de bug ne doit contenir que deux de ces choses

  1. Ce que l’utilisateur a constaté
  2. Le contexte dans lequel le bug s’est produit

Le premier point est, si vous avez de la chance, correctement écrit par l’utilisateur. Si vous avez un peu moins de chance, ou une organisation plus spécifique (par exemple un bug tracker public pour vos utilisateurs, et un bug tracker interne pour votre équipe de développement), cette partie est écrite par votre équipe QA (ou vous-même, si vraiment vous n’avez pas de chance). Ce point doit contenir le cas minimal reproductible.

Le second point est avant tout validé par la QA. C’est cette équipe qui a pris le temps de vérifier chaque version déployée (même si, comme vous n’êtes pas ignoble, vous avez tout fait pour les aider en exposant les versions des différentes briques de façon claire – pour la QA). Et si vous pensez que c’est sans intérêt … Rappelez-vous juste que ça vous permet de vous mettre sur le bon code source. Parce que débugger un autre code que celui que l’utilisateur a vu, c’est sans intérêt.

Donc, maintenant, notre bug est correctement découvert, identifions-le.

Identification d’un bug

Qu’est-ce que ça veut dire ? Tout simplement qu’il faut faire un lien entre le comportement constaté par l’utilisateur et le code source de l’application. Autrement dit, identifier ce qui est radioactif (pour prendre l’exemple de Marie Curie) ou la maladie donnant ces symptômes (pour prendre à nouveau celui de House).

Comment identifier un bug ?

Je vais prendre comme hypothèse que vous avez votre cas minimal reproductible et m’appuyer, pour une fois, sur un truc qui marche en informatique : les tests.

La première chose à faire, c’est écrire un premier test, au niveau de l’utilisateur, exposant le bug. C’est ce que je faisais il y a des années quand j’ai écrit gaedo, et croyez-moi, ça marche très bien. Parce que ce premier test va vous permettre de tester vos théories beaucoup plus rapidement.

Mais comment tester une théorie ?

Une théorie, c’est une hypothèse qui pourrait expliquer pourquoi le code se comporte de cette façon. Ce que dit la méthode scientifique, c’est qu’une théorie, pour être validée, doit être mise en valeur par une expérience. Et ça, ça nécessite trois étapes

  1. Expliciter cette théorie, c’est-à-dire l’écrire (évidement dans votre rapport de bug, afin de ne pas tenter deux fois d’expliquer le bug par la même théorie)
  2. Concevoir une expérience validant cette théorie. Attention, cette expérience ne doit valider que cette théorie. Elle va évidement prendre la forme d’un test unitaire plus précis que celui correspondant à ce qu’a observé l’utilisateur.
  3. Valider ou pas cette théorie par l’exécution du test unitaire

Si votre expérience n’est pas valide, c’est-à-dire si votre théorie concernant le bug est fausse, ça n’est pas grave. En fait, c’est même bien : ça veut juste dire que, comme House, vous avez écarté une cause possible du bug. Et c’est bien, parce qu’au bout d’un moment, quand vous aurez écarté toutes les mauvaises théories, il ne restera plus que la bonne.

La pugnacité, encore

Evidement, cette phase est la plus longue et la plus frustrante. Mais si vous la réalisez de cette manière, elle va vous apporter beaucoup de choses.

D’abord, vous comprendre beaucoup mieux votre système logiciel.

Ensuite, vous gagnerez en confiance en votre système logiciel. Parce que vous aurez essayé de le casser de multiples manières pour chaque bug que vous avez rencontré.

Enfin vous gagnerez en confiance dans la méthode. Parce qu’au début, vous aurez l’impression de perdre du temps à écrire tous ces tests. Mais de mon point de vue, cette méthode vaut dix fois mieux que TDD. Parce que vous construisez votre harnais de test autour de l’usage réel de l’application, et pas autour de l’usage imaginé par un PO ou (pire encore) un développeur. Je ne veux pas écrire qu’il ne faut pas faire de TDD. Je veux juste clarifier un point douteux : TDD est bâti autour de l’hypothèse que le PO et les développeurs connaissent l’espace réel d’utilisation de l’application. Mais cette hypothèse est démontrée chaque jour par tous les bugs du monde comme fausse. Justement parce que les logiciels ont des zones sombres, que les bugs et ces tests viennent éclairer.

On fait quoi de ces tests une fois le bug corrigé ?

J’ai déja vu des équipes supprimer les tests correspondant aux bugs saisis par les utilisateurs, au prétexte qu’ils ralentissent l’intégration continue. A mon sens, c’est la pire erreur de qualité qui puisse se faire. Ca revient à dire qu’il vaut mieux risquer de nouvelles erreurs pour livrer plus vite. En sachant que le gain espéré est souvent de moins d’une heure. Et quand bien même il faudrait une journée entière pour jouer les tests, c’est la meilleure politique qualité du monde, parce que ces tests correspond aux erreurs constatées dans le monde réel et qui ont été corrigées.

On a trouvé la bonne théorie expliquant le bug !

Parce que pendant qu’on parlait accumulation de tests, un débuggeur pugnace a pris le temps de tester différentes théories, de les noter dans le bug report, en a trouvé une qui expliquait correctement le bug, a implémenté un test l’expérimentant, et ce test donne le résultat attendu (c’est-à-dire qu’il plante quand le test utilisateur plante). Donc on peut le féliciter. Et surtout, on peut noter quelle est la bonne théorie dans le rapport de bug et commiter les tests associés.

Et on peut passer à la correction.

Correction d’un bug

L’avantage de cette méthode, c’est qu’elle munit rapidement votre code d’un ensemble de tests signifiants. Vous pouvez donc corriger votre bug de la manière la plus simple n’entraînant pas de régression par ailleurs. Et pour ça, je vous fait confiance, vous êtes développeurs, construire quelque chose avec un ensemble de contraintes est à mon avis assez familier à vos yeux. Je vais donc laisser cette partie de côté, surtout que c’est généralement celle sur laquelle insistent les docs de produits comme JUnit, TestNG, et tous les autres frameworks de tests.

Efficacité de la méthode

En guise de conclusion, j’aimerai rappeler pourquoi cette méthode est efficace.

Avant tout, comme toute méthode, elle offre un cadre. Et si avoir un cadre est souvent contraignant, c’est aussi très utile dans les situations délicates. Or corriger un bug est une expérience psychologiquement délicate : vous devez faire le deuil de certaines de vos illusions (comme par exemple croire que vous savez écrire du code libre de bugs, ou que vous livrerez votre produit dans les temps), vous êtes soumis à une certaine pression. Et ce sont précisément dans ces conditions que le cadre devient rassurant, parce qu’il va vous permettre de reconstruire une progression là ou vous n’en voyez initialement pas.

Ensuite, cette méthode s’appuie sur deux ou trois choses qui marchent : la méthode scientifique a, je pense, fait ses preuves. La méthode d’enquête également.

Enfin,c’est toujours ce schéma qui est utilisé par les équipes de développement, mais il n’est que très rarement explicite. Et c’est vraiment dommage, parce que ça permettrait à mon avis de restaurer une communication correcte (c’est-à-dire ni culpabilisante, ni infantilisante) autour d’un sujet toujours crispant.

Au bout de combien d’itérations un code est-il le bon ?

Suite aux précédents articles, j’ai récemment écrit un nouveau module de mon générateur de lifestream pour traiter les flux OML. Sur le papier, c’était une bonne idée … Donc je l’ai codé, et ensuite j’ai réfléchi. Et je me suis rendu compte que c’était une mauvaise idée.

Je ne vais pas vous expliquer pourquoi, parce que c’est de la technique assez basique, et franchement assez peu intéressante. Ce qui est plus intéressant, c’est la question sous-jacente.

En effet, j’ai découvert en participant à Codingame que ma première solution n’était jamais la bonne. Et par ailleurs, si vous regardez les repositories que je laisse traîner sur GitHub que c’est en fait également le cas des autres projets : pour que le code soit bon, il faut que je le réécrive plusieurs fois. En fait, j’ai découvert que le code était généralement bon après … au moins deux réécritures complètes. D’ailleurs, ça ne me dérange même plus de réécrire mon code après un certain temps. Je me dis en fait plutôt que le moment de la réécriture est le moment où j’ai suffisamment appris … ce qui n’est pas très rationnel, mais assez proche de ce que je ressens.

Et en fait, je me suis rendu compte avec un poil de tristesse que c’était aussi le cas du code que j’écrivais professionnellement … Un poil de tristesse, parce que reprendre le code trois fois, ça n’est pas très économique à court terme. Par contre, je sais que ces réécritures ne sont jamais des réécritures complètes : les morceaux stables (par exemple, les tests et les interfaces publiques) demeurent. De plus, si j’y réfléchis, c’est très proche de ce que permet, et même recommande, la méthode agile : utiliser chaque sprint comme une expérience, et en tirer toutes les conclusions nécessaires. Quitte à ce que l’une de ces conclusions soient « on recommence ».

Je rapproche ça de la construction de prototypes et de maquettes, méthode utilisée dans bien des domaines de l’ingénierie, avec toutefois la différence importante que le prototype devient parfois la version définitive (ce qui n’est le cas que pour le Concorde, en fait).

Seulement, je m’interroge : est-ce que je suis leu seul à avoir cette pratique de l’informatique ? Est-ce même une bonne pratique ? Je n’ai pas vraiment de réponse à cette question, mais je la trouve franchement intéressante, parce que je me demande vraiment comment un logiciel se construit « correctement » – si tant est qu’une réalité existe derrière ce terme.

Mais pourquoi tu fais ça, Nicolas ?

Mon dernier article était un mensonge.

Ou plutôt, une erreur d’interprétation : j’ai attribué à Twitter une erreur de Tweetledee. C’est moche. Heureusement, quand j’ai compris que j’avais fait cette erreur, j’ai été voir dans le code de Tweetledee … et j’ai corrigé l’erreur (et je vais pousser ça dès demain).

Si j’étais un peu sérieux, j’en ferai une illustration des biais cognitifs des développeurs. Mais là, ce soir, je veux juste dire que je me suis trompé.

Mais pourquoi tu fais ça Twitter ?

Je ne vais pas parler ici de l’horreur qui se développe outre-atlantique, je agrde ça pour un peu plus tard.

Non, je vais vous parler d’un problème très personnel. Vous savez que Twitter a récemment changé d’interface pour un truc plus fischer-price (des gros boutons, des couleurs voyantes). Comme ça quoi

C’est beau, c’est simple

Ah pardon, on me signale que je me suis trompé, c’est plus comme ça

Bon, pas toujours, parce que quand je lis un tweet depuis tweetledee + rrss2imap, le tweet est comme ça dans Thunderbird

Avouez que c’est d’une sobreté de bon aloi

Mais quand je clique sur le lien indiqué dans l’URL, ça donne ça

Il manque un ou deux trucs, non ?

Bon, tout est dit, non ?

Et si je regarde dans ce super site (wheregoes) que j’ai découvert il y a peu, ça donne ça

Et ce qui est fou, c’est que si j’ouvre directement la dernière page, le tweet est complet ! Alors c’est quoi l’intérêt de cette manoeuvre ? A qui profite le truc ? Je ne comprend pas. Si quelqu’un a le moindre début d’explication, je vous laisse parler.

Par contre, je sais déja que je vais aller regarder dans le code de Tweetledee comment faire pour qu’il m’ouvre directement l’url finale, parce que franchement, atterir sur des tweets tronqués, ça ne m’intéresse pas trop.

Cette histoire de flux devient vraiment intéressante …

Donc, suite à l’article d’hier, j’y ai réfléchi … un peu plus.

J’ai donc d’un côté un fichier OPML assez frustre généré par rrss2imap (et en fait généré toutes les nuits). Ce fichier ressemble à ça

    <outline title="RSS/work" text="RSS/work">
      <outline xmlUrl="http://feeds.feedburner.com/GeekAndPoke" type="rss" text="http://feeds.feedburner.com/GeekAndPoke" />
      <outline type="rss" text="https://blog.codinghorror.com/rss/" xmlUrl="https://blog.codinghorror.com/rss/" />
      <outline xmlUrl="https://what-if.xkcd.com/feed.atom" type="rss" text="https://what-if.xkcd.com/feed.atom" />      <outline xmlUrl="http://tumourrasmoinsbete.blogspot.com/feeds/posts/default" type="rss" text="http://tumourrasmoinsbete.blogspot.com/feeds/posts/default" />
      <outline xmlUrl="http://strangepaths.com/feed/fr/" type="rss" text="http://strangepaths.com/feed/fr/" />      <outline xmlUrl="http://feeds.feedburner.com/SociologicalImagesSeeingIsBelieving" type="rss" text="http://feeds.feedburner.com/SociologicalImagesSeeingIsBelieving" />
      <outline type="rss" text="https://informationisbeautiful.net/feed/" xmlUrl="https://informationisbeautiful.net/feed/" />      <outline type="rss" text="http://abstrusegoose.com/feed" xmlUrl="http://abstrusegoose.com/feed" />
      <outline text="https://taoofmac.com/rss" type="rss" xmlUrl="https://taoofmac.com/rss" />
    </outline>

Ayant moi-même écrit le code Rust qui génère ça, je sais précisément pourquoi c’est aussi frustre. Mais en tant qu’utilisateur, je trouve assez laid de vous balancer ça dans les dents.

Et comme j’ai déjà en projet un super outil de lifestream (qui commence à marcher efficacement, mais lentement), je me suis dit que la meilleure chose à faire serait d’améliorer cet export avec un titre, des infos de rafraîchissement, et une description, qui pourrait être tirée de Shaarli avant de prendre cet export pour en faire un fichier Asciidoc que je mettrais ensuite dans mon lifestream. Si vous vous dites que c’est inutilement complexe … vous avez peut-être raison, mais peut-être pas.

Parce que franchement, lire un fichier OPML, rajouter des infos, ça m’a pas l’air bien compliqué. En fait, ça m’a l’air totalement faisable … en Groovy ! (et vous savez comme j’aime ce langage de script). Et générer un fichier Asciidoc avec … c’est une simple histoire de XSLT, non ? Et en plus, je peux mettre tout ça dans un profil Maven. Et ça, c’est vraiment chouette.

Allez, on va essayer ça, ça va être marrant cinq minutes !

Faut faire le ménage

Dans la suite des articles précédents, j’allais naïvement m’engager dans une liste à la Prévert des flux RSS que je suis, quand je me suis rendu compte de deux choses

Bon, ça, c’est la première chose : j’ai beaucoup de flux qui traînent. Parce que la deuxième, un peu moins visible, mais néanmoins évidente une fois que je regarde les logs de rrss2imap, c’est qu’un nombre certain (mais pour l’instant inconnu) sont en fait morts.

[2020-05-25 10:00:01.553545 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 1/91 from https://xkcd.com/rss.xml[2020-05-25 10:00:01.766933 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-05-25 08:00:01 while previous read date is 2020-05-22 04:00:00[2020-05-25 10:00:01.784650 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 2/91 from http://bricablog.net/dotclear/index.php/feed/atom[2020-05-25 10:00:02.243409 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2018-03-08 17:37:08 while previous read date is 2018-03-08 19:37:08[2020-05-25 10:00:02.245046 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 3/91 from https://moijuliettef.wordpress.com/feed/[2020-05-25 10:00:02.554085 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2017-10-05 22:35:23 while previous read date is 2019-03-20 18:51:36[2020-05-25 10:00:02.555533 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 4/91 from http://www.linesandcolors.com/feed/[2020-05-25 10:00:04.247961 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-05-14 21:05:55 while previous read date is 2020-05-14 20:59:44[2020-05-25 10:00:04.249122 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 5/91 from http://manchu-sf.blogspot.com/feeds/posts/default[2020-05-25 10:00:04.563142 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-05-23 07:38:34.091 while previous read date is 2020-05-20 19:52:15.710[2020-05-25 10:00:04.567645 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 6/91 from https://margauxmotin.typepad.fr/margaux_motin/rss.xml[2020-05-25 10:00:05.250799 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2018-03-02 20:33:46 while previous read date is 2018-03-02 20:33:46[2020-05-25 10:00:05.251818 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 7/91 from http://zepworld.blog.lemonde.fr/feed/[2020-05-25 10:00:05.600096 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2018-04-17 16:35:44 while previous read date is 2018-04-17 16:35:44[2020-05-25 10:00:05.601766 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 8/91 from http://feeds.feedburner.com/zenpencils[2020-05-25 10:00:05.731067 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-03-12 01:57:47 while previous read date is 2019-10-07 07:17:29[2020-05-25 10:00:05.732688 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 9/91 from http://fr.rec.arts.fantasy.narkive.com/rss[2020-05-25 10:00:06.177723 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-05-25 08:00:06 while previous read date is 2019-12-01 09:00:09[2020-05-25 10:00:06.182928 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 10/91 from http://fr.rec.arts.sf.narkive.com/rss[2020-05-25 10:00:06.602247 +02:00] INFO [rrss2imap::feed_reader] src/feed_reader.rs:65: Feed date is 2020-05-25 08:00:06 while previous read date is 2020-04-21 16:35:30[2020-05-25 10:00:06.616145 +02:00] INFO [rrss2imap::feed] src/feed.rs:87: Reading feed 11/91 from http://generationscience-fiction.hautetfort.com/atom.xml[2020-05-25 10:00:07.907775 +02:00] ERROR [rrss2imap::feed] src/feed.rs:101: Content ar http://generationscience-fiction.hautetfort.com/atom.xml is neither Atom, nor RSS Could not parse XML as Atom or RSS from input.TODO check real content type to help user.

Là, par exemple, sur dix flux, je pense que seuls deux ou trois ont encore un contenu à jour.

Donc avant de pouvoir donner une liste de trucs intéressants à lire, il va falloir que je fasse le tri dans cette liste (ou plutôt que je vous donne le reader’s digest, sans les trucs vraiment à la noix). Ce qui me fait d’ailleurs penser que je dois faire la même chose dans mon Shaarli, qui doit être plein à craquer de vieux sites morts … Et ce qui me fait à nouveau penser à une idée délirante que j’ai eu à un moment : faire de mon Shaarli une espèce de réservoir de liens multi-usages : si j’annote un lien avec @for_rss2imap, j’écris un simple script qui génère le fichier OPML à partir de cette catégorie, et j’ai une belle mémoire bien propre.

Je pense que je vais mettre ça dans mes idées de développement à la noix (idées qu’il faut d’ailleurs que je retravaille, parce que je crois que pour l’instant, ça n’a aucun support autre qu’un quelconque « @… » dans Shaarli). Mais rien de tout ça ne vous aide, en fait …

Comment exploiter ces informations ?

Cet article fait suite à celui concernant l’ingestion d’informations.

Maintenant que nous avons parlé de ce que ça impliquait de lire des tonnes d’articles, il faut aussi réussir à en faire quelque chose … Parce que sinon, vous vous retrouvez à devenir une espèce de monsieur je-sais-tout un peu chiant (à ce sujet, je fais partie des interdits de Trivial Pursuit et autres jeux basés sur les connaissances par ma famille – tant mieux, parce que je trouve maintenant ça un peu vain – oui, c’est extrêmement prétentieux, mais hélas vrai).

Un peu d’histoire

Il y a vingt ans, quand j’ai commencé dans ce métier, je faisais comme tout le monde à l’époque et je mettais tous les sites que je réutiliserai dans les signets de mon navigateur, en abandonnant ceux qui ne me serviraient pas … Et ça n’était pas vraiment efficace : changer d’ordinateur, c’était perdre une partie de sa mémoire tant qu’on n’avait pas importé les signets du navigateur précédent … (souvenez-vous que Dropbox et autres n’existaient pas …).

Lors de la première bulle internet, un site vraiment génial appelé delicious a été imaginé. Ce site, c’est un peu comme les signets de votre navigateur, mais organisés par des tags au lieu d’être organisés dans des dossiers. Et franchement, les tags, à l’époque, c’était la révolution qui suffisait à faire financer faramineusement votre startup (et par faramineusement, je veux dire carrément 1 MILLION d’euros). Donc, dans delicious, vous associez au lien un descriptif, et des mots-clés. Vous y mettez ce que vous voulez, et ça vous suffit. C’était vachement bien. J’en ai donc mis des tonnes : dès que je tombais sur un site un tant soi peu intéressant, paf, dans delicious, avec les tags qui vont bien. Au début, je laissais la description imaginée par delicious …

Et puis delicious a été racheté/démonté par Yahoo. A l’époque, ça a été un choc. Heureusement que je connaissais déjà Shaarli, parce que j’ai pu migrer vers cette solution, qui collait alors avec mes souhaits de revenir vers une solution auto-hébergée (parce que j’ai découvert à cette époque grâce à delicious et d’autres applications web que les services commerciaux ont une durée de vie inférieure aux êtres humains, et pour le coup, ma mémoire, j’y tiens).

Mais qu’est-ce que ça veut dire ?

Ce que ça veut dire, c’est que, comme j’ai écrit dans le premier article de cette série, il faut utiliser l’ordinateur pour ce à quoi il est bon, et l’humain pour ce à quoi il est bon.

Que sait faire l’ordinateur ? Mémoriser et organiser. C’est pour ça que je stocke tous les sites un tant soi peu sympa dans Shaarli, avec des tags que je définis selon des règles qui me sont propres.

Que sait faire l’humain ? Inférer, être flou. Et c’est pour ça que, depuis delicious, j’ai remplacé le texte de description automatiquement écrit par ce que je pense sans censure (d’où une série de liens très chouettes sur YAML). De façon à ajouter aux faits que contiennent les tags des impressions que sont ces descriptions.

De cette manière, normalement, si je me débrouille bien, je peux ressortir la plupart des liens assez rapidement. Et si j’ai besoin d’un peu plus de largeur de vue, j’ai toujours mon lifestream qui m’offre le même type de recherche par tag …

Il manque un truc …

En vérité, en écrivant tout ça, j’ai l’impression qu’il manque un truc : autant l’ingestion que la restitution de ces informations me paraît tomber sous le sens. Alors pourquoi est-ce que des gens très intelligents me demandent comment je fais ?

Comme je suis maintenant un peu vieux, et peut-être assez sage, je vais me permettre un avertissement : je vais ici ne faire preuve d’aucune espèce de modestie. Bon, ceux qui me connaissent physiquement savent à quel point c’est un défaut qui m’est habituel … Donc il savent. Pour les autres … désolé.

Donc je pense que l’élément manquant est la connexité du graphe de connaissances que vous avez en tête : si vous êtes capables de faire un lien entre, par exemple, la conquête spatiale et le sexe (merci Yann Minh) ou, pour donner un exemple moins scabreux, le cyberpunk et le bitcoin, c’est parce que vous connaissez assez bien les deux notions mentionnées pour imaginer comment elles s’articulent. Comme bien des choses, c’est une compétence, et même une compétence très utile dans les métiers de l’ère de l’information. Et c’est mon avis le truc important qui permet de créer à partir des connaissances ingérées des hypothèses intéressantes. Comment la travailler ? Simplement en ingérant plus de connaissances différentes : intéressez-vous aux arts, aux sciences sociales, aux activités physiques louches, bref, à tout ce qui est un peu à la frange, parce que c’est à la frontière de l’inconnu que se créent les nouveautés.

Pour conclure cette courte série, je vous parlerai plus en détail de mes sources d’information la semaine prochaine … Je vais essayer de faire un truc marrant de cet annuaire.

Comment ingérer de l’information en masse

Cet article fait suite à Comment ingérer et retranscrire des informations en masse ? et va détailler la partie entrée de mon système d’information.

Parce que de l’information, à l’ère de l’information, il en faut.

Concepts

J’ai donc, comme tout le monde, un système de lecture de divers sites web. Comme je ne suis plus tout jeune, il s’appuie techniquement sur des flux RSS et un Raspberry, évidement, et conceptuellement, sur des idées aussi idiotes que

  • M’exposer à la diversité,
  • Toujours garder de la place pour l’art,
  • Préférer la profondeur à la largeur
  • Si ça m’intrigue, je creuse

Et sur les non-buts suivants

D’abord, je ne veux pas de bulle de filtrage. Je suis déjà assez solipsiste par nature ne pas laisser un algorithme décider à ma place de ce qui va m’intéresser. Par ailleurs, ces algorithmes font une chose que je ne veux absolument pas : encourager mes instincts face à ma réflexion. Je me rends bien compte qu’il y a une forme de schizophrénie à écrire ça tout en utilisant Twitter. Mais d’une part je choisis très précisément la forme de ma bulle Twitter, et d’autre part, les outils que j’utilise ne m’affichent pas la timeline, mais bien tous les tweets de cette bulle. Et surtout, ça n’est qu’une de mes sources, sans doute la plus inégale, d’ailleurs.

Ensuite, je ne cherche pas à simplifier, ni à avoir des résumés ou des versions courtes. Parce que je sais lire vite (Goodreads vous le montrera bien mieux que moi). Et on ne va pas se mentir, pour ingérer de l’information, lire vite est un prérequis. Comme d’autres choses, c’est une compétence, qui peut être cultivée (et très facilement) : trouvez un genre littéraire, quel qu’il soit, qui vous plaît, et lisez tout ce que vous aimez. Vous verrez votre rythme de lecture augmenter dans tous les domaines. Et je le répète, lire rapidement (et comprendre rapidement ce qu’on lit), est à mon sens un prérequis à l’ingestion d’information.

Enfin, je ne veux pas utiliser de navigateur comme source de lecture. Il y a à ça une raison fonctionnelle, et une raison pratique. La raison fonctionnelle, c’est que je ne veux pas voir la mise en page changer à chaque article. Et malheureusement, le mode lecture des navigateurs n’offre pas à mon sens le niveau d’isolation que je recherche. La raison technique, c’est qu’un navigateur nécessite du réseau synchrone, quand un mail nécessite du réseau asynchrone, et permet bien plus facilement d’exploiter son temps.

Vous voulez vraiment parler de technique ?

Sur la partie technique, tout est détaillé dans cet article : Mais qu’est-ce que je fais de mon Raspberry la partie qui vous intéresse est celle qui contient RSS-Bridge (pour les sites comme GQMagazine qui offrent des flux RSS tronqués), rrss2imap et Tweetledee. Ensemble, ces trois mini-logiciels me permettent de recevoir tout ce que je veux dans ma boîte mail, et de faire la relève de ces flux RSS toutes les deux heures précisément.

Mais ça se passe comment ?

Parce qu’avec tout ça, je reçois environ 200/250 messages par jour. Oui, ça fait 250 mails, et franchement, c’est plus une solution qu’un problème.

Donc tous les matins, à partir de 8H30, je fais une première passe dessus : j’élimine tout ce qui n’a aucune chance de m’intéresser (les annonces de nouveaux frameworks, l’essentiel du show politique, les utilisations de twitter comme hotline). Quand cette première passe est finie, il me reste en général moins d’une cinquantaine d’articles. Ceux-là, je les parcours. Autrement dit, j’ouvre la page web, je regarde rapidement si ça peut m’intéresser. Si ça n’est pas le cas, j’élimine. Il faut noter qu’un article important réapparaîtra forcément. Du coup, si vous le virez une fois, mais que vous le revoyez poindre par un autre canal, peut-être bien qu’il est important … Après ce parcours, il ne reste vraiment plus grand monde : en général, moins d’une dizaine d’articles que je vais lire tranquillement dans la journée. Et lors de cette lecture, je passe à la deuxième partie du traitement : le stockage et la restitution, qui sont isolés et seront décrits dans un autre article.

Un autre avis ?

Si vous voulez une autre opinion sur la raison pour laquelle les flux RSS sont très chouettes, lisez donc cet article : It’s Time to Get Back Into RSS