|
L'art de bien programmer, ce n'est malheureusement pas quelque chose
qui s'apprend dans les livres ou en lisant une chronique en quelques
points bien choisis; c'est quelque chose qui s'apprend par la pratique. Au
jour le jour, en ne sautant pas d'étapes.
Plusieurs facteurs joueront. Un de ces facteurs sera votre attitude.
- D'abord, il faut être zen: Quand vous codez, vous codez. Vous ne
regardez pas la télé, vous ne chattez pas. Vous codez.
Sans aller jusqu'à commencer chaque séance de programmation par une
méditation zazen de quinze minutes, chasser toutes les distractions
et centrer toute son attention sur la tâche à accomplir est essentiel.
Il est déjà difficile de produire des algorithmes et des programmes qui
fonctionnent bien en tout temps, nul besoin d'introduire des erreurs
d'inattention qui s'avéreront difficile à trouver plus tard. Éliminez
les sources de distraction de façon active: utilisez même des bouchons
pour les oreilles s'il le faut. N'hésitez pas à dire à votre cocubiculaire
de se la fermer.
- Ensuite, il faut être zen: Ce qui mérite d'être fait, mérite d'être
bien fait. Ne faites pas comme un ami dont je tairai le nom qui un jour
me donna un bout de code nul à chier en s'attendant que je me dise tout
naturellement « mais ouah, quel génie, je suis sûr qu'il code bien mieux
d'habitude. » Eh bien non. Vous écrivez du code, vous le faites
bien, ou pas du tout. Donnez toujours le meilleur de vous-même. Un code
c'est comme une calligraphie; exact, précis, élégant.
La notion d'élégance appliquée au code est souvent étrangère aux
programmeurs. Il ne suffit pas que le code fonctionne (c'est déjà ça,
me direz vous) il faut aussi que le code soit beau, c'est-à-dire
qu'il soit intelligible par un tiers qui n'y a jamais touché. Certes,
cela peut être difficile de comprendre un algorithme sophistiqué, mais
il devrait être possible de se retrouver dans un programme en quelques
minutes, comprendre quels modules sont responsables de quelles fonctions
et quels types/classes/structures de données sont les plus importants.
La notion d'élégance est, comme en art, très difficile à définir. Il y
a cependant des points élémentaires sur lesquels il faut insister, comme,
par exemple, la structure et un choix judicieux des noms des
différents éléments (variables, constantes, fonctions, fichiers) de votre
programme. Nommer une fonction RegressionLineaire est beaucoup plus
utile au programmeur que si vous la nommez, disons, RgssLnr, même si
ce nom cryptique est tout à fait limpide dans votre petit univers personnel.
Évitez les vieux standards cuculs de programmation qui contraignent les noms
de fichier ou de fonctions à 6 ou 8 caractères de long. Un fichier nommé
RegressionLineaire.h est tout à fait acceptable. Fortran est mort
depuis longtemps (quoi que puissent en dire quelques irréductibles fortreux.)
- En plus, il faut rester zen: vous devez réparer le code de quelqu'un
d'autre ? Ne vous perdez pas en invectives inutiles. Réparez le code ou
débugguez à la dynamite (i.e., explosez le code et recommencez.)
Utilisez toujours la force nécessaire, jamais moins, jamais plus.
Qui n'a pas eu à modifier un programme préexistant et dont le programmeur
original a été congédié voilà trois ans ? Évidemment, c'est arrivé à tout
le monde. Parfois, vous êtes chanceux, et ce programmeur était bon,
mais souvent, hélas! le programmeur en question a été congédié pour une
bonne raison. Le code est très mauvais, désorganisé, rempli de variables
globales (naturellement nommées a, aa, et aaa, de types
différents et déclarées dans 14 fichiers) et vous découvrez que le
code qui devrait être contenu dans deux ou trois fonctions est en fait disséminé
un peu partout dans le code et dépend d'interactions bizarres. À un point même
où vous vous demandez si ça n'a pas été programmé par un singe.
Vous avez donc essentiellement deux choix: modifier le code existant en
faisant le moins de modifications possible (et réduire l'entropie
du code ce faisant) ou tout simplement l'exploser et recommencer.
Exploser le code et recommencer est sûrement l'option la plus tentante,
celle qui flattera le plus votre ego: quelle satisfaction que de remplacer
du code foireux par son propre code adoré à soi! Résistez à la tentation
s'il est clair que la modification à apporter est mineure et qu'il serait
facile et rapide de réparer le bug. Considérez la quantité de code
à refaire et l'effort nécessaire.
D'un autre côté, certains programmes sont irrécupérables.
L'attitude ne sera pas le seul facteur de votre
réussite. C'en sera une bonne part, certes, mais ne saurait être à elle
seule suffisante. Il vous faut aussi de la méthode. Comme il faut être
zen, il faut être méthodique.
-
Soyez méthodique. Établissez vous un
standard de programmation qui
couvre jusqu'à l'indentation si nécessaire. Avoir un standard pour
nommer les types, les variables (selon le scope au besoin), les
constantes, les fonctions. Peu importe que vous soyez un suppôt de GNU
et du tab-à-4, ou de Microsoft et de la notation
hongroise, suivez le standard que vous vous êtes établi. Soyez
constant. L'exception tue.
Les standards de programmation sont nombreux et ont tendance à être
dogmatiques. Vous pouvez adhérer à un ou l'autre des standards
« officiels », que ce soit celui de GNU ou un autre; mais vous
avez aussi toute liberté de créer le vôtre. Un standard de programmation
n'est pas une religion, vous avez le droit de le changer lorsque vos
besoins évoluent. Gardez à l'esprit que même les grands bonzes de GNU
ne détiennent pas la vérité absolue, et qu'il leur arrive aussi de dire
des niaiseries — quoique moins souvent que d'autres.
La règle, s'il en est une, c'est que votre standard de programmation
doit rendre votre code plus lisible. Il doit faire en sorte que si vous
regardez une fonction, vous pouvez savoir si elle globale ou une méthode
( member function. ) Si vous regardez une variable,
pouvez-vous dire immédiatement si c'est une variable locale, un membre
de la classe courante, un paramètre, une constante ? Une macro ?
- Soyez méthodique. Dépendemment de vos aptitudes à l'organisation,
prenez plus ou moins de temps à l'organisation de votre code. Posez vous
les questions
- Qu'est-ce que ça doit faire ? Faire un programme qui ne répond pas
à un besoin est parfaitement inutile. Vous perdrez votre temps.
Répondez bien à cette question et déjà l'utilité de votre programme
sera accrue.
Cette question est habituellement répondue par le client, par une
analyse plus ou moins poussée des besoins. Dans le cadre d'un projet
personnel, ne vous vautrez pas dans la programmation dès que vous avez
le germe d'un début d'idée. Sans aller dans l'artillerie lourde (comme
UML, Rose, et ces outils de conception) accordez vous un temps de réflexion
sur votre projet. Ça peut être des minutes, ou des jours; mais donnez
vous le temps de méditer votre projet et d'en voir plusieurs facettes.
Cela vous permettra peut-être d'observer certains aspects qui ne vous
étaient pas apparu de prime abord. Qui sait, peut-être même aurez vous
des idées qui simplifieront grandement la conception ?
Certaines personnes trouvent une certaine sécurité dans les méthodes
lourdes comme UML et Rational Rose. Pour ma part, je pense qu'une bonne
part de planification et de documentation devrait être réalisée avant
d'écrire le code pour de très gros projets qui vont demander beaucoup
de programmeurs. Pour de petits projets, il existe des méthodes de
développement « agiles » comme la programmation eXtrême (qui
n'a d'ailleurs rien d'extrême) et d'autres paradigmes du même genre.
Vous pouvez glaner çà et là des idées et développer votre méthode
maison. Mais faites attention! Votre méthode devra faire en sorte que
vos points faibles en développement seront moins faibles.
- Comment ça devrait le faire ? Une fois que vous savez qu'est-ce
qu'un programme doit faire, demandez vous comment il doit le faire.
Ai-je besoin d'un GUI ? Préférerai-je une version command line ?
Doit-il pouvoir s'interfacer avec d'autres applications ?
S'exécutera-t-il dans un environnement embarqué ? Dois-je sauvegarder
les préférences dans la mémoire flash, le registry ou dans
/etc/truc/machin.conf ? Les choix peuvent être dictés par vos goûts
personnels, mais devront satisfaire le besoin et devront être appropriés
à l'environnement de développement choisi.
- Comment séparer les fonctionnalités ? En modules, processus, etc.
Peut-être votre programme est-il court et quelques .h/hpp et .c/cpp
suffiront ? Peut-être est-il composé en fait d'une série de programmes
indépendants ?
- Quelle est la façon la plus efficace (temps, mémoire) pour
accomplir telle ou telle tâche ? Le choix des structures de données et
des algorithmes est crucial. Cela fait toute la différence entre un
logiciel lourd et lent ou un logiciel léger et rapide. Là encore, il
faut être zen: ça prend ce que ça prend. Ne lésinez pas sur les
algorithmes. Fouillez le web pour des structures de données et des
algorithmes appropriés... Il y a de grandes chances que quelqu'un
d'autre, quelque part, ait tenté de résoudre ce même problème avant
vous.
En effet, le web est une source inépuisable de documentation. Plusieurs sites
se consacrent entièrement aux algorithmes et aux structures de données. Plusieurs
conférences mettent aussi à la disposition de tous des versions électroniques
de leur comptes-rendus, vous permettant de vous tenir à jour même dans les sujets
les plus pointus.
Si vous n'êtes pas très fort en algorithmique, ni en structures de données, il
vous est quand même possible de développer votre application et de revenir plus
tard sur certains modules pour remplacer un algorithme simpliste (on dit aussi
« naïf ») par un algorithme computationnellement efficace. En effet, si
vous avez bien encapsulé vos fonctionnalités, il vous sera facile de changer
l'implémentation d'un module sans en changer l'interface.
Il ne faut vraiment pas hésiter à refaire ses algorithmes et/ou ses structures
de données. Si vous avez besoin d'un algorithme de tri, vous pouvez toujours
commencer par un tri à bulles, ou encore par un tri qui demande beaucoup de mémoire,
quitte à revenir sur cette implémentation et remplacer votre tri à bulles par un
Quicksort. Pour le reste du programme, la méthode qui est appelée demeure
Trier( ) et rien n'est changé.
On ne saurait trop insister sur la nécessité d'utiliser des algorithmes efficaces.
Si vous avez implémenté un algorithme O(n2)
mais connaissez un algorithme (qui calcule la même chose) en O(n lg n), allez-y,
refaites votre implémentation. Le gain de performance sera spectaculaire.
Ne reculez pas devant la difficulté que présente un algorithme
« compliqué. » D'abord, parce qu'il est très possible que vous puissiez
trouver une implémentation disponible sur le web qu'il vous sera facile de
modifier pour vos propres besoins. Il est aussi possible que cet algorithme aura
été implémenté par quelqu'un qui y a mi beaucoup de temps et d'effort et que, par
conséquent, ce code soit très performant par rapport à l'implémentation naïve que
vous en auriez fait. Ensuite, parce qu'apprendre de nouveaux algorithmes, sans cesse
plus difficiles que les précédents, fera de vous un meilleur programmeur.
- Quels outils utiliserez vous ? Est-ce que votre logiciel devra
fonctionner sur une plate-forme BSD ? Si oui, ne cherchez pas à faire
du Windows sous BSD. Vous êtes un pingouiniste convaincu et pratiquant?
Utilisez quand même Windows si c'est ça que ça prend. Choisir l'outil
(plate-forme, langage, environnement) pour réaliser un projet, c'est
comme se demander quel outil utiliser pour enfoncer un clou. Un clou,
ça prend un marteau, pas un tournevis, même si vous aimez la licence
Open Source du tournevis. Soyez pragmatique.
Il semble de plus en plus difficile d'ignorer les guerres de religion du genre
BSD contre Linux contre Windows contre Apple. Sur les forums de discussion, les
pinguinistes ultra se comportent souvent comme de petits fascistes d'opérette,
n'hésitant pas à dénigrer tout autre système d'exploitation. Vous pouvez les
ignorer, la plupart ne connaissent rien à Linux (ni à l'informatique) de toute
façon et se font aller le pingouin pour la frime, histoire de faire différent
des autres.
Adoptez une position neutre face aux systèmes d'exploitation. Demandez vous quels
sont les outils qui serviront mieux votre projet. Si vous trouvez les meilleurs
outils sur Windows, ne cherchez pas systématiquement à trouver des outils de
remplacement sur BSD: peut-être vous retrouvez vous avec un produit inférieur parce
que telle ou telle technologie n'est pas encore au point sur BSD, alors qu'elle est
à pleine maturité sur Windows. De même, n'hésitez pas à vous lancer sur Linux si
vous pensez que, justement, les outils dont vous avez besoin sont mieux implémentés
sur Linux que sur Windows. Si votre marché cible se retrouve à 90% chez les
utilisateurs d'Apple — une application de montage vidéo, par
exemple — oubliez Windows, et foncez sur OS X.
Un argument spécieux utilisé pour justifier le choix du système d'exploitation,
qui revient souvent, est la supériorité du logiciel libre sur le logiciel
propriétaire.
Premièrement, ces deux options ne sont pas mutuellement exclusives. Un logiciel
peut être propriétaire et Open Source. Vous pouvez très bien garder tous
vos droits sur un logiciel tout en laissant le source accessible à tous. Il y a
tout un spectre de possibilités entre le logiciel propriétaire et secret et le code
tout à fait libre.
Deuxièmement, il faut se méfier du code « libre .» En effet, ce ne sont
pas toutes les licences Open Source qui vous conviendront. La GPL, par exemple, vous
obligera à mettre en GPL les portions de votre code qui utilisent du code déjà GPL.
Cela pourrait vous être fatal dans la mesure où la pertinence de votre application
repose sur des algorithmes dont vous seul avez le secret et qui vous donnent
un avantage décisif sur la concurrence.
Pour en savoir plus:
www.OpenSource.org.
Enfin, troisièmement, il n'est pas clair que le logiciel libre soit
systématiquement supérieur au logiciel propriétaire. Dans certains cas, le fait que
le code source ait été mis à la disponibilité de tous a permis d'expurger les bugs
du logiciel et d'ainsi de créer un logiciel d'une très grande fiabilité, tout en
s'assurant que la grande majorité des failles ait été découverte. Le logiciel
secret (je ne dis pas propriétaire car un code peut être, rappelons nous,
propriétaire et Open Source) n'a pas le bénéfice d'être aussi bien scruté et peut
présenter des failles importantes qui n'ont pas été détectées par les concepteurs.
D'un autre côté le code libre est souvent maintenu par des volontaires qui y
consacrent plus ou moins de temps, et les mises à jour peuvent être très espacées
et, dépendemment de la compétence des volontaires, plus ou moins bonnes. Un logiciel
propriétaire est maintenu activement par des gens qui sont payés pour ne faire que
ça dans la vie. L'échelle du travail peut aussi changer dramatiquement entre un
logiciel libre et un logiciel commercial: Open Office, ce n'est pas Microsoft
Office.
- Soyez méthodique. Testez votre code le plus exhaustivement possible,
morceau par morceau. Rien de plus bête que de chercher un bug dans un
nouveau bout de code alors qu'en fait il est causé par le
dysfonctionnement d'une fonction ancienne mal testée mais que l'on
supposait fiable. Ne supposez rien des intentions des utilisateurs de
votre code. Vous avez testé avec "eh", il y aura inévitablement un petit malin
qui va essayer avec le texte intégral de Guerre et paix. Munissez vous des
outils pour debugger votre code.
- Implémentez des tests qui vérifieront l'exactitude de vos résultats.
Utilisez des algorithmes alternatifs, même s'ils sont plus lents. Vous
pourrez toujours les éliminer dans la version finale. Ces tests
peuvent aller de quelques petites comparaisons à des algorithmes
complexes; ne lésinez pas, il est préférable de passer du temps à
s'assurer que le code fonctionne correctement au moment du
développement que de passer le reste de ses jours à maintenir un
logiciel qui devient de plus en plus crasseux.
-
Identifiez les vulnérabilités de votre logiciel. Telle ou telle fonction
présente-t-elle un risque d'exploitation ? Gérez vous correctement
les tampons d'une grandeur inattendue, soit trop grands ou trop petits ?
Qu'est-ce qui se passe lorsque vous passez 0 alors qu'un nombre positif est
attendu ? Qu'est-ce qui se passe si vous épuisez toute la mémoire
disponible ? Est-ce que votre programme explose, ou est-ce que les
erreurs sont bien gérées, quitte à abandonner les calculs de façon inopinée
mais sans perdre de données ?
Ce type de vulnérabilité est souvent exploité par les petits plaisantins
pour causer toutes sortes de problèmes dans les ordinateurs accessibles à
partir de l'Internet. Les troubles vont de l'interruption de services
jusqu'à la prise de possession de l'ordinateur par les pirates.
En effet, dans les attaques de type buffer overrun, un pirate envoie
un message plus long que ce que le logiciel peut gérer. Si le tampon qui
contient le message se retrouve sur la pile, cela offre au pirate l'opportunité
de choisir jusqu'où il veut beurrer la pile et remplacer les adresses de retour
par une adresse de son choix, possiblement pointant ... dans le
tampon où le petit malin aurait pris soin d'insérer son code malicieux.
Résultat: parce que vous avez oublié de gérer explicitement la taille maximale
d'une donnée, votre système est tombé dans les mains de l'ennemi. Bravo!
- Faites-vous des outils pour visualiser vos données. Si vos données
sont complexes, il pourrait être rentable de se programmer des outils
de visualisation de données, soit d'utiliser un debugger (comme DDD sur Linux)
qui soit capable de représenter un tableau sous forme graphique.
Peut-être n'est-ce pas valide pour toutes les formes de données, mais
si le contenu d'un tableau représente une courbe « lisse », ça se voit bien
sur un graphique, alors qu'inspecter un gros tas de nombres du genre de
1.231231e-21 n'est pas aussi facile. N'hésitez pas à utiliser un outil
mathématique comme maple, Matlab ou Mathematica.
- Faites-vous des suites de tests. Choisissez des données pour
lesquelles vous connaissez les résultats. Vérifiez que vos changements
n'altèrent pas ces résultats. Cela permet de trouver les effets
secondaires qui se manifestent ailleurs qu'immédiatement dans vos
modifications. Construire un corpus représentatif peut être un défi
mais ce n'est pas rare qu'il puisse être réutilisé pour d'autres
projets. De plus, dans certains domaines, il existe déjà des corpus
standards contre lesquels les logiciels sont
comparés.
|
|