zen by numbers 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.

Comme la tortue, faites votre chemin lentement, mais sûrement








( vous voulez commenter?: steven.pigeon@videotron.ca )