Analyser les erreurs

Comme tout ce qui n’est pas testé ne fonctionne pas, tout développeur a forcément des erreurs à corriger dans son code ; je laisse la démonstration de cette assertion au lecteur. D’après mon expérience, la capacité à bien utiliser les outils à sa disposition pour analyser les erreurs dans son programme est un des facteurs ayant le plus d’impact sur la rapidité des développeurs à livrer une application opérationnelle, d’autant plus pour les applications webs qui sont constituées de nombreuses couches de code interagissant les unes avec les autres. Sans prétendre à l’exhaustivité, cet article va vous donner les quelques pistes à explorer pour accélérer le processus d’analyse.

RTFL! (Read the Fucking Logs!)

De très nombreuses bibliothèques, frameworks et autres environnements d’exécution comme les navigateurs internet ou les machines virtuelles – et même les systèmes d’exploitation eux-mêmes – ont la politesse de créer des journaux dans lesquels on peut trouver des informations sur l’exécution des programmes. Rien n’est plus exaspérant pour un référent technique comme moi que de voir arriver un développeur coincé, de lui demander « que vois-tu dans les logs ? » et de s’entendre répondre « je ne sais pas, je n’ai pas regardé… ». Voici une liste de journaux utiles.

Notre framework utilise log4net de l’Apache Software Foundation pour journaliser ses opérations ; par exemple, en mode ERROR, toutes les requêtes SQL provoquant une exception sont écrites dans le journal, et en mode DEBUG, toutes les requêtes y sont écrites. Si vous souhaitez ajouter une journalisation à vos programmes, je vous conseille log4net et ses équivalents sur d’autres plateformes, l’ancêtre log4j, log4php, etc. qui sont peu invasifs, performants, flexibles et possèdent de nombreuses méthodes d’écriture (fichier, journal d’évènement sous Windows, email, console, bases de données, trace ASP.NET, socket, etc.).

PHP peut afficher les erreurs dans la sortie HTML, ce qui est une très mauvaise idée pour des raisons de sécurité ; du coup, les administrateurs désactivent généralement complètement la journalisation des erreurs, alors qu’elles peuvent être très facilement envoyées vers un fichier précis ou vers les journaux système. Quand je débarque dans un code PHP inconnu, je commence généralement par activer la sortie des erreurs, et là c’est festival avant même d’avoir commencé à corriger les problèmes qu’on m’avait soumis !

Sous Windows, le journal d’événements est une mine d’or d’informations pour le débogage. Les services du système d’exploitation y écrivent toutes leurs erreurs, par exemple IIS ou le service de relais SMTP qui y met les messages d’erreur des serveurs SMTP distants. La machine virtuelle .NET y journalise les exceptions non interceptées avec la pile d’appels au moment de l’erreur. L’onglet « Sécurité » contient les erreurs d’authentification et, encore plus intéressant, les traces des audits d’accès aux ressources. Ce dernier outil, assez méconnu, est un don du ciel quand vous ne comprenez pas un problème d’accès à un fichier ; en effet, plus les problématiques de sécurité se font prégnantes, plus les systèmes d’exploitation ont tendance à faire exécuter les programmes par des profils à faibles autorisations, voire à ne pas charger totalement les profils – une spécialité de Windows. Si vous souhaitez comprendre pourquoi vous n’avez pas accès à tel ou tel fichier, vous devez effectuer les opérations suivantes :

  • cibler la ressource
  • activer l’audit sur la ressource (pour un fichier ou un répertoire, aller dans ses propriétés, onglet Sécurité, cliquer sur Avancé puis aller dans l’onglet Audit et activer les audits utiles)
  • activer l’audit sur la machine ; pour cela, aller dans Stratégie de sécurité locale dans les Outils d’administration, déplier Stratégies locales puis Stratégies d’audit, et activer les échecs et/ou les réussites sur la catégorie qui vous intéresse
  • réitérer la tentative d’accès
  • lire le journal Sécurité, dans lequel vous saurez quel utilisateur a tenté avec ou sans succès à la ressource, depuis quel programme, etc.
  • une fois les problèmes réglés, désactiver les audits pour éviter de graver le journal pour le plaisir

Les systèmes de gestion de bases de données relationnels peuvent, en fonction de leur configuration, écrire des traces des requêtes erronées – configuration par défaut de PostgreSQL – ou des requêtes coûteuses – configuration par défaut de MySQL. Ils supportent tous l’instruction EXPLAIN donnant le plan d’exécution, ont des outils de trace avancés, tiers ou natifs, capables de proposer des index pour accélérer les requêtes.

Les navigateurs internet modernes ont des outils pour les développeurs qui auraient fait baver le petit François à ses débuts de développeur web en 1997 : console avec toutes les erreurs, suivi de variables javascript, débogueur avec points d’arrêt et instruction d’entrée dans le débogueur (debugger), liste de règles CSS appliquées à un élément et possibilité de tester des modifications sur icelles, liste des ressources chargées avec source du chargement, temps d’attente du premier octet, temps de téléchargement, en-têtes HTTP en entrée et en sortie, remis en forme indentée des fichiers javascript compressés, manipulation du code HTML, simulation de résolutions tierces et d’interfaces utilisateur tactiles…

Les débogueurs modernes peuvent prendre la main sur un programme déjà lancé, sur la machine locale ou même sur une machine distante, en s’attachant à ce programme, en dehors de leur capacité bien connue de lancer un programme directement en mode débogage.

Et même quand vous n’avez pas accès à la machine, localement ou à distance, vous pouvez demander à l’utilisateur de faire un export mémoire exploitable par votre débogueur, par exemple avec procdump et Visual Studio pour Windows, natif ou .NET.

En bref, avant quoi que ce soit d’autre, RTFL!

Le mille-feuilles de l’informatique distribuée

Très longtemps, les programmes informatiques se sont exécutés sur une machine unique, sans collaboration avec d’autres ; au pire, on avait affaire à un serveur tout-puissant et un terminal d’affichage stupide.

Aujourd’hui, avec les développement des réseaux, le gros des applications d’entreprise et même grands public distribuent les tâches à plusieurs ordinateurs collaborant pour rendre le service attendu. C’est en particulier le cas du développement web, où vous avez au minimum un serveur manipulant des données de référence pour les rendre intelligibles et modifiables par un client exécutant l’interface utilisateur dans un navigateur web. Le cas général  comprend côté serveur des systèmes de stockage de données ayant leur propre langage, SQL ou non, un serveur web pour gérer les connexions réseau, une plateforme logicielle intégrée au serveur web pour tout lier, et côté client du code HTML et CSS définissant l’apparence des écrans et du code javascript pour gérer l’interaction avec l’utilisateur.

En cas de bogue, la couche dans laquelle il survient est rarement difficile à trouver, même si certaines erreurs réseau peuvent être un peu plus vicieuses – comme les validations de certificats SSL. Par contre, il peut s’avérer nettement plus compliqué de déterminer dans quelle couche la correction doit être effectuée : si la reptation jusqu’au client d’une donnée stockée dans une base relationnelle provoque une erreur dans le code javascript, par exemple une « ‘ » non échappée dans une chaîne de caractères, l’erreur se manifeste dans le code javascript exécuté sur le poste du client, alors que la correction à apporter doit l’être dans le code serveur le générant – et pas dans la base, dont les données doivent être agnostiques de la façon dont elles seront utilisées.

Il n’existe pas de règle s’appliquant à toutes les architectures distribuées pour débusquer ce genre d’erreurs, mais en être conscient est déjà un début de solution.

Utiliser les moteurs de recherche

Quand j’ai commencé à programmer, internet n’existait pas pour le grand public ; nous n’avions comme seules ressources que la documentation du langage – 700 pages sur papier bible pour Turbo Pascal 5.5 – et les articles de magazines et livres que nous pouvions trouver en français, autant dire pas grand chose.

Aujourd’hui, il est rare de tomber sur un problème dont personne n’a publié la solution sur internet, mais encore faut-il savoir comment chercher.

Première règle : chercher en anglais. On peut hurler à l’hégémonie anglo-saxonne autant que l’on voudra – j’écris en français volontairement pour créer du contenu francophone sur l’informatique – malgré ses 275 millions de locuteurs, notre langue est loin d’être la plus présente sur internet. Si votre message d’erreur est en français – ou dans n’importe quelle autre langue – traduisez-le du mieux que vous pouvez ; les systèmes de suggestion automatiques peuvent vous aider, et certains services existent pour certaines plateformes. Petit à petit, à force de parcourir les documentations et forums en anglais, vous acquerrez le vocabulaire ad hoc. En désespoir de cause, pour des plateformes traduisant les messages d’erreur en utilisant les paramètres régionaux comme .NET ou Java, vous pouvez forcer la langue d’exécution du programme pour obtenir le message d’erreur en anglais.

Deuxième règle : même si vous cherchez sur un site précis, n’utilisez pas la recherche intégrée du site, utilisez votre moteur de recherche préféré et sa fonctionnalité de limitation à un nom de domaine. Google ou Bing indexent mieux les sites que les sites eux-mêmes, et ils supportent la notation site:nomdedomaine.tld. De toutes façons, les meilleures ressources en dehors des documentations officielles, comme stackoverflow.com ou codeproject.com, sont par nécessité très bien construits pour les moteurs de recherche.

Troisième règle : si le message d’erreur ne donne pas de résultat, passer aux noms des fonctions employées assortis de mots clés correspondant à l’erreur et du langage de programmation ou la plateforme – .NET et Java par exemple ont tendance à avoir des noms d’objets assez semblables – et ça vous évite aussi les pages visant le grand public plutôt que les développeurs – les utilisateurs aussi voient des messages d’erreur. Les noms de méthode dans la pile d’appel peuvent aider à cibler plus précisément la recherche.

Enfin, si jamais vous résolvez un problème sans en passer par internet, ou après une longue recherche et un croisement de plusieurs ressources, rendez la solution disponible pour les copains !

Mono, Postgresql et UTF-8

Nous avons déployé récemment notre première application métier sur une plateforme Linux / Apache / Mono / Postgresql sur un serveur tiers, et nous avons eu un problème pas très facile à diagnostiquer et dont je vais partager la solution au cas où cela serve à quelqu’un.

La base de données postgresql était bien configurée en UTF-8, le paramètre serveur « client_encoding » était bien configuré en UTF-8, mais le site persistait à nous afficher les accents de la base avec des « ? », et de même, à l’enregistrement, les accents se transformaient en « ? ». Nous avons regardé la documentation de Npgsql, le driver .NET Postgresql, où nous avons trouvé un paramètre « Encoding » mais déclaré obsolète et comme valant toujours unicode. Nous avons fait exécuter « SHOW client_encoding » qui doit renvoyer la valeur du paramètre pour la session, et avons reçu « UTF-8 ».

Finalement, nous avons trouvé une documentation Npgsql chez Mono qui conseillait d’utiliser le paramètre Encoding avec la valeur UNICODE si on avait des problèmes avec UTF-8 (attention, UNICODE en respectant les majuscules !). Et effectivement, en rajoutant Encoding=UNICODE dans la chaîne de connexion, les « ? » sont redevenus des caractères accentués.

Résumons : la base est en UTF-8, la valeur par défaut pour le codage de caractères de la connexion est UTF-8, la connexion est bien en UTF-8, mais le driver Npgsql embarqué par Mono s’embête à saloper toutes les chaînes avec une option déclarée comme obsolète par les développeurs de Npgsql eux-mêmes… Merci pour ce moment !

Un bon framework

Avertissement : je suis l’architecte et l’auteur principal du framework de développement d’applications web et mobiles de Yoocan ; assez logiquement, les idées développées dans cet article correspondent aux principes architecturaux mis en oeuvre dans celui-ci.

Définition

En dehors des cas simples – en termes d’architecture – il est rare de démarrer le développement d’une application de zéro ; en général, on s’appuie sur une structure, un cadre prédéfini, qu’en informatique on nomme d’un mot anglais, framework, qui se traduit par cadre de travail. Des termes français comme « structure logicielle » ou « cadriciel » existent, mais sont peu usités. Un framework est un objet composite visant à simplifier et accélérer le travail de développement : il impose un plan d’architecture général appuyé sur un ensemble de patterns – ou patrons logiciels – et de bibliothèques standards.

L’utilisation d’un framework apporte de nombreux gains :

  • le partage de tâches communes et fastidieuses à développer à chaque nouvelle application : analyse des paramètres d’entrée, contrôles graphiques prêts à l’emploi, etc.
  • des garanties en termes de sécurité, en empêchant le développeur de faire des erreurs communes : injection SQL, cross-site scripting, buffer overflow, etc.
  • des garanties en termes de conformité de fonctionnalités standards vis-à-vis de règles métier, juridiques, techniques : respect des règles comptables, de lois physiques, etc.

La contrepartie réside dans le cadre imposé, et son degré de rigidité, ce qui limitera votre liberté d’agir ; j’y reviendrai.

Un framework peut être plus ou moins spécialisé :

  • le .NET framework ou la plateforme Java permettent de créer pratiquement tout type d’application, du petit utilitaire en ligne de commande au mastodonte distribué, à l’exception des logiciels très proches du métal comme les pilotes matériel
  • CodeIgniter ou Symfony, tous deux basés sur PHP, sont des frameworks adaptés au développement de tous types de site internet
  • DirectShow est un framework pour réaliser des applications Windows multimédias
  • WordPress peut être considéré comme un framework spécialisé dans un type de site internet, les blogs

Le point commun entre tous ces outils est leur capacité à vous emmener de l’α à l’ω du développement de votre application, ce qui différencie les frameworks des bibliothèques ou des patrons logiciels.

L’art du cadrage

Le terme anglais framework a un grand défaut et une grande qualité. D’un côté, il décrit assez mal l’idée d’accompagner les développeurs dans le développement et l’aide apportée, mais de l’autre, il appuie sur un point qui me semble central pour le choix : la notion de cadre, qui induit certaines rigidités.

Les frameworks imposent très souvent des bibliothèques précises pour certaines fonctionnalités génériques (accès aux sources de données, journalisation, etc.) quand vous voudriez utiliser votre pilote de base de données ou votre outil de journalisation préféré.

Il est également assez habituel de démarrer son application avec un jeu de fonctionnalités limité et de choisir un framework très ajusté pour développer au plus vite ; lorsque vient le moment de faire évoluer le logiciel, il arrive très souvent que le framework ne permette pas de développer les nouvelles fonctions, voire pire, qu’il ne puisse pas cohabiter avec des outils tiers. Par exemple, il n’est pas très facile d’intégrer ensemble un blog WordPress et un forum phpBB. Dans un genre plus technique, Facebook avait commencé son développement en PHP, et s’est vite trouvé confronté à de grosses problématiques de performance ; en effet, quand le nombre d’utilisateurs augmente, PHP propose principalement deux façons de distribuer la charge : la mise en cache HTML, impossible de par la nature de Facebook, ou l’augmentation du nombre de serveurs, ce qui aurait induit des coûts délirants. Après avoir hésité à tout redévelopper, Facebook s’en est remis à optimiser la plateforme elle-même, en précompilant les pages PHP avec un outil développé en interne.

Le choix d’un framework est donc un exercice subtil où il s’agit d’équilibrer les gains apportés en rapidité de développement et en fonctionnalités « out of the box » et les limitations de l’outil en termes de configurabilité, d’ouverture et de possibilité d’intervertir ou d’ajouter des composants.

Principaux critères de choix

Pour bien choisir son framework, le plus important est évidemment son adéquation avec le type d’application que vous souhaitez construire ; vous n’utiliserez pas un framework internet PHP pour construire une application Windows classique. En prenant en compte la problématique du cadre décrite ci-dessus, cela peut s’avérer moins trivial qu’il n’y parait ; si vous démarrez un blog, vous vous pencherez très probablement sur WordPress, mais si le but de votre blog est de vendre votre production artisanale, et que la partie blog n’est qu’une manière d’améliorer votre visibilité par le grand public dans votre domaine, que faire ?

Tous les frameworks ont un cœur de fonctionnalités qui a présidé à sa création, déterminé ses choix techniques et fonctionnels fondamentaux ; quand un outil assez ajusté – comme WordPress pour les blogs par exemple – cherche à sortir de ce noyau pour faire un peu du tout – du forum, de l’e-commerce, etc. – c’est souvent une mauvaise idée et il fera presque toujours plus mal ses fonctions annexes qu’un outil spécifique. Je conseille d’éviter le proverbial « qui trop embrasse, mal étreint », et si vous vous appuyez sur un framework spécifique, de limiter son usage à ce qu’il sait nativement très bien faire.

Un autre atout d’un framework souvent cité est sa « communauté », c’est-à-dire l’ensemble de ses développeurs et de ses utilisateurs actifs, et plus précisément, ceux volontaires pour apporter de l’aide technique. Il est vrai qu’une communauté nombreuse est un gage, à un instant t, d’obtenir des réponses rapides à ses questions techniques ; cependant, contrairement à une idée répandue, il n’est pas une assurance de pérennité de l’outil. En effet, on constate généralement que lorsque les développeurs en chef disparaissent, pratiquement quelle que soit la taille de la communauté, les outils tombent dans l’oubli ou sont modifiés de fond en comble par une nouvelle équipe, quand vous avez la chance qu’elle se crée.

Car oui, comme tout en ce bas monde, il arrive que les frameworks meurent. Bien entendu, rien ne vous empêche de continuer à les utiliser, enfin, tant que les plateformes sous-jacentes peuvent les faire tourner, qu’il n’y a pas besoin d’ajouter de fonctionnalités ou de boucher des trous de sécurité, qu’on trouve d’autres orphelins de la communauté pour vous aider… Ce qui m’amène à un autre critère très important pour le choix et qui est assez peu souvent évoqué : s’appuyer sur des standards de l’industrie. Entre un framework avec son propre système de template, son propre langage d’accès aux données, son propre format d’export de données, et un autre qui s’appuie sur le SQL, normalisé par l’ANSI, XSLT, normalisé par le w3c, XML, normalisé par le w3c, on pressent naturellement qu’on trouvera plus facilement de l’aide en dehors de la communauté pour le deuxième que pour le premier.

Enfin, pour revenir sur la rigidité du cadre, avant de s’enfermer dans un choix, il est vital de bien étudier les possibilités que vous laissent le framework d’étendre le cadre ou d’en sortir :

  • l’utilisation de l’inversion de contrôle est généralement un gage de la possibilité de réimplémenter à sa sauce certaines parties du framework
  • dans le cas d’un outil fortement spécialisé, il faut étudier dans quelle mesure il peut s’intégrer dans un écosystème tiers (authentification, autorisation, suivi statistique, charte graphique, etc.), donc de vivre dans un framework plus générique que lui
  • à l’inverse, un outil générique doit être capable d’accueillir en son sein des produits plus spécialisés

Conclusion

Le choix d’un framework est très loin d’être anodin et peut revenir vous hanter pour des années, oscillant entre Charybde – la réécriture complète – et Scylla – maintenir un outil obsolète ou en étendre un mal adapté. De plus, il est très souvent sujet à des guerres de religion dont les informaticiens sont friands – microkernel contre kernel monolithique, Linux contre Microsoft, .NET contre Java, etc., quand ce ne sont pas des béotiens sur les questions techniques qui en imposent un pour des raisons n’ayant rien à voir avec la technologie. Si vous retenez de cet article qu’il faut bien évaluer le cadre imposé, et vous méfier des frameworks vous proposant une énième solution quand des standards techniques internationaux existent, il aura atteint son but.

SharpZipLib, Winzip et Office Open XML

Nous utilisons l’excellente bibliothèque native .NET SharpZipLib pour compresser et décompresser ; elle gère les formats tar, bzip2, gz et tar, fournit des implémentations bas niveau surchargeant Stream et plus haut niveau pour des tâches standards comme décompresser directement un zip dans un répertoire.

Dans le cadre de la mise en oeuvre d’un export xlsx pour notre contrôle tableau, j’ai naturellement utilisé SharpZipLib pour compresser les fichiers – xlsx est en ensemble de fichiers XML zippés. Après quelques erreurs venant du format du fichier XML inclus, qu’Excel me reportait clairement (erreur ligne x colonne y dans le fichier z), Excel continua à me dire qu’il avait du corriger mon fichier mais sans m’indiquer aucune erreur. Ouvert avec winrar, le fichier semblait parfaitement conforme ; pire, comparé à la version PHP, le contenu du zip était au caractère près le même, et pourtant Excel ne disait rien sur le fichier généré par la version PHP.

Je me suis donc naturellement tourné vers l’utilitaire de compression ; après quelques tripatouillages d’options, j’ai trouvé la bonne : UseZip64. SharpZipLib supporte Zip64, qui permet d’avoir des fichiers de plus de 4Go inclus dans le zip. Apparemment, il est connu que cette option est mal supportée par de vieilles versions de Winzip et par l’utilitaire de décompression inclus dans l’explorateur de fichiers de Windows XP ; j’ajoute à la liste au moins Excel, je n’ai pas testé avec Word ou PowerPoint mais j’imagine que ça doit être pareil. Pour que ça fonctionne, j’ai du modifier mon code de la façon suivante :

using(ZipOutputStream zos = new ZipOutpuStream(s)) {
  zos.UseZip64 = UseZip64.Off;
  ...
}

D’après la documentation, la valeur par défaut est Dynamic qui devrait déterminer si ça sert à quelque chose d’activer Zip64 ; dans mon cas, aucun fichier ne dépasse les 100ko, et pourtant il m’a activé Zip64, donc je ne sais pas trop quels sont les critères employés mais j’ai du désactiver complètement Zip64 pour qu’Excel soit content. Si ça peut servir à quelqu’un…

Ce qui n’est pas testé ne fonctionne pas

Lors de mes recherches sur la proposition d’apprendre le code à l’école du Conseil National du Numérique, j’ai retrouvé plusieurs fois l’idée selon laquelle la programmation pouvait être une activité formatrice au sens où elle promouvait un processus de création par essai – erreur où l’erreur n’était pas considérée comme une sanction définitive mais comme une étape naturelle participant à la construction de la solution. Cette idée est également très régulièrement citée comme un des facteurs de la réussite de la Silicon Valley, où un échec n’est pas considéré comme rédhibitoire, mais comme une expérience valorisable comme une autre.

Encore faut-il que les programmeurs s’intéressent au fait que leur programme soit erroné, et d’après mon expérience, c’est souvent là que le bât blesse.

C’est ballot, mais la moindre modification du code doit être testée !

Je vais reprendre un exemple récent arrivé à un de mes développeurs – si il se reconnait, rien de personnel, c’est pour l’exemple – sur une fonction plpgsql ; ça, c’est la première version qui marche (simplifiée à l’extrême bien sûr) :

CREATE OR REPLACE FUNCTION MAFONCTION(V_ID INT, V_MONPARAMETRE BOOLEAN) RETURNS INT AS $$
DECLARE
 V_RESULT INT:=1;
BEGIN
 UPDATE MATABLE SET MAVALEUR=V_MONPARAMETRE WHERE ID=V_ID;
 RETURN V_RESULT;
END;
$$ LANGUAGE plpgsql;

En relisant les spécifications, le développeur s’aperçoit que j’avais demandé que le deuxième paramètre soit optionnel et ait comme valeur par défaut false, et connaissant mal la syntaxe plpgsql, écrit le code suivant – négligeant de le tester, se disant qu’il n’y avait pas de raison que cela ne fonctionne pas :

CREATE OR REPLACE FUNCTION MAFONCTION(V_ID INT, V_MONPARAMETRE BOOLEAN) RETURNS INT AS $$
DECLARE
 V_RESULT INT:=1;
 V_MONPARAMETRE BOOLEAN:=false;
BEGIN
 UPDATE MATABLE SET MAVALEUR=V_MONPARAMETRE WHERE ID=V_ID;
 RETURN V_RESULT;
END;
$$ LANGUAGE plpgsql;

Pas de bol, il se trouve que les paramètres d’une fonction plpgsql peuvent être nommés, mais que ce n’est qu’une sorte de macro ; posgtresql va remplacer toutes les occurrences du nom choisi dans la fonction par le numéro du paramètre précédé d’un $ ; dans notre cas, postgresql ne le fera pas, puisqu’on a défini une variable dans la clause DECLARE qui écrase le paramètre en entrée, et postgresql ne fera ni erreur ni avertissement. Du coup, la valeur de V_MONPARAMETRE sera toujours false, quoi qu’on passe à la fonction. Le développeur est venu une fois fini le reste du travail demandé me dire que tout était terminé ; mes tests d’intégration n’ont bien sûr pas fonctionné, pas plus que mes tests unitaires. Le développeur était pourtant certain d’avoir vu sa fonction marcher, sans doute avant sa dernière modification qu’il considérait comme tellement triviale qu’il n’y avait pas besoin de la tester.

Un exemple historique… et autrement plus coûteux

Le premier vol d’Ariane 5 s’est achevé au bout de quelques dizaines de secondes, détruisant pour 370 millions de dollars de satellites. La source du problème ? Un module de calcul de poussée de la fusée, repris tel quel d’Ariane 4, dans lequel la poussée était stockée sur une variable d’une taille trop petite pour la nouvelle fusée, munie de moteurs plus puissants ; habituellement, en programmation, quand une variable numérique reçoit une valeur trop grande pour sa capacité de stockage, et en l’absence de vérification, la valeur passe à 0 (cas non signé) ou à la plus petite valeur négative (cas signé), donc en tout état de cause une valeur anormalement basse.

Du coup, la fusée s’est crue dans une position nécessitant une intervention immédiate et radicale du pilote automatique pour rectifier la trajectoire, intervention qui a exercé des contraintes telles sur la fusée qu’elle a commencé à se disloquer, aboutissant à l’enclenchement du mécanisme d’auto-destruction, et à un joli mais très coûteux feu d’artifice. Tout ça pour une variable stockée sur 8 bits au lieu de 9 nécessaires, dans un module repris à l’identique, mais… non testé dans les nouvelles conditions.

De ces deux exemples, on peut déduire une première règle : ne jamais oublier que quelle que soit la petitesse de la modification effectuée sur le code, ce qui n’est pas testé ne fonctionne pas.

Et deux tests valent mieux qu’un…

Une autre de mes activités, récemment en croissance, est de débusquer des trous de sécurité, que ce soit sur des sites nous appartenant ou que nous hébergeons ; rien de très évolué, plutôt du très classique : injection SQL permettant de s’identifier avec n’importe quel compte ou de consulter toute une base de données payante sans l’acheter, cross-site scripting lors de la soumission de données pour intégrer du code actif envoyant discrètement des données du site attaqué vers un tiers ou pour faire du hameçonnage, ce genre de choses. Le point commun de ces défauts de sécurité, également commun avec les classiques attaques buffer overflow à la base de la plupart des failles des systèmes d’exploitation ? Le système définit des entrées – par exemple, le premier paramètre doit être un entier, et le deuxième une chaîne de caractères de moins de 256 octets de long – mais ne vérifie pas que les valeurs passées respectent cette définition.

Tendance bien naturelle : quand on programme la fonction et les appels à la fonction puis que dans la foulée, on effectue les tests, il est assez logique de mettre en oeuvre des tests respectant les contraintes qu’on a soit même définies, elles sont assez fraîches dans notre esprit. De nombreuses façons d’éviter ces erreurs existent : faire écrire les tests par une autre équipe que l’équipe de développement est une parade classique, certains langages de programmation incluent ce type de contraintes dans la signature des fonctions comme Ada par exemple, etc. Mais aucune n’est plus efficace que d’être conscient de la problématique et de la mettre au cœur de ses pratiques !

Ces exemples nous permettent d’énoncer une deuxième règle : ne jamais faire confiance aux données envoyées par le client.

Si vous gardez ces deux règles présentes à l’esprit tout au long de vos développements, quels que soient les outils que vous utilisez, aussi protecteurs que vous pensiez qu’ils soient contre les fautes de programmation, vous aurez fait un grand pas vers la production de programmes conformes et sûrs.

Le côté obscur de l’information

L’Union Européenne publie depuis 2014 un indice répondant au doux nom de DESI (Digital Economy and Society Index, Indice d’Economie et de Société Numérique) dont le but est de comparer l’avancement des états européens en termes de pénétration des outils numériques. La France se trouve classée au milieu de la mêlée, avec d’assez mauvaises notes en déploiement du très haut débit et en utilisation par les PME – allez par là pour vous lancer, amies PME – mais des bonnes notes en formation professionnelle et en administration numérique.

Le choix des indicateurs est à mon sens au moins aussi éclairant que les résultats eux-mêmes : l’omniprésence de l’utilisation d’internet, qui pourtant n’existe pour le grand public que depuis moins d’une génération, est frappante, comme si les usages numériques se limitaient quasiment exclusivement aux services disponibles sur internet.

Mais les sous-catégories qui ont particulièrement attiré mon attention sont la 3a et la 3b, usage d’internet / contenu et communication, sensées traiter des contenus et de l’interaction en ligne. Commençons par décrire les indicateurs.

Le contenu sur internet en 2015, objet de consommation ?

L’étude mesure la pénétration des contenus numériques en Europe en évaluant le pourcentage d’internautes consommant des actualités, de la musique, des vidéos et jeux, de la vidéo à la demande et de la télévision par IP, et la communication par les appels voix ou vidéo sur IP et l’utilisation des réseaux sociaux.

Ces indicateurs, combinés les uns avec les autres, dessinent un réseau dans lequel les contenus sont produits par des services centraux, puis poussés vers des consommateurs dont la seule action est le commentaire et le partage. Pour une étude débutée en 2014, c’est un choix assez surprenant, sachant que la révolution du web 2.0 – dont la principale caractéristique est de décentraliser la production de contenus par la démocratisation des moyens de création et de diffusion – est maintenant bien stabilisée. Malheureusement, les choix des indicateurs sont trop peu motivées pour en tirer une quelconque conclusion éclairée ; est-ce un reflet du lobbying des acteurs historiques de la production de contenus ? Est-ce une impossibilité matérielle d’obtenir des chiffres exploitables ? Mystère.

Les résultats n’en sont pas moins intéressants ; par exemple, la France, créatrice du modèle « triple play », est en tête et pas qu’un peu dans les domaines de la télévision par IP et la vidéo à la demande, alors que nous sommes dans les derniers de la classe pour l’abonnement au très haut débit dont on pourrait pourtant penser qu’elle est une condition du déploiement de ces services. Là se trouve résumée la grande faiblesse de cette étude : aucune corrélation n’est faite entre les indicateurs et aucune tentative d’explication n’est apportée ; d’une part, on peut assez facilement attribuer le relatif faible débit constaté en France à la structure géographique de notre pays – les pays plus physiquement centralisés trustant les premières places – et d’autre part, quelle importance accorder à la pénétration du très haut débit si l’implantation des services l’utilisant le plus en semble totalement décorrélée ?

Mais le chiffre le plus amusant est pour moi le 3b2 : la France est la dernière dans toute l’Union Européenne pour l’utilisation des réseaux sociaux, mesurée comme l’écriture de message ou autres contributions à Facebook, Twitter, etc. J’ai immédiatement rapproché ce chiffre d’un concept très rigolo : le « dark social ».

Le « dark social », késako ?

J’ai vu apparaître le terme en fin d’année 2014, ici ou  ; il semblerait qu’après la vague de croissance des réseaux sociaux, et leur tentative d’apprivoisement pas toujours réussie par les entreprises, les services marketings et communication se soient réveillés d’un seul coup pour s’apercevoir que les moutons les consommateurs avaient le front de parler de tout et n’importe quoi en dehors des réseaux sociaux, loin des capacités d’analyse automatisée : échanger des liens intéressants, donner leur avis sur des produits, etc. D’après les évaluations relayées, nous serions les rois de l’OCDE du « dark social », ce qui entre parfaitement en résonance avec les chiffres de l’Union Européenne.

Au delà de l’ironie de voir nommer « dark social » la communication interpersonnelle qui existe depuis la nuit des temps – donc en opposition avec une tendance pourtant extrêmement récente à considérer qu’il est loisible de rendre public ses avis, ses goûts et ses opinions – il me semble intéressant de juger de la pertinence de considérer que c’est une preuve de maturité numérique que d’utiliser massivement les réseaux sociaux.

Maîtriser les nouvelles technologies de l’information, au delà de l’utilisation des outils, ce doit être comprendre ce qu’est une information, quelle est sa valeur, sa qualité, à qui la transmettre et comment ; dans le cas précis des réseaux sociaux, l’idée selon laquelle tout y est public, directement ou indirectement, et que s’y exprimer revient à aller crier à tue-tête sur la place du village, commence à faire son chemin, mais prend du temps à être complètement intégré dans les modes de pensée du grand public.

En ce sens, il me semble qu’une utilisation modérée et contrôlée des réseaux sociaux relève d’une appréhension plus fine des outils numériques ; du coup, le critère 3b2 ne me semble absolument pas pertinent, dans un sens ou dans l’autre. Il faudrait certainement le remplacer par des critères plus qualitatifs sur la façon d’utiliser les réseaux sociaux, mais ils sont probablement très compliqués à définir et à standardiser à l’échelle européenne.

Mais au moins maintenant, vous saurez qu’en envoyant un email à vos amis sur une nouvelle vidéo YouTube, tel M. Jourdain, vous faites du « dark social » sans le savoir !

Faut-il enseigner « le code » à l’école ?

En octobre 2014, le Conseil National du Numérique a publié un rapport sur le numérique et l’éducation dont la traduction médiatique et politique a principalement tourné autour de la proposition d’enseigner la programmation à l’école, sujet qui m’a évidemment intéressé, étant fils de professeurs, formateur à mes heures, et professionnel de l’informatique. Ma première réaction, épidermique, a été de rejeter l’idée d’emblée, surtout en écoutant les débats médiatiques menés par des ignorants à la fois des questions éducatives et de la discipline informatique, qui en général considéraient qu’il était nécessaire de connaître la programmation pour évoluer dans la société de l’information. Comme si il fallait savoir construire une centrale nucléaire pour utiliser le courant électrique… Après réflexion, et documentation sur la façon dont cette idée était présentée dans le rapport – toujours lire les rapports ! – mon avis a évolué tel que je vais vous le présenter ici.

Le contenu du rapport

Je ne vais pas résumer tout le rapport ; je me limiterai à décrire succinctement ses différentes parties et préciser ce qui tourne autour de l’enseignement de l’informatique per se.

Loin de se limiter à l’apprentissage de la programmation, ce rapport analyse tous les aspects de la relation qu’entretiennent le système éducatif et les outils et disciplines informatiques : non seulement l’utilisation du numérique à l’école pour lui-même et l’apprentissage de la discipline informatique, mais aussi l’utilisation du numérique pour les autres matières, ainsi qu’une éducation plus générale aux outils numériques que pourront rencontrer les élèves dans leur vie, les transformations que ces outils amènent dans la vie de tous les jours et la citoyenneté. Il fait un plaidoyer assez convaincant pour une intégration en profondeur du mode de pensée informatique dans le processus d’apprentissage des élèves, en précisant les prérequis et le chemin d’une telle transformation réussie.

A propos de la discipline informatique elle-même, j’ai été très heureux de lire que la proposition n’était pas de l’introduire par le petit bout de la programmation, mais par l’initiation à la pensée informatique, en primaire et – comble de joie – en mode connecté ou non (cf recommendation 1, page 29 du rapport).

La suite des opérations se passe au collège où le cours de technologie serait consacré une année à l’informatique, a priori en troisième, où l’on enseignerait des rudiments d’algorithmique et, en tant qu’application, de la programmation.

Enfin, l’informatique serait reprise au lycée dans toutes les sections, avec un approfondissement des notions déjà abordées au collège, en fonction des spécificités de la filière choisie par l’élève.

On est loin du simple « enseigner le code » relayé publiquement ; je reviendrai sur les raisons qui à mon avis ont amené à cette simplification, mais continuons par un retour dans les années 80.

La tortue et l’enfant

Je me souviens avec acuité qu’en CE2 nous étions partis par petits groupes dans une autre école afin d’y utiliser des ordinateurs. Nous avions déjà à la maison un TI99/4A que nous avions principalement utilisé avec mes frères pour jouer, même si nous étions parfois tombés sur le prompt Basic – sans trop savoir au premier abord à quoi il pouvait bien servir. Les ordinateurs de l’école étaient des Thomson MO5 et TO7 à claviers à gomme – quelle plaie ! – mis en réseau avec un Bull Micral 30 – que contrôlait la maîtresse – muni d’une imprimante à aiguille.

La principale utilisation de ces ordinateurs qui nous fut proposée – en dehors de programmation Basic extrêmement guidée, nous n’avions que 8 ans quand même – était de piloter la tortue ; le principe était de dessiner à l’aide d’une bestiole virtuelle à qui nous donnions des ordres simples comme avancer de x pixels, tourner de y degrés, changer la couleur etc. Ces ordres étaient exprimés en français courant, voici un exemple pour réaliser un carré :

POUR CARRE
REPETE 4 [AVANCE 100 TOURNEDROITE 90]
FIN

J’étais assez frustré de découvrir un outil que je connaissais pas, alors que j’avais annoncé avec fierté avoir un ordinateur à la maison et donc de bien savoir comment ça marchait, mais je me suis vite pris au jeu, réalisant plusieurs polygones réguliers et des rosaces, que j’avais déjà l’habitude de dessiner avec mon compas quand je finissais en classe mes exercices de mathématiques en avance. Et me voilà 30 ans plus tard directeur technique d’un éditeur de logiciels…

Au delà de l’aspect nostalgique, l’intérêt de cette expérience est de mettre en exergue ce que peut être une initiation réussie à la programmation : programmer, ce n’est que donner des ordres à un ordinateur ; en choisissant un domaine qui plait naturellement aux enfants, dessiner, et en limitant les ordres possibles à des primitives simples, l’enfant comprend très rapidement ce qu’est ordinateur – un esclave numérique, ce qu’il sait faire – répéter sans se fatiguer ni se lasser et à grande vitesse des listes d’instruction, et comment le faire – en parlant avec lui dans son langage.

Pour ceux que ça intéresse, la tortue est toujours disponible sur des plateformes récentes : http://www.yann.com/fr/apprendre-la-programmation-aux-enfants-avec-le-langage-logo-17/09/2010.html

Objectifs pédagogiques

Grosso modo, une matière peut s’enseigner pour deux raisons : soit elle dispense des savoirs immédiatement opérationnels, soit elle aide à la construction de l’esprit, les deux pouvant se combiner. Certains savoirs sont tellement fondamentaux que tous doivent les apprendre, comme la lecture, l’écriture, les 4 opérations et la règle de trois ; certains restent du domaine de la professionnalisation, comme de savoir faire correctement une piqûre pour un infirmier ou de dupliquer une clé pour un serrurier. Le latin est très peu opérationnel dans le monde moderne, mais sa capacité à structurer l’esprit et à aider à l’apprentissage du français ne sont plus à prouver. Dans quelles catégories tombe l’informatique ?

Si on se limite à la programmation, il est très tentant de ranger l’informatique dans les savoirs professionnels ; c’est à de très rares exceptions près le cas aujourd’hui, avec le très dommageable effet secondaire que même dans les études professionnelles, son enseignement est exclusivement utilitariste – un très bon sujet pour un futur article. Mais comme vous le savez si vous avez lu mes articles précédents, l’informatique est une science, avec un objet et des méthodes définies qui lui sont uniques ; sans même plonger dans une analyse poussée de la question, il est donc certain que son enseignement aide l’esprit à se structurer comme tout autre champ de la connaissance, si tant est qu’on l’enseigne comme une science et pas comme une technique. C’est ce dont parle le rapport du Conseil National du Numérique sous le vocable de « pensée informatique ».

Une des caractéristiques fondamentales de cette pensée informatique est la numérisation du réel afin de le rendre intelligible et exploitable par les ordinateurs ; cette numérisation a pour corollaire une très forte pression à la désambiguïsation qui peut aboutir à une standardisation de la pensée. Par exemple, quand vous commencez à saisir une requête dans un moteur de recherche, un système de suggestion va vous indiquer des compléments possibles ; vous fait-il gagner du temps, ou oriente-t-il votre pensée et votre désir ? Sachant que ces compléments proviennent d’études statistiques sur les requêtes les plus souvent lancées, je tendrais plutôt vers la deuxième option ; or, quoi de plus important dans la formation d’un futur citoyen que l’apprentissage de l’esprit critique et du libre-arbitre ?

Dans le même ordre d’idées, afin de réaliser ses traitements, l’ordinateur a besoin de données normalisées, et c’est à l’être humain qui l’alimente d’effectuer cette normalisation ; il est alors lui-même un objet informatique, puisqu’il fait partie de facto de la chaîne de traitement de l’information. Nos enfants peuvent rester des Monsieur Jourdain de l’informatique, mais étant donnée son ubiquité aujourd’hui, ce savoir ne peut qu’apparaître fondamental.

Voilà le genre de méthodes propres à la pensée informatique que les enfants doivent maîtriser pour se mouvoir dans la société numérique. Et ce n’est pas en programmant qu’ils l’apprendront – la plupart des programmeurs professionnels que je rencontre ne sont pas eux-mêmes conscients de ces questions !

Conclusion

Ma réponse courte à la question initiale est non ; si c’est pour retrouver à l’école la même approche utilitariste que je constate dans les formations professionnelles, mieux vaut ne pas perdre le temps de tout le système éducatif. Il est d’ailleurs tout à fait éclairant sur l’état de la réflexion sur l’école en France aujourd’hui que la réponse politique à ce rapport brillant et complet ait été d’en extraire le seul aspect purement utilitariste en oubliant tous les aspects pédagogiques et émancipateurs ; pour résumer ce que j’ai entendu, et j’ai bien tendu l’oreille, la petite musique était « apprenons le code le plus tôt possible à nos enfants, et nous damerons le pion aux américains et aux indiens dans la compétition numérique ». Si seulement.

Ma réponse longue, développée ci-dessus, est oui, si on applique scrupuleusement ce qui est développé dans le rapport : une initiation à la pensée informatique à l’école, sur le modèle de la tortue par exemple, mais d’autres initiatives très intéressantes existent comme « Computer science unplugged » (l’informatique débranchée), un approfondissement au collège avec de l’algorithmique simple et de la programmation en application, et une version plus avancée au lycée. Les professeurs suivront-ils, comme ma maîtresse avait su le faire à l’époque ? Les parents, ignorants de ces sujets, en comprendront-ils l’intérêt ? Les politiques, qui paraissent aujourd’hui mépriser ce qui construit l’esprit pour y préférer un utilitarisme de court terme, auront-ils la présence d’esprit de suivre le rapport à la lettre ?

Loi sur le renseignement : si elle passe, qu’est-ce-qui change ?

Je me concentrerai ici sur les aspects concernant l’hébergement d’applications, le domaine que je connais. Attention, je ne suis pas juriste, donc ce qui suit est ma lecture de technicien ; si un juriste passe par ici et m’explique en quoi je me tromperais éventuellement, je lui en serais reconnaissant.

Tout d’abord, la référence, c’est-à-dire la loi adoptée par l’Assemblée Nationale et qui repart maintenant au Sénat : http://www.assemblee-nationale.fr/14/ta/ta0511.asp. Pour ce qui est de l’hébergement, une des subtilités de la loi est qu’elle enrobe plusieurs textes existants, dont la loi pour la confiance dans l’économie numérique – qui n’a jamais aussi mal porté son nom – avec de nouveaux éléments déclencheurs (en particulier cet article : fourniture des clés de décryptage).

Les boîtes noires

On a beaucoup glosé sur les « boîtes noires » que les services de renseignement pourraient installer un peu partout sur internet pour suivre le trafic ; telles que décrites dans la loi, ces « boîtes noires » – le terme n’apparaît pas ainsi dans le texte – peuvent être installées chez les opérateurs faisant transiter des données dans le réseau, donc pour simplifier chez les FAI et les routeurs, ainsi que directement chez les hébergeurs puisque ceux-ci sont visés par l’article L246-1 du code de la sécurité intérieure (renommé en L851-1, voir ici) via l’alinéa 2 de l’article 6 de la loi pour la confiance dans l’économie numérique (voir ici). Ces dispositifs sont sensés analyser les données uniquement dans le but de rechercher des activités terroristes, et ce de façon anonyme. Si quelque chose est détecté, l’anonymat est levé.

En tant qu’hébergeur, nous devons donc laisser installer sur nos machines des dispositifs fournis par les services de renseignement, si ceux-ci peuvent nous fournir l’autorisation du Premier Ministre ou des personnalités qualifiées par lui. Nous pouvons éventuellement nous plaindre au Conseil d’Etat si nous considérons que la demande est injustifiée ; il doit se prononcer dans un délai d’un mois. Suite à la rencontre avec des représentants du collectif ni pigeon ni espion le gouvernement avait indiqué que nous pourrions demander quels étaient les algorithmes internes de ces dispositifs, mais je n’en vois pas trace dans la loi et de toutes façons cela me semblerait assez surprenant pour l’efficacité supposée de ces écoutes numériques.

Le décryptage des données

Dans le cas où les communications seraient cryptées, nous devons mettre à disposition des mêmes personnes les moyens de les décrypter (voir ici pour l’article initial, qui devient applicable aux demandes des services de renseignement en vertu de l’article 6 de la loi). Imaginons que l’Etat mette en oeuvre des dispositifs d’interception chez les principaux FAI français ; quand vous accédez à un site en SSL, une écoute numérique, même chez le FAI, ne suffit pas à lire en clair les communications, et même pas les URL que vous consultez. Pour cela, il vous faut la clé privée du site. Cet article indique donc que si vous hébergez des sites en SSL, vous devez fournir sur demande administrative vos clés privées. Je ne sais pas pour vous, mais une fois que ma clé privée est compromise, je la change – et ça me coûte, en temps et en régénération de certificats.

Là où ça devient compliqué à gérer pour nous hébergeurs, c’est que les données collectées ont bien un délai de conservation, mais celui-ci court à partir de la date de décryptage (article L822-2 du nouveau code de la sécurité intérieure). Ce qui veut dire qu’on peut tout à fait venir vous demander de fournir sans délai (article 6 de la loi) vos clés privées d’il y a 20 ans ! Nous allons donc devoir stocker nos clés privées ad vitam aeternam.

Que penser de ces mesures ?

Je ne me prononcerai que sur les écoutes numériques en masse, les écoutes ciblées de personnes connues n’étant pas de ma compétence. Le principe est d’analyser l’historique de navigation et les textes échangés pour tenter de déterminer un comportement potentiel voire des idées partagées. Dans ce type de traitement, vous avez deux risques : rater un positif (risque alpha) et détecter un négatif (risque bêta). Si vous ratez trop de positif, votre système ne sert à rien ; et de manière un peu moins évidente, si vous détectez trop de négatifs, votre système ne sert à rien non plus, puisque vous perdez votre temps à courir après des chimères. De plus, dans le cas présent, les faux négatifs ont des conséquences très graves pour les personnes concernées.

Ce type de systèmes peut analyser soit des données fortement structurées, par exemple une saisie parmi une liste de valeurs possibles, soit des données faiblement structurées, par exemple de l’analyse de langage naturel. Evidemment, lorsque des données structurées sont disponibles, cela simplifie le travail de classement ; malheureusement, il est peu probable que des sites hébergés en France se caractérisent de façon univoque comme terroristes. Plus probablement, le travail se fera sur du langage naturel, et là les faux positifs seront nombreux.

Nous pourrons compter également comme faux positifs des personnes recherchant ou enquêtant sur ces sujets et qui ne consulteront les sites que pour s’informer et pas pour militer.

Enfin, les faux positifs, ça se fabrique, ça s’appelle du bombing : on crée une page web tout à fait inoffensive à l’écran mais contenant textuellement des éléments qu’on sait être détectés par les systèmes automatiques de façon à écraser le système par un trop plein de données.

Au final, il me semble que le risque important de faux positifs combiné à la gravité d’une erreur justifie les peurs que de nombreux hébergeurs, dont nous, ont exprimées. On m’objectera qu’aujourd’hui cette mesure est limitée à l’antiterrorisme, mais d’une part, la définition française du terrorisme est assez large, et donc justifie d’ores et déjà beaucoup d’écoutes, et d’autre part, le législateur malin connait bien la fable de la grenouille : on commence doucement, dans l’eau froide, et on chauffe petit à petit. Vous souvenez-vous que la CRDS devait s’arrêter en 2014 ? Que la CSG a commencé à 1,1 % pour en être maintenant à 7,5 % ? Parier qu’une loi d’exception finira par être supprimée ou qu’elle ne sera jamais étendue est bien risqué, surtout quand elle touche aux libertés les plus fondamentales.

SQLite et les types de données

Pour le meilleur et pour le pire, SQLite est l’unique sgbd embarqué sur les principales plateformes mobiles du marché – au moins, il est présent sur toutes, c’est déjà ça.

Pour quelqu’un d’habitué à un sgbdr comme Oracle ou Postgresql, le système de typage de SQLite peut être très déroutant et entraîner des bogues très difficiles à débusquer. Cet article va vous donner quelques trucs pour éviter les plus vicieux.

La documentation ne vous prend pas en traître : les colonnes en SQLite ne sont pas typées statiquement (cf https://www.sqlite.org/datatype3.html). Eux ont l’air de trouver ça génial, vous allez voir que ce n’est pas vraiment mon avis.

Concrètement, qu’est-ce-que ça change ? Quand vous insérez une valeur dans une colonne SQLite, SQLite décide de lui-même d’une « classe de stockage » (storage class) qui peut être NULL, INTEGER, REAL (en virgule flottante), TEXT et BLOB suivant les caractéristiques qu’il perçoit de la donnée que vous lui transmettez.

Mais alors, si SQLite décide du stockage lui-même, à quoi servent les types qui sont données dans les instructions CREATE TABLE ? La réponse est que ce ne sont pas des types, mais des « affinités de types » (type affinities), une sorte de préférence pour le stockage. Pour les exemples ci-dessous, j’emploierai la table suivante :

CREATE TABLE TEST_CRAPPY_TYPING_SYSTEM(
  t text,
  not_quite_float float
);

La première conséquence est que de ligne en ligne, la classe de stockage pour une même colonne peut varier ; par exemple :

INSERT INTO TEST_CRAPPY_TYPING_SYSTEM VALUES('test',500); -- 500 est stocké en INTEGER
INSERT INTO TEST_CRAPPY_TYPING_SYSTEM VALUES('test 2',500.5); -- 500.5 est stocké en REAL

La deuxième conséquence, encore plus rigolote, est que contrairement à l’exemple ci-dessus, la classe peut sembler complètement incompatible :

INSERT INTO TEST_CRAPPY_TYPING_SYSTEM VALUES('test 3','tralala'); -- ne fait pas d'erreur et est stocké en TEXT

Ce qui peut amener si on ne fait pas attention à des cas très vicieux :

INSERT INTO TEST_CRAPPY_TYPING_SYSTEM VALUES('test 4','4,567'); -- stocké sous forme de chaîne, car SQLite ne reconnait pas 4,567 comme un REAL !

Cas particulièrement vicieux car si vous faites :

SELECT not_quite_float * 100 FROM TEST_CRAPPY_TYPING_SYSTEM WHERE t='test 4';

Vous recevez un joli 400 – car SQLite fait un gros effort pour tenter de faire de votre chaîne un nombre, qui s’arrête lamentablement à la virgule ; du coup, vous avez l’impression qu’il y a bien quelque chose comme un nombre dans votre valeur, sauf que non. Ca fait un peu penser à MySQL et son absence d’erreurs sur les débordements numériques, sauf que SQLite a l’excuse de le faire exprès et de le documenter.

Maintenant, si vous exécutez le code C# suivant (j’omets la création de la connexion et toutes les fermetures propres de ressources) :

IDdCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT not_quite_float FROM TEST_CRAPPY_TYPING_SYSTEM";
IDataReader rs = cmd.ExecuteReader();
while(rs.Read()) {
  Console.WriteLine(rs.GetValue(0).GetType().FullName);
}

Vous récupérez Int32, Decimal, String, String. C’est un peu mieux que le driver OleDb Excel qui devine le type sur les premières lignes, puis renvoie NULL si il rencontre une valeur qui ne se conforme pas au type qu’il a décidé, mais il vaut mieux être prévenu.

Conclusion : si vous voulez de la cohérence de typage avec SQLite, do it yourself, et si vous avez des résultats étranges avec les types numériques, vérifiez bien ce que vous avez donné à manger à SQLite en insertion.

Faut-il avoir peur des intelligences artificielles ?

Plusieurs figures éminentes de la technologie et de la science ont récemment exprimé des inquiétudes vis-à-vis du développement des intelligences artificielles : Elon Musk, cofondateur de Paypal et fondateur de Tesla Motors et SpaceX, a été le plus théâtral en parlant « d’invoquer le démon » et que les intelligences artificielles seraient « plus dangereuses que les armes nucléaires », suivi de près par l’astrophysicien Stephen Hawking qui a déclaré qu’elles pourraient « sonner le glas de l’humanité » car elles évolueraient plus rapidement que les êtres biologiques, et d’une certaine manière, Bill Gates, fondateur de Microsoft, plus mesuré, qui a estimé que « dans quelques dizaines d’années, elles pourraient devenir un problème ». Cette poussée de fièvre subite me semble très prématurée, et probablement assise sur une incompréhension de ce qu’est une intelligence artificielle et de l’état de l’art en la matière, ce que je vais tenter de démontrer ici.

Définition

Il n’est pas aisé de définir ce qu’est une intelligence artificielle ; pour preuve, dans sa déclaration, Bill Gates parle des problèmes que pourraient poser une « superintelligence » par opposition aux intelligences dont nous disposerions aujourd’hui. De plus, le terme est une locution qui conjugue deux mots ayant eux-mêmes des sens ambigus. Commençons par la notion d’artificialité.

Fidèle à moi-même, je ne relie pas l’artificialité au fait que l’entité concernée soit un ordinateur dans son acception commune, mais à l’origine de cette entité : dans la suite de cet article, par artificiel, j’entendrai construit par l’homme. Ce choix est moins anodin et évident qu’il n’y parait : en effet, ainsi défini, un être biologique – au sens de forme de vie basée sur la chimie du carbone – créé par des humains et accédant à l’intelligence serait aussi artificiel qu’un calculateur. Pourquoi se restreindre au silicium et au cuivre dans notre ambition démiurgique ? Une objection valide à ma définition est qu’il n’y aurait pas de différence fondamentale entre un être biologique créé en laboratoire et un être biologique nés de processus naturels.

Le terme d’intelligence est encore plus difficile à définir. Pour ce faire, je vais considérer la notion d’intelligence tel qu’un humain l’entend, c’est-à-dire une entité capable de comportements d’une certaine complexité.

Bien qu’une définition négative ne puisse être totalement satisfaisante, je commencerai par des exemples de ce qui n’est pas, pour moi, une intelligence. Les systèmes d’informatique d’entreprise que nous construisons chez Yoocan, qui appliquent à des données pour la plupart structurées des règles fixes définies par des humains, suivant des processus modélisables mathématiquement sous forme d’algorithme, ne sont pas une forme d’intelligence. De même, une machine industrielle comme un robot soudeur répétant inlassablement les mêmes actions suivant un rythme fixe n’est pas une forme d’intelligence.

De ces deux exemples, je peux tirer une première caractéristique d’une entité intelligente : son comportement ne doit pas être fixe ; elle doit donc être capable de modifier celui-ci en fonction des circonstances qu’elle rencontre, en d’autres termes, elle doit être capable d’apprendre.

La capacité à apprendre est au cœur de nombreux systèmes informatiques cherchant à rapprocher les machines des humains : pour prendre un exemple que je connais bien de par mon stage ingénieur au Japon chez ATR, les systèmes de reconnaissance de la parole apprennent des exemples de correspondance onde sonore / phonème qu’on leur fournit en usine ; ils sont ensuite capables de raffiner leur approche une fois mis en production par les corrections par des êtres humains des erreurs qu’ils commettraient. Cela rend-il pour autant un ordinateur muni d’un logiciel de reconnaissance de la parole intelligent ? Je ne sais pas pour vous, mais certainement pas pour moi ; il ne remplit qu’une seule tâche que l’on pourrait qualifier d’intelligente, et cette tâche ne lui permet que de nous restituer ce que nous lui avons donné comme information.

De cette limitation, je peux tirer une deuxième caractéristique d’une entité intelligente : elle doit créer du sens de ce qui l’entoure ; pour être plus précis, elle doit être capable, à partir de ses capacités sensorielles, de se construire une vision de ce qui n’est pas elle afin d’interagir avec.

Un bon exemple de cette caractéristique est le fonctionnement des robots aspirateurs ; afin de traiter toute la pièce où ils se trouvent, ils s’en construisent un plan mental avec ses bordures et ses zones déjà visitées. Je ne l’ai volontairement pas précisé pour les systèmes de reconnaissance de la parole, mais ils ne se limitent pas à l’analyse des ondes sonores ; ils tentent de découper les mots, d’en déduire les phrases, y compris leur sens et la fonction des mots, afin de valider la reconnaissance audio par la probabilité que la suite de phonèmes veuille vraiment dire quelque chose dans la langue cible. Cela fait-il d’un robot aspirateur une entité intelligente ? Pour moi, toujours pas ; il lui manque la capacité à affirmer et partager sa vision de ce qui l’entoure et de faire des choix.

De cette objection, je peux tirer la troisième et plus fuyante caractéristique d’une entité intelligente : elle doit pouvoir dire « je » ; en d’autres termes, avoir conscience d’elle-même, de son unicité et de sa capacité à analyser et agir sur son environnement, en affirmant son identité et une forme de volonté.

Autant que nous sachions, nous n’avons pas encore créé d’entité artificielle qui possède cette caractéristique ; pire, malgré plusieurs milliers d’années de réflexion philosophique et scientifique sur la question, nous ne savons pas d’où vient cette capacité que nous prêtons aux êtres biologiques.

Pour cet article, je définirai donc une intelligence artificielle comme une entité créée par l’homme capable d’apprendre, de se créer une vision de son environnement, de partager cette vision et de choisir par elle-même comment elle va agir.

Un peu d’histoire

Si on admet mon acception de l’intelligence artificielle, l’idée n’est pas née avec l’informatique au XXème siècle ; de nombreux mythes antiques y font référence – les automates d’Héphaïstos par exemple – de grands intellectuels de la Renaissance et de l’époque classique ont travaillé dessus – comme Léonard de Vinci ou Descartes – et des œuvres littéraires majeures en ont fait un thème majeur – comme Frankenstein ou le Prométhée moderne de Mary Shelley.

Au XXème siècle, l’idée d’une intelligence artificielle a préoccupé les informaticiens dès les prémices de la discipline ; Alan Turing lui-même, dès 1950, s’intéressait déjà à la question. Il a défini le célèbre « test de Turing », dans lequel on caractérise une intelligence comme une entité capable de communiquer avec un être humain sans que celui-ci puisse deviner qu’il ne parle pas avec un autre être humain. Tout en n’étant pas complètement satisfaisant pour détecter une intelligence, ce test reste non résolu à ce jour.

Aujourd’hui, brique par brique, nous construisons des outils capables d’appréhender leur environnement – comme les robots dont j’ai déjà parlé – de raisonner sur des problèmes précis et de communiquer naturellement avec des êtres humains.

Où en sommes-nous ?

Pour revenir à la déclaration de Bill Gates, on distingue classiquement deux niveaux d’intelligence : l’intelligence faible, qui correspond à celle des robots à spectre limité comme les robots aspirateurs, des systèmes expert ou des analyseurs big data et l’intelligence forte, qui correspond à ma définition.

Nous avons bien progressé sur l’intelligence faible : de nombreuses tâches unitaires ont atteint une bonne qualité de traitement – la reconnaissance de la parole, la vocalisation, l’appréhension et la création de modèle de l’environnement physique – et des applications avancées comme grand public réellement intéressantes sont disponibles. En particulier, de plus en plus de tâches répétitives, qui généralement rebutent les humains, peuvent être laissées à des machines. D’ailleurs, la mécanisation de ces tâches me paraît une des grandes victoires de l’informatique, j’y reviendrai certainement dans un autre article.

Un autre cas où les intelligences artificielles pourraient apporter beaucoup est l’intervention en milieu hostile – sous-entendu hostile pour l’être humain : irradiation, environnement extraterrestre ou absence d’air respirable, hautes pressions comme dans les hauts fonds marins, etc. Ces cas sont particulièrement intéressants car plus que de décharger les humains de tâches ingrates, ils correspondent à des situations où l’être humain ne peut pas intervenir du tout. Force est de constater que les systèmes actuellement en production ont une intelligence très limitée – en particulier une intelligence adaptative proche de zéro – et ont des périmètres d’intervention très restreints. Deux exemples concrets :

  • la sonde Rosetta : en simplifiant son fonctionnement, on lui demande de se placer sur telle ou telle orbite autour de la comète 67P pour procéder à des analyses ; afin de s’assurer que sa course est toujours correcte, elle calcule régulièrement sa position dans l’espace par triangulation avec trois étoiles lointaines ayant des spectres lumineux bien définis. Récemment, un incident est survenu, car la comète se rapprochant du soleil, elle a commencé à perdre de la matière que la sonde a prise pour une de ses étoiles de guidage ; conçue très robustement, la sonde s’est éloignée de la comète en se basant sur la position calculée antérieurement, et a passé la main aux ingénieurs au sol pour déterminer la suite. Bravo aux ingénieurs ayant conçu la sonde, mais on est loin des capacités d’un pilote humain
  • la centrale de Fukushima : un robot a été lancé mi-avril pour évaluer certains dégâts en zone fortement irradiée ; il n’avait cependant que peu d’indépendance de manipulateurs humains, s’est coincé dans un conduit, n’a pas réussi à se débloquer, et a donc fini par cesser de fonctionner à cause des radiations qui, comme on le sait, attaquent également les circuits électroniques.

Enfin, beaucoup de fantasmes entourent les systèmes d’analyse de données des géants du web comme Google ou Facebook qui seraient capables de modéliser les comportements humains. Il suffit pour se rasséréner de voir les applications concrètes qui en sont faites :

  • les publicités supposément ciblées mais qui manquent régulièrement leur cible, que ce soit par manque d’information – on vous propose pendant des mois des ventes de portable hybride car on a détecté une recherche sur un site partenaire, mais on a raté votre acte d’achat sur un site qui n’est pas partenaire – ou par manque de finesse d’analyse – sous prétexte que vous passez par hasard sur une page de vente de parapluie en vous trompant de lien, on vous propose à nouveau pendant des mois des parapluies
  • les propositions d’articles liés : au mieux – en terme d’intelligence artificielle, la présence de vocables proches déclenche l’affichage, mais le résultat est rarement pertinent ; au pire, les titres sont uniquement construits par des humains de façon à attirer le chaland, comme les « tops n », les photos bien choisies ou les citations croustillantes sorties de leur contexte, ce qui n’a rien d’artificiel, et pas grand chose d’intelligent !

Le point commun de tous ces exemples d’intelligence limitée ? Ces outils sont créés à l’aide d’algorithmes « classiques » dont le cheminement est entièrement décidé par un être humain, avec une capacité d’apprentissage – ou dans ce cas plus précisément d’auto-paramétrage – limitée. Les pistes les plus prometteuses en terme d’acquisition d’une forme d’intelligence par une machine se trouvent plutôt dans la construction de simili cerveaux génériques capables d’apprendre d’eux-mêmes, mais c’est un domaine encore balbutiant (voir les liens en fin d’article pour des détails sur la question).

Alors, à quand Skynet, Puppet Master et autre Omnius ?

Quand on remarque que l’intelligence artificielle est un objet de recherche constant depuis près de soixante dix ans, et que malgré cela, nous n’avons que des résultats très partiels et aucune perspective proche d’unification de ces résultats dans une entité complète, je pense qu’on peut affirmer que la création d’une intelligence artificielle est encore très lointaine et incertaine.

Par ailleurs, je rejoins Bill Gates sur le fait que l’intelligence que nous exploitons actuellement, l’intelligence faible, ne pose aucun problème même à long terme ; le domaine d’intervention de la machine est limité par nos choix, ainsi que sa capacité d’apprentissage, d’appréhension du réel et d’action sur le réel.

Une autre idée, dont je n’ai pas parlé car elle se situe à la frontière de l’artificialité, et qui apparaît dans l’excellent film Ghost in the shell, est la possibilité que l’intelligence apparaisse d’elle-même par combinaison d’entités simples que nous aurions créées. Elle me semble extrêmement peu probable, car d’une part elle suppose que nous ayons doté ces entités disparates de capacités de communication qui leur permette de constituer une entité supérieure par agrégation, et d’autre part, je ne vois pas quel processus amènerait un œil, une oreille, un nez, une bouche, etc. à se rassembler pour donner un être humain synthétique.

Enfin, la piste sérieuse d’apparition d’une intelligence artificielle, la création d’une copie d’un cerveau biologique couplée à un ensemble de dispositifs mécaniques et sensoriels, est d’une part une perspective très lointaine – comme vous pouvez le voir dans la première vidéo ci-dessous – et d’autre part me paraît contradictoire avec l’argument a priori valide apporté par Stephen Hawking que l’évolution d’une machine à base d’ordinateur se ferait à une vitesse nettement supérieure à celle d’un être biologique ; en effet, les mécanismes d’apprentissage sont les mêmes que ceux d’un être humain, et bien que les ordinateurs personnels actuellement à notre disposition possèdent grosso modo la même capacité de traitement théorique que notre cerveau (cf http://fr.wikipedia.org/wiki/Intelligence_artificielle#Estimation_de_faisabilit.C3.A9), on constate que la phase d’apprentissage n’est pas sensiblement plus rapide. Il se pourrait bien que nous soyons un dispositif particulièrement performants pour l’intelligence. Darwin 1 – Turing 0 ?

Le danger

Quand bien même nous serions à deux doigts sans le savoir de créer une intelligence artificielle forte, serait-elle réellement un danger pour l’humanité ? Si on se fie à l’art, on serait tenté de répondre un oui tonitruant : Frankenstein, 2001 odyssée de l’espace, Blade Runner, Terminator, le cycle de Dune, rares sont les exemples imaginaires de conséquences positives, et même la saga des robots d’Asimov qui institue des règles supposées protéger l’humanité, imposées Dieu seul sait comment aux robots, donne des exemples de contournement de ces règles. Dans une certaine mesure, la planète des singes offre un autre exemple de l’apparition d’une intelligence du même niveau que la nôtre et ayant des conséquences funestes, même si cette intelligence n’est pas artificielle.

Il est vrai que l’évolution darwinienne et la biologie nous enseignent que toute vie n’a pour but que de se multiplier, et que seules les circonstances et les limites des outils à sa disposition l’en empêchent ; l’homme, qui avec son intelligence a des moyens inégalables dans le monde animal pour soumettre son environnement à ses besoins, ne voit guère sa croissance menacée que par lui-même. Mais cette éventuelle intelligence – artificielle et née dans des circonstances différentes de la nôtre – aurait-elle nécessairement cette pulsion incontrôlable à l’expansion et à la domination ? Ces peurs ne seraient-elles pas qu’un énième avatar du récent détournement occidental des valeurs du siècle des lumières, progrès scientifique entraînant progrès technique entraînant progrès social, qui nous fait douter que le moindre progrès technologique puisse être positif ? Ne diraient-elles pas plus de choses sur nous-mêmes que sur les machines pensantes elles-mêmes ?

Pour aller plus loin

Deux conférences passionnantes sur les robots, à regarder dans l’ordre ci-dessous :

  • https://www.youtube.com/watch?v=giqEnlM8D_U : vidéo des rencontres sciences et humanisme 2014, traitant de façon générale la robotique et l’intelligence artificielle, avec des démonstrations de robots faisant de l’auto-apprentissage
  • https://www.youtube.com/watch?v=a6-9n-K2LYc : vidéo de l’espace des sciences de Rennes sur la robotique non humanoïde

Quelques livres :

  • de manière générale, l’oeuvre de Philip K. Dick, qui a passé sa vie à s’interroger ce qui nous pouvait différencier un humain d’une intelligence artificielle
  • le cycle de Dune de Franck Herbert, avec ses mentats et Omnius
  • La cité des permutants de Greg Egan : je trouve l’écriture de Greg Egan parfois indigeste, mais ses idées sont toujours dérangeantes ; dans ce livre, il imagine un système de simulation d’êtres humains physiquement morts, et pour éviter la stagnation et l’ennui dans cette vie éternelle, il embarque des extraterrestres évoluant indépendamment des humains simulés
  • La bionique – Quand la science imite la nature d’Agnès Guillot et Jean-Arcady Meyer, ou quand l’artificiel s’inspire de la nature

  • La conscience a-t-elle une origine ? Des neurosciences à la pleine conscience : une nouvelle approche de l’esprit de Michel Bitbol, qui aborde la question de la formation de la conscience