L'archétype du programmeur est l'individu
qui va tous las matins à son bureau dans une grosse compagnie et
développe en langage de haut niveau des choses pas toujours drôles
mais qui appartiennent au domaine du possible. Dave Small, lui, a créé
sa boîte, vit de l'émulation Mac sur Atari pourtant jugée "impossible"
par des spécialistes, et code en assembleur. C'est en ce sens un
anti-conformiste. C'est pourquoi il est bien placé pour vous proposer
ce mois-ci une petite étude caustique du milieu des développeurs qui
se voulant tous exactement aussi anti-conformistes que les autres.
De prime abord, beaucoup de programmeurs semblent s'afficher comme des
non conformistes absolus. Le plus gros choc survient en général lors
de la première recontre. Imaginez un type portant une queue de cheval
lui descendant jusqu'aux fesses, maintenue par un élastique et une
généreuse couche de sébum, ainsi qu'une barbe à faire pâlir d'envie
Fidel Castro. En outre, l'individu fait de l'exercice chaque jour, et
prend une douche... euh... tous les mois? Ce qui fait que, tandis que
vous lui serrez la main, vous vous placez habilement contre le vent et
vous vous demandez où vous pourriez trouver un désinfectant au plus
vite. Car cette poignée de main évoque les léchouilles gluantes d'un
chien errant sortant de quelque poubelle.
Pour votre édification, je me livre donc ici à quelques propos
hérétiques, et m'attends d'ailleurs à recevoir des tomates la
prochaine fois que je me présenterai à un salon informatique. Sans
compter les tomates "virtuelles" lancées via les réseaux Internet et
USENET (voir mes coordonnées à la fin de l'article). Faites attention,
mon sélecteur de tir, qui est d'habitude en position "coup-par-coup de
précision", est pour cet article placé sur " rafales continues". Comme
vous le savez sans doute, l'arme se relève en tir automatique, et tout
servant de mitrailleuse vous dira qu'il faut ajuster le tir,
c'est-à-dire observer les impacts et corriger. C'est pourquoi, si
certains de mes arguments trop généraux vous semblent àcôté de la
plaque, essayez de voir quel but je vise maladroitement, quels
principes j'essaie d'exprimer, avant d'ouvrir le feu en représailles!
Le bon professeur Wirth est l'inventeur du Pascal et de Modula. C'est
lui qui a mis le monde entier sur les rails de la programmation
structurée. Le Pascal est uniquement un langage d'enseignement de la
programmation, qui était censé montrer comment la programmation
struturée marchait. ll n'a jamais été conçu pour un usage dans le
monde réel, ce qui est par contre le but de Modula (c'est Wirth
lui-même qui le dit). Franchement, si j'étais lui, je ne serais pas
sûr de vouloir passer à la postérité pour le Pascal. Mais
malheureusement, tout ce que dit Wirth est noté aussi scrupuleusement
que si c'était tiré des Tables de la Loi, tout comme le moindre mot de
Brian Kernighan ou Dennis Ritchie est pris comme référence pour le
langage C. Ce qui est aussi aburde que si on on suivait les préceptes
d'Henry Ford pour construire une Ford modèle 1992 sous prétexte qu'il
a inventé Ie Modèle T. Il y a des gens qui ne deviennent jamais adulte
: quand ils étaient petits, leurs héros étaient Musclor et Superman;
maintenant, c'est en Wirth, ou Kernighan et Ritchie, qu'ils ont la foi
absolue. Cette vénération irréfléchie est toujours malsaine. Je ne
sais plus qui a dit que le mot "croire" est le plus effrayant, car il
implique que le cerveau est déconnecté.
Les bidouilleurs utilisent la programmation structurée, ça fait partie
de leur conformisme. Eh bien, moi pas, et mes tentatives pour
l'utiliser se sont soldées par des échecs cuisants. Il me semble
qu'écrire un programme de cette manière revient à me faire
violence. La programmation structurée reflête un certain type de
personnalité, le type NT selon le profil de Myers-Briggs, que j'ai
découvert être celui de pratiquement tous les programmeurs. j'ai écrit
un article à ce sujet [NdT : voir ST-Mag n° 64]; brièvement, je rappelle
que presque tous les bidouilleurs ont une personnalité d'un type rare,
présent chez seulement une personne sur dix, et ont des raisonnements
et des réactions très différentes de ceux de la majorité. Des
psychologues l'ont également remarqué. Les NT sont fondamentalement
des architectes, et tout dans un programme informatique reflête cette
mentalité. Je ne suis pas un NT, je me situe même à l'opposé dans les
tests. C'est pourquoi je comprend l'étonnement de la majorité des gens
devant l'informatique. Les partisans de la programmation structurée
croient que tous les problèmes de programmation peuvent être scindés
en quelques constructions de base : la boucle DO-WHILE, l'instruction
CASE (qui équivaut à une série de lF-THEN-ELSE), et quelques
autres. Et ils croient aussi que c'est ce qui doit être fait dans tous
les cas. Pour un bidouilleur NT, c'est tout-à-fait évident et
intuitif. Pour les 90% du reste de la population, c'est
ahurissant. lmaginez un enfant avec une boîte Lego, séparant et
réassemblant ses pièces, et vous avez un futur NT qui fera de la
programmation structurée.
Pour s'accommoder de la complexité de certains programmes, les adeptes
de la programmation structurée recommandent de scinder un programme en
36 000 petits sous- programmes, dont chacun ne fait qu'une seule
chose. Pour moi, cela rend le tout encore moins compréhensible qu'un
seul gros programme. C'est comme écrire un roman dont chaque
paragraphe est mis dans un fichier séparé! (Ou comme faire un magazine
à partir d'articles contenus dans des fichiers différents... Pauvre
rédacteur-en chef!).
Ajoutez à cela la 17ème Loi de
l'Informatique de Small, "Les ordinateurs ne sont pas encore
parfaits". Les outils de scindage et de réassemblage des morceaux ne
le sont pas non plus.
Pendant que vous compilerez séparément vos différents fichiers avant
de les passer tous ensemble à l'éditeur de liens, vous mettrez votre
machine à rude épreuve. Et vous découvrirez, à la manière forte,
chacun des bogues de votre système d'exploitation, de votre
compilateur et de votre éditeur de liens. J'en ai vu tellement que je
ne soupire même plus de dégoût. J'apprécie vraiment lorsque ALN (le
nouvel éditeur de lien d'Atari) me donne un message d'erreur en
traitant des fichiers qui passaient sans erreur sur le vieux
LO68/RELMOD, par exemple (devinez un peu lequel
j'utilise). Franchement, si quelque chose n' allait pas, je l'aurait
découvert avant; j'ai recompilé ce code des milliards de fois. Et je
pourrais citer bien d'autres exemples.
Rien qu'à l'allumage du Mac, avant d'en arrlver au bureau, je compte
au moins huit erreurs d'écriture en zéro! Et qui a écrit ça?La seule
raison pour laquel le Mac s'en tire est qu'à l'adresse zéro se trouve,
par le plus pur des hasards, de la RAM, ce qui évite donc une erreur
de bus (sur le ST, au contraire, c'est de la ROM, c'est pourquoi il
m'a fallu arranger cela!). Mais souvent, ces bogues reviennent hanter
le programme; après tout, cette écriture en zéro était faite pour
stocker une donnée, et quelque chose d'important n'a pas été stocké à
sa place. Quand le programme le relit, les bonnes valeurs ne s'y
trouve pas, et boum! Erreur d'adresse, le plus souvent (3 bombes sur
le ST, ID=2 sur le Mac). Finalement, la méthode du ST est la
meilleure et il serait bon sur le Mac de modifier l'adresse zéro pour
que toute écriture y engendre une erreur, afin que les programmeurs
corrigent leurs codes. Apple, rendons-lui cette justice, encourage
cela.
Loi de Small n° 1 5 : les vrais programmeurs s'abonnent à tous les
magazines et se connectent à tous les réseaux qu'ils peuvent
atteindre, et découpent ou sauvent dans des fichiers les mentions de
bogues et les astuces de programmation. Vous seriez surpris de voir
combien un seul petit article peut vous aider.
J'aime tirer une leçon de mes erreurs. Je trouve que lorsque je me
tiens en retrait de ce que fait mon code dans la machine, comme par
l'intermédiaire du langage C, ce code devient beaucoup plus dur à
déboguer. Or, le débogage est un gros pourcentage du temps du
programmeur! En utilisant l'assembleur, je peux tracer, pas à pas, mes
instructions, et trouver l'erreur.
En assembleur, vous le trouverez en traçant votre code, parce que vous
voyez l' ordinateur à son niveau réel, et non à travers quelque
fiction de machine parfaite. Vous pouvez même bidouiller des
choses... disons, du code relatif au PC... que vous ne pouvez pas
écrire directement dans votre source, en entrant des octets
manuellement.
Du coup, j'ai acquis une accoutumance à l'assembleur. Quand mon
programme plante, je trotte jusqu'aux adresses $380-$3FF et je regarde
à quelle adresse précisément je me suis planté. Ou bien je lance le
débogueur en mode trace et je regarde le plantage se dérouler. Ou
mieux, j'utilise l'émulateur en circuit Zax [NdT :
les ICE (In-Circuit Emulators) sont des appareils qui reproduisent
la circuiterie d'un microprocesseur comme le 68000, et donnent accès
en temps réel aux états internes, aux registres et au moindre bit du
microprocesseur émulé.] Si votre programme plante, le Zax vous
révélera les 4096 dernières instructions exécutées par votre
machine. Une sacré loupe de Sherlock Holmes! Ce qui me permet de
corriger le bogue immédiatement. Fini la perplexité. Le problème
apparaît en général instantanément.
Si vous aimez le son du Spectre, sachez qu'il est là parce que le Zax
m'a prouvé que la circuiterie de l'Atari accomplissait quelque chose
réputé "impossible". Qui pourtant est là. Le Zax a beaucoup amélioré
le Spectre à partir de la version 3.0. (pour être honnête, les
éditeurs de compilateurs C sortent maintenant des débogueurs
symboliques qui permettent de tracer ce que fait le code C, et ces
outils ont plus d'une ressemblance avec les traces assembleurs.
Disons que comparé au débogage en assembleur et au Zax, ces outils
abordent l' aube de l'ère industrielle.)
Les zélateurs de la programmation structurée affirment que l'on doit
diviser un programme en utilisant seulement quelques structures
simples. En procédant ainsi, affirment les conformistes, vous le
rendez plus simple à maintenir.
Foutaises! Les problèmes les plus difficiles à résoudre en
programmation sont les plus simples conceptuellement. Ces problèmes ne
sont pas simplifiés par un quelconque style de programmation. (Les
autres problèmes sont sans doute des fautes de frappe ou des bugs dans
ce crétin de compilateur C. Exemple : "Est-ce le fabricant a sorti une
mise à jour du compilateur qui ne force pas les définitions SHORT à
être alignées aux mots ? Crénom, pas étonnant que ce code ait eu des
problèmes!...")
Tenez, considérez un pré carré entouré d'une clôture, dont les poteaux
sont espacés de 4 m. Le pré fait 40 x 40 m. Combien de poteau y a-t-il
sur chaque côté? Et au total? Déjà, contrairement à ce qu'on pourrait
penser hâtivement, il n'y a pas 10 poteaux par côté, mais 11. En
effet, il faut un poteau au coin pour marquer le début d'un côté, et
ensuite on en compte 10, un par mètre. En programmation, cela
correspond à une boucle qui débute à 0. Pour aller de 0 à 10 inclus,
il y a 11 itérations. Cette erreur classique de programmation est si
connue qu'elle a justement été baptisée "erreur du poteau" . Pour moi,
cela représente parfaitement le problème phiiosophique extrême de
faire correspondre au monde réel ce que dit l'ordinateur. ll y a
beaucoup d' erreurs classiques de ce genre. Et diviser le problèmes en
structures ne peut vous aider à les résoudre, car ces problèmes ont
leur origine dans votre tête, pas dans la machine!
Je voudrais mentionner une erreur classique de méthode de
programmation que j' appellerais "l'erreur du roi Salomon". Vous vous
souvenez de l'histoire biblique du roi Salomon qui proposa de couper
un bébé en deux pour résoudre une dispute entre deux femmes s'en
prétendant mère? Eh bien, découpez un programmes en morceaux, et vous
aussi découvrirez qu'il est pénible de chercher les interactions entre
les différents modules, simplement parce que vous ne pouvez pas les
voir à l'écran en même temps. Je suis d'autant plus sensibilisé à ce
problème que j'écris. Quand je rédige un article, j'aime en voir le
maximum à l' écran.
J'arrête mes hérésies pour ce mois-ci. Le mois
prochain, je jetterai un oeil à l' hérésie en C et en Basic.
Traduction et adaptation : Password
Non-conformistes?
J'ai rencontré tant de gens comme celui-là que je ne les trouve même
plus exceptionnels. Si vous vouIez vivre cette expérience exaltante,
allez au centre informatique de l'université la plus proche, et
cherchez des étudiants de troisième cycle. Mais cette impression de
non-conformisme ferait place à la stupéfaction si vous voyiez une
cinquantaine de ces bidouilleurs ensemble. Ils ont l'air de
clones. Ils sont en fait tous absolument conformes à un certain code!
ll est hilarant de voir qu'ils ressemblent en cela à ces adolescents
"non- conformistes" qui portent les mêmes jeans, les mêmes coiffures
punk, et conduisent des voitures de sport. [NdT :
on trouve aux USA des voitures de sport d'occasion à moins de 2000
doIlars, le permis est à 16 ans, iI n,y a pas de vignette, et
l'essence 4 est fois moins chère qu'en France. C,est pourquoi même un
ado désargenté peut s'offrir une telle voiture au prix d'un boulot
d'été.].
Par ailleurs, ces bidouilleurs ont en commun beaucoup d'opinions sur
la programmation et ne sauraient mettre en doute ces croyances. Osez
le faire, et, croyez-moi, vous vous ferez expulser de la clique avant
de comprendre ce qui arrive. Je le sais, j'ai émis un doute. Je ne
peux m'en empêcher, ça fait partie de mon type de
personnalité. D'ailleurs, j'ai passé jadis un test mesurant le degré
de conformisme, et mon score était presque nul. C'est pourquoi leur
attitude me donne des boutons, en particulier à raison d'une douche
par mois.
Niklaus Wirth n'est pas un dieu
Ainsi, bien que Wirth ait inventé le Pascal pour l'enseignement, ce
langage a été implémenté sur de nombreux ordinateurs. Et dans le monde
réel, des programmeurs se sont rapidement rendu compte de ses
défauts. En particulier, ce langage est restrictif. Vous aviez beau
savoir ce que vous vouliez faire, ce stupide langage ne vous le
permettait pas. (Les puristes vous diront que ce que vous vouliez
était donc mauvais. Billevesées! Vous avez payé votre machine, vous
pouvez en exiger ce que vous voulez.) Le Pascal est presque dépourvu
d'entrées\ sorties, et se limite à lire ou écrire un caractère ou une
ligne à la fois dans un fichier. Très impressionnant, hein? Ce n'est
pas moi qui irait écrire des programmes dans un langage qui vous lie
une main dans le dos.
Je pense que j'ai une profonde haine du Pascal pour deux
raisons. Primo, on a essayé de m'en gaver de force au lycée, d'où je
me suis échappé juste avant qu' il ne devienne obligatoire (et rende à
mon avis les ordinateurs incompréhensibles à la majorité des gens
auxquels la notion de structure est étrangère). Et secondo les ROM du
Macintosh, sur lesquelles j'ai passé tant de temps, sont
principalement écrites en Pascal, ce qui m'a obligé à avaler les
horreurs produites par le compilateur qui a engendré le code
assembleur stocké dans ces ROM.
Il y a aussi dans ces ROM de l'assembleur fait-main par Andy
Hertzfeld, un magicien, et il est très instructif de comparer ce code
propre et rapide avec l'abominable saleté pondue par le Pascal (toutes
ces instructions LlNK inutiles, par exemple). Le code machine engendré
par cet abruti de compilateur est horriblement inefficace. Moi, quand
j'écris un programme, j'aime pouvoir être fier de sa rapidité et en
tirer quelque gloire.
C'est peut-être pour cela que les programmeurs chez Apple ne mettent
plus leurs nom dans leurs programmes. Peut-être est-ce ausi pour cela
que beaucoup d'entre eux viennent juste d'être licenciés? Non, je suis
sûr qu'ils écrivaient du beau code. C'est plutôt dans la haute
hiérarchie que cela n'allait pas.
Avis aux puristes : je suis conscient des différences entre le code
machine binaire et l'assembleur qui est sa forme symbolique. Pour
cette article, j'ignore cette différence. Rasseyez- vous, ça continue.
La programmation structurée est une
antiquité
Il faut utiliser des
sous-programmes
Adoptez par exemple le style de programmation de chez AT&T, où chaque
sous-programme doit se trouver dans un fichier séparé, et vous vous
retrouvez aux prises avec un bourbier innommable. Vous avez alors
besoin du programme MAKE auquel vous devez préciser, dans un fichier
de commande, dans quel ordre s'emboîtent ces morceaux pour construire
votre programme. Dans ce genre de situation, il faut tout arrêter et
vérifier que la belle idée colle toujours à la réalité (ce que
j'appelle une vérification de réalité). Donc, le programme a été
scindé à grand-peine en 500 modules, avec force variables importées et
exportées, et, toujours à grand-peine, un fichier de commande pour
MAKE a été écrit pour réassembler tous ces morceaux. Question : qu'y
a-t-il dlanormal dans cette situation? Formulez votre réponse en
utilisant les mots " heures" et "jours".
Contre-exemple : comparez avec Dave le simplet. Moi, j'écris le
programme en un seul morceau, je le compile, et c'est fini. Je m'
épargne l'effort considérable de le scinder et le non moins
considérable travail de réassemblage.
Les ordinateur ne sont pas parfaits
Ne faites pas l'erreur de croire que les ordinateurs sont parfaits. Un
tantinet de saine paranoïa s'impose. Si vous comtemplez l'historique
de n'importe quel ordinateur vous verrez immanquablement le même
scénario : l'ordinateur sort, et les corrections de bogues
suivent. Prenons Atari. Citons en vrac Ie bogue des 40 dossiers, celui
du caractère "souIigné" dans le sélecteur d'objet, les 97 bogues
d'AS68 dont j'ai la liste, le bogue exaspérant de RELMOD qui lui fait
remplir tout le disque si le fichier en entrée est incorrect, les
choix discutables de conception du matériel (amener le signal RESET
jusqu'aux lecteurs de disquette sans amplifioation? Non, mais je
rêve!), et j'en passe.
Alors, savez-vous ce que je fais? Je m'en tiens à un seul assembleur
et éditeur de liens, et quand je leur trouve un bogue, je l'ajoute au
dossier BOGUES de ma machine. Je ne change d' outil que dans les cas
désespérés, parce que je sais pouvoir m'affranchir des bogues d'un
outil donné. (Ne pas mettre deux labels à la suite sans instruction
dans AS68, par exemple. Ne pas utiliser la compilation conditionnelle
avec AS68.) C'est en tremblant de frousse que je suis passé à
l'assembleur HiSoft, je reconnais que, mis à part quelques anomalies
(comment diable le fait-on produire du code relatif au PC?), il marche
bien.
Encore une petite vérification de réalité. Figurez-vous que mon
émulateur Mac, le Spectre GCR, est obligé de corriger des défaillances
de programmes Mac lorsqu' ils essaient d'écrire à l'adresse zéro à
cause d'erreurs de logique ou de programmation. Pour mémoire, je
dirais seulement que la moitié des programmes Mac, y compris la
plupart de ceux, très connus, qui ont fait le succès de la machine,
sont truffés d'erreurs d'écriture à l'adresse zéro. Ce sont des
programmes écrits principalement en C et en Pascal, tournant sous un
système d' exploitation écrit en Pascal, et écrits par des gens qui
sont considérés comme étant parmi les meilleurs de la profession. Eh
bien, même eux finissent par ne plus pouvoir se souvenir de leurs
pointeurs et de la validité de ceux-ci, tant sont subtiles certaines
opérations de déplacement de mémoire.
Si vous acceptez de signer un accord de non-divulgation, je veux bien
vous faire faire un petit tour à vous soulever le coeur à travers la
galerie des programmes Mac qui ne tournent que par accident. Je ne
veux pas les nommer ici parce que j'ai horreur des procès.
En assembleur, on voit ce que fait la
machine
En C? Laissez tomber. ll faut revenir au débogage de l'âge des
cavernes en mettant dans le code des lignes affichant "J'ai exécuté la
line 10!", "J'ai exécuté la line 20!" et autres atrocités. Je ne
voudrais pas passer ma carrière à lire et relire mon code C à la
recherche d'un bug que je ne peux pas tracer directement. Vous savez,
ces fameux problèmes à se gratter la tête de perplexité. Et le pire,
c'est qu'il s'agit parfois d'un problème dans le compilateur, ses
bibliothèques ou le système d'exploitation, pas d'une erreur de votre
part, et vous ne le trouverez jamais. Point final.
Plus facile à maintenir
Ah oui, et le nombre total de poteau? Méditez cet exemple parfait de
bonne réponse bâtie sur un mauvais raisonnement, comme ces programmes
qui marchent par hasard : "40 poteaux au total, bien sûr, puisqu'il y
en a 10 par côté."
L'erreur du roi Salomon
Quand je le peux, j'utilise un écran Moniterm, et j'offre une forte
récompense à quiconque modifiera un traitement de texte pour qu'il
puisse utiliser les deux "pages" d'un Moniterm [NdT
: Dave Small ignorait alors que des traitements de texte
européens ont cette possibilité]. En voir beaucoup aide à rendre
l'article cohérent. Non? Alors allez écrire sur un écran de huit
lignes et relisez la bouillie informe qui en émergera. Quand je veux
maintenir quelque chose, je charge le code source entier dans un
éditeur. J'ai parsemé le code source de commentaires contenant des
mots-clés qui me servent de repères. Si je veux, disons, modifier le
code qui gère la souris dans Spectre, je fais une recherche du
mot-clé "trouve-souris", lequel se trouve dans un commentaire en tête
du segment de code en question. Je peux alors regarder ce bout de
code et ses interactions avec le reste sans avoir à ouvrir des
fenêtres, charger d'autres fichiers, etc. Je ne saurais vous dire
combien d'erreurs d' interaction j'aurais manqué si tout n'avait pas
été lisible en un seul endroit.
A Suivre
A la
prochaine fois!