Catégorie : notes côté professionnel

ExtJS et Panel : le layout « absolute »

Après plusieurs heures de recherches, j’ai enfin compris comment fonctionnait le layout « absolute ».
L’utilité de la disposition "absolute", est qu’on peut positionner les éléments dans le conteneur à un endroit bien précis, au pixel près.
Voici l’astuce qui m’a fait perdre tellement de temps, et qui, je l’espère, vous en fera gagner :
D’habitude, sur tous les « layout » existants, lorsqu’on les définit, ils s’appliquent sur les éléments contenus. Et non pas sur le conteneur.
La seule exception se trouve avec le layout « absolute » : je le mets en gros et gras, parce que j’ai passé énormément de temps à trouver cette astuce :

Lorsqu’on utilise le layout « absolute », il faut toujours préciser aussi la largeur et la hauteur du conteneur, sinon ce dernier ne sera jamais affiché

Exemple concret :
Voici ce qui ne fonctionnait pas :
MonPanel = function(tab) {
    this.layout = 'absolute';
    this.border = false;
    MonPanel.superclass.constructor.call(this, {
        items: [{
            x: 0,
            y: 5,
            xtype: 'label',
            text: 'To:',
        }]
    });
};

Le panneau n’était pas affiché. Voici ce qui ne fonctionne :
MonPanel = function(tab) {
    this.layout = 'absolute';
    this.border = false;
    this.width = '100%';
    this.height = 150;
    MonPanel.superclass.constructor.call(this, {
        items: [{
            x: 0,
            y: 5,
            xtype: 'label',
            text: 'To:',
        }]
    });
};

Numéro hotline Linksys Cisco

08 25 54 01 11 0,15 € / min

Numéro Indigo (0,15 Euros TTC/minute depuis un poste fixe France Telecom ou coût lié à votre opérateur)

Bien évidemment les gens parlent un français très approximatif, voire plus qu’approximatif.

Bonjou’ Môsieur, je oué vous wappeler… vous appelez de quel pays ?
Ne wacrochez pas d’accow ?
Quel est votre pwénom ?

« Olivier »

Je vais vous wappeler…

[Je raccroche et j’attends]

Bonjour, Monsieur « Olivier » ?


No comments.

Je ne me permettrais pas de critiquer l’accent ou autre, si la personne avait été compétente, mais j’ai perdu 20 minutes pour apprendre ce que j’avais déjà fait, et que la personne n’avait pas du tout compris ce que je voulais faire, elle a été demander au « département technique »… elle n’avait pas compris parce qu’elle n’était pas compétente et parce qu’elle ne parlait pas correctement français (j’ai dû me répéter pas mal de fois)… vive la mondialisation.

bazaar : tutoriel, et exemple concret d’utilisation

Je fais quelques petites notes personnelles au fur et à mesure de l’utilisation de Bazaar, au cas où cela serve à quelqu’un :

La première chose, la plus importante à savoir, pour les non-anglophones :

Du point de vue de bazaar, « checkout«  signifie « faire un lien entre« .

Par exemple :

  • on fait un lien entre deux répertoires A et B (« bazaar checkout A B »)
  • pour toute validation de modification avec bazaar (« bazaar commit » ou autre), que ce soit sur A ou sur B, bazaar va aussitôt les répercuter de l’autre côté (sur B ou A).

(1) Créer un dépôt « central » distant qui hébergera TOUS les projets

Ici, dans « /rep_bazaar/iwn_bazaar/ » :

> bzr init-repo --no-trees \
    sftp://bazaar@serveur_ftp/rep_bazaar/
bazaar@serveur_ftp's password:
Shared repository (format: 2a)
Location:
  shared repository: sftp://bazaar@serveur_ftp/rep_bazaar/
>

(2) Créer un projet distant : ici, le projet est « projet_web« 

– D’après la config précédente, il faut le créer dans une branche du dépôt central = « /rep_bazaar/projet_web/ » :

> bzr init sftp://bazaar@serveur_ftp/rep_bazaar/projet_web
bazaar@serveur_ftp's password:
Created a repository branch (format: 2a)
Using shared repository: sftp://bazaar@serveur_ftp/rep_bazaar/
>

(3) En local, initialiser un répertoire ‘vide’ qui sera celui de référence à partir duquel toutes les branches futures (dev, preprod et prod, etc.) vont dériver

(!!) dans la ligne de commande, il y a le répertoire distant ET un répertoire destination, ici « website_reference » :

> mkdir website_reference
> bzr  \
    checkoutsftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    website_reference

Attention !

D’après ce que j’ai compris, il ne faut pas toucher aux sources de références, parce qu’elles vont être copiées sur les environnements de dev, preprod et prod.

(4) Ajouter les fichiers source dans le répertoire de référence :

> cp -R website/* website_reference/

(5) Dire à bazaar d’ajouter tous les fichiers :

> cd website_reference/
~/website_reference # bzr add
(
Énorme liste de fichiers :
adding blabla/blabla.png
..
adding drupal/blabla/..
...
adding drupal/.../blabla.gif
)

(6) Valider les modifs en local avec un commentaire pour le dépôt #1 :

~/website_reference # bzr commit -m "Fichiers originaux"
(
Énorme liste de fichiers :
adding ...
..
added ws/blabla.php
...
added xml/xx/blabla.xml
)
~/website_reference #

(!!) On peut donner en local un nom différent du nom de la branche distante !

Mais comme ça risque de devenir rapidement le bazar (ahah), j’ai choisi de donner des noms identiques au répertoire du dépôt distant et aux répertoires locaux :

(7) Création de la branche de développement sur le dépôt distant :

> bzr branch sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev

(8) Lier la branche distante à un répertoire local

(!) je répète : on peut donner en local un nom différent du nom de la branche distante, mais je pense que c’est à éviter, donc :

> mkdir projet_web
> mkdir projet_web/dev
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    projet_web/dev
bazaar@serveur_ftp's password:
>

(9) Création de la branche de préproduction :

Deux mêmes ordres que pour la branche de développement (sauf répertoire final) :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/preprod
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/preprod \
    projet_web/preprod
bazaar@serveur_ftp's password:
>

(9) Création de la branche de production :

Deux mêmes ordres que pour la branche de développement (sauf répertoire final) :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/prod
> bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/prod \
    projet_web/prod
bazaar@serveur_ftp's password:
>

(10) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun, mais aussi en local :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

(11) Créer les sous-branches pour les développeurs :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/autre_dev
> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier

(12) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |
  +--- preprod
  |
  +--- prod

NB : en local, les branches n’ont pas été créées, donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

(13) Exemple personnel : ma branche de développement pour la cellule médicale v 2.0 :

Nb : on crée encore une branche distante, rien n’est encore fait en local :

> bzr branch \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier/nouveau_developpement

(13) Arrivé ici, le schéma est ainsi :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

NB : en local, les branches n’ont pas été créées, donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |
  +--- preprod
  |
  +--- prod

A partir de maintenant, on peut refaire en local toutes les branches qui n’y sont pas encore (autre_dev, olivier, nouveau_developpement).

Mais je choisis, par exemple, de ne faire que mes branche locales à moi (= olivier) :

Je fais le lien (= checkout) entre olivier et olivier distant :

>bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier \
    projet_web/dev/olivier

Je fais le lien (= checkout) entre nouveau_developpement et nouveau_developpement distant :

>bzr checkout \
    sftp://bazaar@serveur_ftp/rep_bazaar/projet_web/dev/olivier/nouveau_developpement \
    projet_web/dev/olivier/nouveau_developpement

(14) Résultat final :

Sur le site de dépôt commun :

projet_web
  |
  +--- dev
  |     |
  |     +--- autre_dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

En local, certaines branches n’ont pas été créées (volontairement) donc en local c’est ainsi :

projet_web
  |
  +--- dev
  |     |
  |     +--- olivier
  |            |
  |            +--- nouveau_developpement
  |
  +--- preprod
  |
  +--- prod

A partir de maintenant, en pratique

En pratique, il me suffit : de travailler sur le répertoire nouveau_developpement puis de faire toutes mes modifs, mes évolutions.

Une fois que je pense que tout est bon :

  • Aller dans le répertoire nouveau_developpement
  • Faire un commit :
    bazaar commit -m "Commentaire mise à jour"
  • Automatiquement, les modifications vont être répercutées sur ma branche distante (= sur le site de dépôt commun).

McAfee : le retour de la vengeance de la merde

Bah oui !
Je dis ici que McAfee est une grosse merde, et j’en donne les conséquences concrètes de ce qu’il a coûté en temps aux entreprises.
Et puis je redis ici que McAfee est une grosse merde, et j’en donne les conséquences concrètes de ce qu’il a coûté en temps aux entreprises, mais pour encore une autre raison, toute aussi lourde et stupide.

Et là il a encore frappé un grand coup dans le cadre de logiciels pourris :
Cliquez ici, une explication claire et précise du logiciel qui a fait planter grave Windows.
Ca a été le cas aussi chez nous où deux PC ont été bloqués et ça a coûté la matinée complète de travail inutile pour réparer les dégâts à notre spécialiste département faxing, et à un développeur :
http://www.clubic.com/antivirus-securite-informatique/logiciel-antivirus/mcafee/actualite-336778-mcafee-faux-positif-planter-windows-xp.html

Et enfin l’article qui couronne le tout : celui de zdnet (cliquez ici pour le lire en entier) :

Je cite :

En raison d’un fichier de mise à jour insuffisamment testé, des milliers d’ordinateurs sous Windows XP SP3 ont été victimes de reboot en boucle. Plus de 1000 magasins d’un distributeur australien ont ainsi été impactés. McAfee a présenté des excuses.

Linux et Applications Windows : ça marche !

Je suis tout simplement impressionné.
En quelques clicks d’installation, j’ai installé « Wine ».
Tout a fonctionné du premier coup.
J’ai copié collé le répertoire dans lequel tournait notre application de téléphonie :
Et voilà le résultat :
Image petite du logiciel Windows sous Linux
Ça fonctionné du premier coup !
Je suis vraiment impressionné.
Donc, pour l’instant, tant que je n’ai pas besoin de fonctionnalités particulières, je reste sous Linux.
Je dois avouer que le seul programme qui me manque c’est Photoshop.
Pour tout le reste, je m’en passe allègrement !

Quand je clique sur arrêter pour arrêter le PC, c’est simple :

  • sous Windows, il met montre en main plus d’une minute, et encore… je ne suis même pas sûr qu’il s’arrête pour la simple et bonne raison qu’il y a des tonnes de programmes : un anti virus, un anti spam, le logiciel de téléphonie qui ne veut quitter sous aucun prétexte, le logiciel d’archivage, etc. et des fois ils se gênent tous entre eux ;
  • sous Linux, ça met 4 secondes montre en main, c’est véridique !

Linux : exemple php pratique pour grep, awk, sort, uniq et xargs

Ci-suivent quelques étapes qui expliquent l’utilisation des outils grep, awk, sort et uniq. C’est juste un exemple concret et pratique, n’imaginez pas un truc immense ! J’espère que cela vous donnera des idées, si un jour vous avez besoin de faire quelque chose dans le genre.

Objectif : lister tous les fichiers php du répertoire courant, qui font appel à l’ordre « date() ».

Donc :

  • Ordre « find » de Linux qui liste tous les fichiers d’un répertoire et de ses sous-répertoires :
    >find .
    ./robots.txt
    ./tarification2.php
    ./partenaire_demande.php
    ./img
    ./img/menu-gb_02-Carte-image_02_o.gif
    ./img/fleche_blc_fond_bleu.gif
    ./img/old_get_adobe_reader.gif
    ./img/menu-gb_02-Carte-image_05_o.gif
    ./img/ste_gestion_over.gif
    ./img/cbp_attest_ass_over.gif
    ./img/index_06.jpg
    [etc. etc.]
  • Ordre « grep » de Linux qui ne prend que les fichiers « qui se terminent par php » :
    >find . | grep php$
    ./img/index.php
    ./aore/verlogin.php
    ./aore/tarication2.php
    ./aore/img/iex.php
    ./aore/corats.php
    ./aore/ind.php
    ./aore/ccts.php
    [etc. etc.]
  • Ordre « xargs » de Linux qui dit « je vais te donner un programme (ici « grep »), et tu lui fais suivre ligne par ligne les résultats. Pour la note, « grep 'date(' [nom_de_fichier] » vérifie si dans le fichier [nom_de_fichier], il y a ‘date(‘ :
    >find . | grep php$ | xargs grep 'date('
    ./pe.php: $date=date("Y-m-d H:i:s");
    ./partde.php: $date_french=date("d-m-Y H:i:s");
    ./as/vergin.php:$date=date("Y-m-d H:i:s");
    ./as/cs.php:$date=date("Y-m-d H:i:s");
    ./as/cs.php:$date=date("Y-m-d H:i:s");
    ./as/cs.php: $date=date("d-m-Y H:i:s");
    ./as/sis.php:$date=date("Y-m-d H:i:s");
    ./ae/sis.php:$date=date("Y-m-d H:i:s");
    ./ae/stre_cle.php:$date_heure = date("Y-m-d H:i:s");
    ./ae/stre_cle.php:$date = date("Y-m-d");
    [etc. etc.]
  • Ordre « awk » qui prend la ligne en cours, considère que les « : » sont les séparateurs (-F:), et n’affiche en sortie que le premier enregistrement ('{print $1}') pour chaque ligne :
    >find . | grep php$ | xargs grep 'date(' | awk -F: '{print $1}'
    ./re/vein.php
    ./re/ctrs.php
    ./re/ctrs.php
    ./re/ctts.php
    ./re/sises.php
    ./re/sires.php
    ./re/sire_cle.php
    ./re/sire_cle.php
    ./re/sire_cle.php
    ./re/sire_cle.php
    ./ae/mu.php
    ./ae/mu.php
    [etc. etc.]
  • Ordre « uniq » qui prend la totalité de ce qu’on lui passe, et supprime les doublons :
    >find . | grep php$ | xargs grep 'date(' | awk -F: '{print $1}' | uniq
    ./re/vein.php
    ./re/ctrs.php
    ./re/ctts.php
    ./re/sises.php
    ./re/sires.php
    ./re/sire_cle.php
    ./ae/mu.php
    [etc. etc.]
  • Ordre « sort » qui trie par ordre alphabétique :
    >find . | grep php$ | xargs grep 'date(' | awk -F: '{print $1}' | uniq | sort
    ./ae/mu.php
    ./re/ctrs.php
    ./re/ctts.php
    ./re/sises.php
    ./re/sires.php
    ./re/sire_cle.php
    ./re/vein.php
    [etc. etc.]

Et voilà ! Une minute pour taper cette commande, et on a la liste de tous les fichiers à vérifier pour être certain qu’il n’y aura plus de warnings() lors de l’utilisation de date() dans ces fichiers php.
Pour la note, j’ai eu besoin de faire ça parce que ces fichiers devaient avoir en tête l’initialisation préalable date_default_timezone_set(). Ces fichiers sont les fichiers d’un très vieux site qu’il faut faire fonctionner en mettant au minimum les mains dedans, c’est ce que j’ai tenté de faire (pour préserver aussi ma santé mentale).

(Update 6 février 2011)
Sur ce site ici qui me cite, il y a une réponse très intéressante : lorsqu’on connait bien l’ordre « find« , on peut résumer tout mon article en une seule ligne et un seul ordre :

find -iname "*.php" -exec grep "\Wdate(" "{}" \; -print

Bon, le résultat ne renvoie pas que les fichiers, mais il est bien formaté, c’est aussi très pratique. Voici un exemple de sortie de cet ordre :

  $debloc_jj = (int) date('d');
  $debloc_mm = (int) date('m');
  $debloc_aa = (int) date('Y');
  echo '<li>Lancement des calculs à '.date("H:i:s").'.</li>';
  echo '<li>Terminé à '.date("H:i:s").'.</li>';
./_tests_unitaires/tarifs_generali/tarifs_2010.php
  $debloc_jj = (int) date('d');
  $debloc_mm = (int) date('m');
  $debloc_aa = (int) date('Y');
./_tests_unitaires/verifs.php
  $debloc_jj = (int) date('d');
  $debloc_mm = (int) date('m');
  $debloc_aa = (int) date('Y');
./_tests_unitaires/verifs_multi.php

McAfee : à éviter à tout prix !

Je disais ici que c’est un vrai logiciel de merde.
C’était il y a presque deux ans.
Eh bien j’ai confirmation que c’est toujours d’actualité : McAfee est toujours une méga merde.
Regardez le commentaire ici : lorsqu’ils ont découvert une faille sur Firefox, le type qui a été victime de l’attaque explique :

Voici la traduction faite par moi-même de son commentaire :

La vulnérabilité de Firefox3.6.1 est réelle.
J’ai été touché par elle la nuit dernière, par un site pornographique : ça a planté Firefox et toutes ses fenêtres et onglets, et ça a lancé le programme de prise de contrôle à distance (« rootkit ») sur mon PC (sous Windows XP-pro).
J’ai éteint mon PC, j’ai pris le disque, j’ai scanné le disque avec mon antivirus Avast. Ce dernier a detecté « HTML:RedirME » et « Prontexi » dans le cache de Firefox ; plus d’information ici.
Je n’avais pas Avast qui tournait à ce moment, mais c’était McAfee et McAfee n’a rien vu. Même pas un tout petit signe. Complètement aveugle.

Vous avez tout ici (en Anglais), commentaire n. 12 :
http://blog.mozilla.com/security/2010/02/22/secunia-advisory-sa38608/

Pour information, Avast est gratuit (si je ne m’abuse)…

Python : mes premiers essais

Bon, sur cet article ici, j’ai traduit tout le vécu d’un auteur, et j’ai voulu tester par moi même.

En pratique, j’ai installé un dictionnaire de Français entièrement gratuit, et je voulais récupérer les mots Français, sans la définition (je ne dirai pas pourquoi par contre hahahah).

Donc je regarde les fichiers, c’est du XML.
Ok donc il me faut juste un parseur.
En Delphi, ça m’aurait pris disons… une trentaine de minutes.
Eh bien pour mon premier script en Python, ça m’a pris… 10 minutes.
Oui oui je n’exagère pas : 10 minutes, j’ai lancé le chrono pour voir si j’allais être rapide ou pas.
Voilà mon script :

1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # r = open('/datas/dictionnaire/test
5
6 import types, fileinput
7
8 def process(line):
9 if line[0:7] == ' 0):
12 sub = sub[:sub.find(' ')]
13 if (sub.find(',') > 0):
14 sub = sub[:sub.find(',')]
15 print(sub)
16
17 for line in fileinput.input():
18 process(line)

Incroyable. Effectivement, en pratique c’est vraiment ce que j’ai mis sur mon article précédent : tout est clair, lisible, la documentation aide bien, et c’est extrêmement rapide, en tous les cas sa rapidité suffit amplement pour faire toutes les tâches de scripts de base que l’on veut.

Je suis extrêmement content, à part depuis la découverte de la librairie ExtJs, qui est très impressionnante, ça allait faire longtemps que je n’avais pas été autant enthousiasmé (du point de vue informatique, j’entends).

Débutants : pourquoi le langage Python ?

J’ai fait cette traduction, vous pourrez trouver l’article d’origine ici.

Pourquoi Python ?

Par Eric Raymond

Le cardinal Biggles a gardé Eric au confessionnal pendant quatre heures avant d’entendre cette confession…
La première fois que j’ai dû me pencher sur Python… c’était par pur accident. Et je n’ai pas vraiment apprécié ce que j’ai vu à ce moment là. C’était début 1997, et le livre sur la programmation Python de Mark Lutz (O’Reilly & Associates) venait tout juste de sortir. Parfois les livres O’Reilly arrivent sur le pas de ma porte, en suivant un processus complètement aléatoire pour lequel j’ai abandonné tout essai de compréhension.
L’un deux était « Programmation Python ». Comme je collectionne les langages de programmation, j’ai trouvé cela intéressant. Je connais déjà une bonne douzaine de langage génériques, j’ai écrit quelques compilateurs et des interpréteurs pour le fun, et j’ai déjà designé quelques langages qui avaient des objectifs spécifiques et qui devaient suivre un certain formalisme. Récemment j’ai d’ailleurs écrit SNG, un langage écrit spécifiquement pour manipuler des images PNG (Portable Network Graphics). Les lecteurs intéressés peuvent regarder la page en question ici : http://www.catb.org/~esr/sng/. J’ai aussi écrit quelques implémentations de vieux langages, vous pouvez voir ça sur ma page du musée de la rétro-programmation (« Retrocomputing Museum page ») ici : http://www.catb.org/retro/.
Concernant Python, j’avais juste entendu que c’était un langage de « scripting », donc un langage destiné à écrire des scripts, avec son propre gestionnaire de mémoire intégré, et de grandes facilités pour appeler et coopérer avec d’autres programmes. Je me suis donc plongé dans « La Programmation Python » avec une idée bien précise en tête : que fait Python que Perl ne peut pas faire ?
Perl, bien sûr, était le poids lourd des langage modernes de scripting (NDT : c’était en 2000). Il est souvent devenu le langage de prédilection pour les administrateurs système en lieu et place du langage de scripting shell, souvent grâce à sa librairie UNIX et ses appels système, et aussi grâce à sa collection énorme de modules Perl construits par une communauté Perl très active. En 2000, ce langage est estimé être à l’origine de 85% du contenu « live » que l’on peut trouver sur le Net. Larry Wall, son créateur, est souvent considéré, à juste titre, comme l’un des leaders les plus importants dans la communauté Open Source, et apparait souvent en troisième place derrière Richard Stallman, et Linus Torvalds dans le panthéon des hackers demi-dieux.
A cette époque, j’avais utilisé Perl pour plein de petits projets. J’avais trouvé ce langage assez puissant, même si la syntaxe et quelque autres aspects de ce langage semblaient rebutants. Je pensais que Python avait un sacré chemin à faire en tant que nouveau langage de script, et au moment où j’ai commencé ma lecture, je me suis intéressé d’abord à ses aspect qui le rendaient unique.
J’ai fait immédiatement un mauvais trip sur la première chose que tout le monde remarque quand on lit un script Python pour la première fois : le fait que les espaces (= l’indentation) signifie quelque chose dans la syntaxe du langage. Ce langage n’a aucun délimiteur du type des crochets que l’on trouve en C ou en Perl ; au lieu de cela, les changements dans l’indentation délimitent naturellement les groupes. Et, naturellement, comme la plupart des hackers, lorsque j’ai réalisé cet état de fait, je suis retombé immédiatement dans une phase de dégoût.
Je suis suffisamment vieux pour avoir programmé en FORTRAN dans les années 1970. Au jour d’aujourd’hui, personne – ou presque – ne l’a jamais fait, mais le fait de l’avoir fait a mis en tête à ceux qui ont dû « subir » ça, quel point il est énervant de pratiquer le principe de « champs prédéterminés ». En fait, le terme « formatage libre » utilisé pour décrire le nouveau style de langage orienté « mot-clé », par exemple en Pascal et en C, a presque été oublié ; c’est parce que tous les langages d’aujourd’hui sont basés sur ce principe. Enfin presque tous. C’est difficile de blâmer quelqu’un, si, lorsqu’il voit un code Python, réagit comme s’il avait marché dans une bouse de dinosaure.
C’est un peu ce que j’ai ressenti. J’ai alors lu le reste de la description du langage, sans trouver quelque chose d’autre d’intéressant. Je n’y voyais aucune raison de recommander Python, à part le fait peut-être que la syntaxe semblait un peu plus claire que celle de Perl et qu’il semblait plutôt facile de créer des éléments d’interface utilisateur (« GUI elements ») tels que les boutons et les menus.
J’ai remis le livre sur l’étagère, en pensant qu’il faudrait que je me fasse un petit projet orienté GUI en Python, juste pour m’assurer que j’avais bien compris les fondements du langage. Jamais je n’aurais cru que ce que j’allais voir éclaterait littéralement la compétition avec Perl.
C’est à ce moment là qu’une conspiration de choses inutiles à faire s’est organisée autour de moi, et j’ai mis la priorité de « Test Python » tout en bas de la liste des choses à faire. Cela dura plusieurs mois. Entretemps j’ai même écrit le livre « The Cathedral and the Bazaar ». Mais j’ai tout de même trouvé le temps d’écrire quelques programmes en Perl, dont deux assez gros et complexe. L’un deux, « keeper », est un assistant qui est encore utilisé (NDT : en 2000) lors de soumissions de nouveaux fichiers qui arrivent au gestionnaire d’archives du laboratoire Metalab. Il génère les pages web que vous pouviez voir à metalab.unc.edu/pub/Linux/!INDEX.html. L’autre, « anthologize », était utilisé pour générer automatiquement la documentation PostScript de la sixième édition de l’archive des HowTos du Projet de Documentation Linux. Ces deux programmes sont disponibles à Metalab.
Écrire ces programmes en Perl m’a laissé progressivement un gout amer. Les gros projets semblaient transformer les petites choses ennuyeuses de Perl en problèmes sérieux et récurrents. La syntaxe qui parait simplement un peu excentrique au début, se transforme au bout de plusieurs centaines de lignes en une jungle vierge pratiquement impénétrable, et je ne vous raconte pas quand il s’agit de milliers de lignes. La maintenance devient exponentielle en fonction du nombre de lignes de code. Beaucoup de ces problèmes ont été résolus en ajoutant des patches à Perl (objets, variables locales, « use strict », etc.), mais cela m’avait bien refroidi.
De plus, la résolution de bogues, déjà anormalement difficile à résoudre, se transformait en mission presque impossible si on s’absentait quelques jours pour faire autre chose. Plus le temps passait, plus je me battais avec les problèmes du Perl au lieu de me pencher sur les problèmes de l’application proprement dite. Le pire de tout, c’est que le code devait être sale. C’est simple : des programmes laids et sales sont comme des ponts suspendus : ils ont beaucoup plus de chances de s’effondrer que des ponts classiques, parce que la manière dont nous percevons la beauté (particulièrement les ingénieurs) est intimement reliée à notre capacité de gérer et de comprendre la complexité sous-jacente. Un langage qui empêche, de par sa nature, d’écrire un code élégant, empêche aussi d’écrire un bon code.
Avec une expérience d’une vingtaine de langages dans mes valises, je pouvais distinguer tous les petits signes qui me disaient que j’avais poussé tel ou tel langage jusqu’à ses propres limites. A la mi-1997, je me disais « il doit y avoir une meilleure solution ». Et je me suis mis à rechercher un langage de scripting plus élégant.
Je n’ai même pas imaginé replonger dans le C. Les jours où il semblait censé d’écrire ses propres allocations mémoire et son propre gestionnaire d’allocations sont largement révolus, mis à part certaines niches de développement comme l’écriture de code pour le noyau, le graphisme 3D, bref, des endroits où on doit gagner un maximum de temps machine et par là même un contrôle personnalisé de l’utilisation mémoire.
Dans toutes les autres situations, il est impensable d’imaginer passer du temps en plus, à déboguer les débordements de buffer (buffer overruns), la mauvaise gestion des pointeurs, les fuites mémoire générées par les malloc/free et tous les autres inconvénients liés à cela. C’est bien mieux de se dire que la machine va mettre un peu plus de temps et que le programme va consommer un peu plus de mémoire, et économiser sur le facteur humain. C’est d’ailleurs cette stratégie qui a conduit à l’explosion de Perl vers le milieu 1990.
J’ai commencé par tester Tcl, et j’ai rapidement découvert que c’était encore pire que Perl. Le vieux LISPer que je suis s’est alors penché sur les variantes de Lisp et Scheme, mais comme cela l’a été depuis le début pour Lisp, même un bon design est rendu complètement inutile s’il n’existe aucune documentation (ou très peu) sur les liens POSIX/UNIX, et si la communauté est très faible et, de plus, fragmentée. Si Perl est devenu populaire ce n’est pas par accident. La plupart de ses compétiteurs étaient simplement plus mauvais.
La seconde fois où je me suis penché sur Python était aussi accidentelle que la première fois. En octobre 1997, j’ai reçu plein de questions sur « fetchmail », la plupart venant d’utilisateurs basiques, qui montraient clairement qu’ils avaient des difficultés à générer des fichiers de configuration pour mon utilitaire « fetchmail ». La configuration du programme utilise une syntaxe classique, du style UNIX, mais peut devenir extrêmement compliquée à partir du moment où un utilisateur a des comptes POP3 et IMAP sur plusieurs sites. Par exemple, voici un fichier de configuration : Listing 1.
J’ai alors décidé d’écrire un éditeur facile à appréhender, pour aider à la configuration : « fetchmailconf ». L’objectif était clair : cacher complètement la complexité de la syntaxe derrière une interface utilisateur simple, claire et conviviale, avec des boutons de sélection, et des fiches simples à remplir.
Rien que l’idée de faire ça en Perl me faisait peur. J’avais déjà vu du code GUI en Perl, et c’était un vague mélange de Perl et de Tcl qui était encore plus laid au final que mon propre code Perl. C’est à ce moment là que je me suis souvenu de Python, que j’avais à peine survolé six mois auparavant. C’était le moment ou jamais.
Bien sûr, l’objectif allait sûrement tester sévèrement mes compétences en tant que personne inexpérimentée dans ce langage. La première chose que j’ai revue était cette fameuse indentation. Cette fois néanmoins j’ai passé outre, et j’ai commencé à taper un code grossier pour faire quelques éléments GUI. Aussi bizarre que cela puisse paraitre, après une vingtaine de minutes, ce procédé d’indentation ne m’a plus du tout paru anormal. J’ai juste indenté comme je l’aurais fait en C, sans me poser plus de question, et ça a fonctionné.
C’était ma première surprise. La seconde est venue après plusieurs heures de codage du projet, lorsque j’ai remarqué durant mes « va-et-viens » entre le programme et le livre sur Python, que j’écrivais du code pratiquement aussi vite que je le tapais. Lorsque j’ai réalisé cela, j’ai été comme électrifié. Si on y pense bien, une grosse partie de l’effort du codage correspond à tous les moments où lorsqu’on veut résoudre un problème, cette résolution ne s’écrit pas comme on se la représente mentalement. Et on met toujours beaucoup de temps à réaliser que ce que l’on a écrit ne correspond pas forcément à la résolution du problème. Ce principe aide énormément à mesurer la qualité d’un langage : lorsque vous apprenez un langage, combien de fois il vous a fallu ré-écrire une portion de code tant que vous ne connaissiez pas bien ce langage.
Lorsque vous écrivez un code qui fonctionne presque aussi vite que vous le tapez, vous ne revenez pratiquement jamais en arrière, et en général cela signifie que vous maitrisez parfaitement ce langage. Mais ce n’était pas du tout logique, parce que c’était mon premier jour de Python et je faisais régulièrement des pauses pour regarder, dans le livre, les appels à faire aux différentes librairies !
C’est le premier indice qui m’a fait penser que Python avait un design exceptionnellement bon. La plupart des langages ont des spécificités et des choses si particulières à apprendre qu’il faut toujours énormément de temps avant de pouvoir bien les maitriser. Python était le premier langage qui invalidait ce principe.
J’ai mis très peu de temps avant de comprendre des particularités. J’ai écrit « fetchmailconf », avec GUI, en six jours, dont deux ont été utilisés pour apprendre Python lui-même. Cela reflète une autre propriété utile de ce langage : il est compact. Vous pouvez avoir toutes ses caractéristiques facilement et rapidement en tête (tout au moins son concept et ses librairies de base). C est un langage connu pour être compact. Perl est connu pour ne pas l’être. On a beau dire ce qui a fait le succès de Perl : « Il n’y a pas qu’une seule manière de l’écrire », dans tous les cas, ce n’est jamais concis.
Le moment le plus dramatique de ma découverte était encore à venir. Mon design avait un problème : il était facilement possible de générer un fichier de configuration, mais après, lorsqu’il fallait mettre les mains dans ce fichier de configuration on retombait à nouveau dans le problème d’origine.
Le parseur du fichier de configuration de « fetchmail » est plutôt élaboré. Pour tout dire, il est écrit en YACC et Lex, deux outils classiques UNIX qui sont utilisés pour générer le code C d’un parseur. Pour que « fetchmailconf » puisse éditer des fichiers de configuration existants, je me suis dit que je devais faire un parseur fonctionnant à l’identique en Python. Je n’en avais pas du tout envie, d’une part à cause de tout le travail que cela impliquait, et d’autre part parce que je n’étais pas sûr que les comportements allaient être de manière fiable absolument identiques. C’était bien la dernière chose dont j’avais besoin : du boulot supplémentaire pour tenir à jour deux parseurs en même temps lors des futures évolutions de « fetchmail ».
Ce problème m’a bloqué pendant quelque temps. Puis j’ai eu une inspiration subite : je vais laisser « fetchmailconf » se servir du parser de « fetchmail » ! J’ai alors ajouté l’option –configdump à « fetchmail » afin qu’il puisse parser un fichier « .fetchmailrc » et en sortir un fichier sous la forme d’un initialiseur Python. Voici un exemple de fichier qu’il était possible de sortir : Listing 2 (pour gagner de la place un peu d’information pas liée au sujet a été supprimée).
Python pouvait évaluer la sortie de la commande « fetchmail –configdump ».
Ce n’est pas fini ! Je ne voulais pas que « fetchmailconf » puisse lire la configuration courante, mais je voulais la transformer en arbre d’objets dynamiques. Il devait y avoir trois types d’objets dans cet arbre :

  1. Configuration (l’objet de plus haut niveau qui représente toute la configuration)
  2. Site (objet qui représente entièrement l’un des sites)
  3. User (les données d’un utilisateur particulier rattachées à un site)

Le fichier d’exemple précédent décrit cinq objets « Site », chacun ayant un objet « User » rattaché à lui.
J’avais déjà écrit ces trois classes d’objets (c’est ce qui m’a pris quatre jours, pendant lesquels j’ai surtout passé du temps à mettre les objet GUI à la bonne place). Chaque classe avait une méthode qui pouvait faire surgir un pop up d’édition qui éditait les données de l’objet proprement dit. Il ne me restait plus qu’à transformer les données lues d’origine en objets réels.
J’ai tout d’abord imaginé écrire du code qui connaitrait les informations de chaque classes et utiliserait ces connaissances afin de faire une correspondance, mais j’ai rapidement oublié cette idée, parce qu’en imaginant ajouter des nouveautés il y aurait des problèmes de compatibilité.
Ce que je voulais vraiment c’était un code qui analyserait la forme et les membres de l’initialiseur, en demandant directement au code qui définissait les classes, et qui s’ajusterait automatiquement afin de faire concorder les données d’un côté et les objets de l’autre.
Ce genre de choses est appelé « bidouille de méta-classes » (« metaclass hacking ») et est souvent considéré comme quelque chose d’ésotérique et d’effrayant (de la magie noire). La plupart des langages « orienté-objet » n’ont pas cette capacité ; pour ceux qui le peuvent (Perl y compris), cela a tendance à rendre le code plutôt complexe et dur à appréhender. J’avais déjà été impressionné par la rapidité d’apprentissage de Python mais là on arrivait à un vrai test. Quelle complexité de code est-ce que cela allait engendrer ? Je savais par expérience que cela allait être difficile, et même en arrivant à mes fins, le résultat allait être sale. J’ai tout de même pris le livre et je me suis penché sur les capacités Python concernant les méta-classes. La fonction résultat est dans le Listing 3, et le code qui l’appelle est dans le Listing 4.
Ça n’a pas l’air super compliqué soi-disant pour de l’affreuse magie noire, pas vrai ? Trente deux lignes en comptant les commentaires. En sachant juste ce que j’ai dit sur la structure de la classe, le code appelant est compréhensible. Mais ce n’est pas la taille qui est vraiment impressionnante. Tenez-vous bien : il m’a fallu quatre-vingt-dix minutes pour écrire ce code, et il a fonctionné correctement la première fois où je l’ai testé.
Dire que j’étais épaté est un euphémisme. Rien que le fait d’avoir un code qui fonctionne dès la première écriture est déjà remarquable en soi ; mais en plus, c’était ma première bidouille avec des méta-classes, six jours après avoir appris le langage ! Même en essayant d’imaginer que je suis un sacré bon hacker, ça n’en resterait pas moins une preuve vivante de la clarté, de la concision, et de l’élégance du design de Python.
C’est bien simple : il n’y a aucune possibilité simple de faire cela en Perl, même avec mon expérience plutôt poussée avec ce langage. C’est à ce moment là que j’ai réalisé que c’en était fini de Perl.
C’était un moment très intense. Bon, j’avoue qu’avec du recul, on peut juste constater que ce n’était qu’une bidouille subtile et élégante rendue possible grâce la souplesse de Python. L’utilité à long terme d’un langage ne se trouve pas que dans la possibilité, justement, de faire des bidouilles subtiles, et élégantes, mais aussi dans l’utilité qu’on a du langage au jour le jour. Le travail au jour le jour ne consiste pas qu’à écrire de nouveaux programmes, mais principalement à en lire et à en modifier des existants.
La vraie conclusion de cette anecdote est celle-ci : plusieurs mois après avoir écrit « fetchmailconf », je pouvais toujours lire et comprendre mon code sans avoir de gros effort de concentration pour tout comprendre à nouveau. Je stresse déjà rien qu’en imaginant avoir à replonger dans le code de « keeper » ou « anthologize » à nouveau, mais « fetchmailconf » ne pose aucun problème.
Perl a toujours son utilité. Pour des petits projets (100 lignes ou moins) qui impliquent énormément de filtres de texte (« pattern matching »), je pense que je pencherai peut-être vers une bonne expression régulière Perl plutôt que du code Python. En regardant les scripts « timeseries » et « growthplot » Perl de la distribution « fetchmail », je peux dire que ce sont presque des choses qu’on pourrait faire en utilisant une bonne combinaison de awk/sed/grep/sh. Pour tout le reste, je préfère de loin les vertues de Python, je pense que si vous testez, vous en arriverez certainement à la même conclusion.

Autohotkey : un programme à tout faire, vraiment tout !

J’ai eu une discussion récemment avec un type qui a pris mal le fait que je me sois servi d’autohotkey pour aller plus vite que les autres dans le jeu Dofus.

En fait c’est amusant, parce que la discussion que j’avais avec ce type n’avait aucun rapport avec Dofus : en fait je voulais me servir de autohotkey pour générer un labyrinthe dans l’éditeur de circuit TrackMania.

Vous remarquerez que j’ai mis cet article dans la catégorie « games » mais aussi « notes côté professionnel ». Pourquoi ? Je vais vous donner un exemple de ce que j’ai fait avec le géniallissime programme qu’est autohotkey.

« Oui », je me suis servi de autohotkey pour accélérer ma progression dans le jeu massivement multijoueurs qu’est Dofus. Alors que des joueurs passent des jours entiers, dans le jeu, à couper du bois, à aller pêcher, à aller à la mine, pour récolter des choses et les revendre, moi, je lançais mon programme le soir et le lendemain j’avais mon stock plein de matières premières qu’il ne me restait qu’à vendre. C’est sûr que dans ce cadre, plein de joueurs râlent ! Mais que voulez vous c’est la vie. Cela dit je viens de surprendre plusieurs joueurs mécontents qui disent que autohotkey est un programme de triche. Non, c’est faux. Autohotkey sert à envoyer des touches et des mouvements de la souris à l’ordinateur, exactement comme si c’était un être humain qui l’avait fait. C’est d’ailleurs pour cela que personne ne m’a jamais surpris en mode « automatique » à Dofus. Mais le côté professionnel est celui-ci : un jour, La Mondiale, grosse société d’assurance avec laquelle nous avons travaillé pendant trois années, nous envoie ses tarifs pour que nous les intégrions dans notre base de données. Seul problème : tous leurs tarifs étaient dans un gros fichier Excel. Et sur plusieurs onglets qui plus est ! Alors que notre programme d’administration, lui, demandait à ce qu’on entre valeur par valeur… bref nous étions tous sacrément embêtés. La première solution qui nous est venue à l’esprit a été la suivante : nous avons demandé aux gestionnaires, dès qu’elles avaient un peu de temps libre, d’entrer les informations petit à petit. Et donc, quelques jours plus tard, une gestionnaire arrive et me dit qu’après avoir passé une matinée dessus, elle n’avait pu entrer que la moitié des tarif d’un onglet (il y en avait une dizaine).

J’ai donc cherché une autre solution et là, hop, la solution géniale : autohotkey. J’ai passé une matinée à faire un script autohotkey, et le résultat a été ultra simple : la souris se déplaçait toute seule, sélectionnait Excel, faisait un copier de la valeur courante, revenait sur le programme de gestion, insérait le tarif, et puis revenait sur Excel, se déplaçait et faisait un copier de la valeur courante, revenait sur le programme de gestion, etc. Bref nous avons fait ça sur un ordinateur seul qui a tourné toute la nuit et le lendemain, tout était fini !

Autrement dit ce programme nous a fait économiser plusieurs dizaines d’heures de main d’œuvre. Pratiquement un millier d’euros (oui je n’exagère pas : une personne qui passe 8 jours complets à entrer des tarifs aurait coûté à peu près cette somme).

Autohotkey est donc un programme vraiment génial. Ah oui vous savez quel en a été ma première utilisation ?

Il m’a aidé à rencontrer un monde fou ! En effet, lorsque j’étais célibataire, je me suis inscrit sur un club de rencontres, et je n’écrivais qu’un seul message, puis je lançais mon script autohotkey qui faisait un copier-coller, et qui l’envoyait à la personne suivante. En quelques heures, et sans rien faire, j’avais écrit à plusieurs centaines de personnes !
C’est ainsi que j’ai pu organiser un repas avec dix-neuf personnes, et je n’en connaissais qu’une (une amie) !

Autohotkey me sert tous les jours. Par exemple, je lance un script qui lance putty, attend le login, entre le login, le mot de passe, et lance screen. Bref, il fait ça en trois secondes alors que j’en mets une dizaine à la main. Six secondes de gagnées. « Ce n’est rien », me direz vous. Mais six secondes fois vingt fois dans la journée égal deux minutes par jour. Deux minutes sur l’année ça fait quatre heures. Ce logiciel fait économiser une demi journée complète par an à ma société. Et il ne me sert pas qu’à ça comme je l’ai dit. Il doit globalement faire économiser à moi et aux autres plusieurs jours par an à la société. C’est très loin d’être négligeable.

Aussi incroyable que cela puisse paraitre, autohotkey est un outil vraiment très très puissant : c’est un vrai couteau Suisse et dès qu’on a une grosse tâche répétitive à faire sur ordinateur ma première pensée c’est : est-ce que je pourrais faire un script autohotkey ou pas ?