Je vais commencer doucement, avec certainement le code le plus (in) utile que j’ai pu voir jusqu’à maintenant :
if (0) { /* beaucoup de code très compliqué */ }
J’ai une affection très particulière avec l’extrait suivant, que je trouve très mignon :
try { return true; } catch (exception $ exception) { /* beaucoup de code très compliqué */ }
Je poursuivrais avec un grand classique qu’il est possible de retrouver dans quasi tous les langages supportant cette structure :
switch ($ value) { case/*… */: break ; default: /*… */ break; // extrémement utile voir indispensable… }
Il arrive également que je tombe sur des choses de ce genre :
sprintf("'%s'", (string) $element);
Et dernièrement, j'ai lu ceci :
function handle ($ foo = null) {if ($foo === null) return parent::handle() else return parent::handle($foo);}
Bref, je trouve des perles, la liste est encore longue, et il serait possible d’en rire pendant très longtemps (et j’avoue que je ne m’en prive pas), sauf qu’au final ça n’apporte pas grand-chose.
En effet, à un moment ou un autre, indépendamment du langage et des outils que nous utilisons, nous faisons tous plus ou moins de la merde.
Elle colle plus ou moins à la cuvette et sent plus ou moins fort en fonction de nos compétences et de notre expérience (et ce n’est pas forcément celle du plus inexpérimenté qui est la plus nauséabonde), mais ça reste de la merde.
Et si nous sommes souvent totalement responsables du merdier que nous laissons derrière nous, parfois, ce n’est pas le cas.
Parfois, cette merde peut être le résultat de l’infection de votre commercial ou de votre supérieur par des agents pathogènes extérieurs encore plus puissants que ceux de la gastro-entérite et qui les poussent à vous imposer des délais impossibles à tenir et vous oblige donc à rogner sur la qualité en faisant les choses à l’arrache.
Parfois, le code dont vous avez la charge a des années d’existence et il est le fruit du travail de plusieurs développeurs qui ont laissé leur quota de merde dans le code.
Et vous êtes obligé de l’accepter, car vous ne voulez pas ou vous ne pouvez pas tirer la chasse.
Alors, que faire pour éviter cela ?
Je n’ai pas LA réponse à cette question, car il faudra de toute façon que la chasse soit tirée un jour ou l’autre, mais je peux par contre vous dire qu’il vaut mieux le faire le plus rapidement possible.
Car plus vous attendez pour le faire, plus la merde s’incruste dans la cuvette et plus elle sera difficile à enlever.
Le nettoyage vous prendra donc de plus en plus de temps et vous coûtera donc de plus en plus cher.
Et dans le pire des cas, à un moment, la merde submergera l’intégralité de votre code et compromettra très sérieusement son bon fonctionnement et sa maintenance.
Le plus raisonnable est donc de nettoyer la merde au plus tôt, ou, pour utiliser un vocabulaire un peu moins fleuri, de réduire la dette technique de votre code le plus rapidement possible.
Et pour cela, je vous recommande deux chose : effectuez des revues de code régulières et écrivez des tests unitaires ou fonctionnels exécutables par la machine (et souvenez-vous que les tests fonctionnels sont complémentaires des tests unitaires, et non exclusifs).
Les revues de code vous permettront en effet de détecter au plus tôt les problèmes dans votre code et donc de les corriger pour un coût minime vu qu’ils n’auront pas encore eu de conséquences.
Les tests vous permettront quant à eux de vérifier facilement que les corrections effectuées sur le code à la suite d’une revues de code n’ont pas altéré significativement son fonctionnement.
En effet, si grâce à eux vous ne pourrez peut-être pas détecter tous les problèmes, vous pourrez cependant être certain que le code corrigé se comporte toujours de la même façon dans le cadre des tests (et uniquement dans ce cadre et avoir de tels tests ne vous dispensent donc pas d’effectuer des tests manuels).
De plus, comme ils sont exécutés par la machine, ils sont réalisés exhaustivement et surtout bien plus efficacement que s’ils étaient effectués par l’Humain, ce qui permet de valider le fonctionnement du code également à moindre coût.
Alors, si vous souhaitez suivre mes conseils, je vous recommande l’'excellente conférence de Jean-Marc Fontaine concernant les revues de code, ainsi que Crew qui vous simplifiera le processus si vous utilisez Git pour gérer votre dépôt de codet.
Et en ce qui concerne la mise en œuvre de tests unitaires ou fonctionnels, je vous recommande de vous intéressez à des outils tels qu’atoum, PHPUnit ou Behat ainsi qu’à des outils d’intégration continue tels que Jenkins ou Travis.
7 réactions
1 De Julien - 01/02/2013, 15:04
On en a parlé à mon nouveau boulot de celle-ci :
if (false) { }
Le pire c'est que tout le monde laisse un jour ou l'autre son lot de merde parce que comme tu le dis si bien il y a des contextes qui nous poussent à le faire. J'ajouterais en plus des facteurs que tu as donnés :
La démotivation quand cela fait 3 mois que tu codes la même feature et que tu as l'impression que cela ne se terminera jamais.
Le développeur solitaire
2 De Damien - 01/02/2013, 15:12
Malheureusement, face au manque d'utilisateurs Coconut-Ci à fermé ses portes il y a quelques semaines. Mais TravisCi et CircleCi sont là pour de bon !
3 De magnetik - 01/02/2013, 16:26
En complément de cet article, je recommande l'excellent "Code Simplicity" chez Oreilly (http://shop.oreilly.com/product/063...).
4 De OPi - 04/02/2013, 22:24
Perso je laisse des if ( false ) { /* code utile pour du débogage */ } dans mes programmes. Je peux ainsi changer le false en une valeur vraie (j'utilise '???' que je peux ainsi repérer) si je dois déboguer.
Je trouve ça pas mal de placer systématiquement un break dans le default, cela évite de l'oublier si on change la répartition des cas en un copier-coller un peu rapide.
Pour le
function handle ($foo = null) { if ( $foo === null ) return parent::handle() else return parent::handle($foo); }
la méthode handle() dans la classe n'a pas nécessairement une valeur par défaut null pour son premier argument.
Sinon je suis bien d'accord, nettoyer au fur et à mesure. Mais cela implique de savoir où l'on met les pieds, alors que simplement passer pour faire une petite modification jugée indépendante de son environnement ne le nécessite pas.
5 De Chris - 05/02/2013, 09:16
Je suis actuellement en train de reprendre le code d'un site et je peux te dire que je rêverai de ne voir "que" des merdes comme celles tu cites !
Un bout de code commenté ou entouré d'un "if(false)" ça a au moins l'avantage d'être évident, par contre il y a des merdes beaucoup plus subtiles et beaucoup tenaces qui pousserait celui qui reprend le code à vouloir se suicider !
Pour moi le plus crade dans ce genre de situation c'est tout simplement le manque de commentaire. On peut faire des trucs crado pour diverses raisons (après une nuit blanche, par manque de temps, ...) mais si c'est commenté ça a au moins l'avantage d'être "facile" à reprendre !!!
6 De Enerian - 05/02/2013, 18:10
@OPi
Sérieusement, plutôt que de faire des if (false) { /* code de debug */}, pourquoi ne pas plutôt définir quelque part une variable $debug = false; et l'utiliser dans ta condition : if ($debug) { /*...*/}.
Je trouve ça carrément plus propre et plus explicite tout en conservant la simplicité, même si si ce n'est pas optimal. Cela a en plus le mérite de ne pas devoir désactiver / réactiver chaque code de debug manuellement ainsi que de retrouver facilement les emplacements.
7 De OPi - 05/02/2013, 23:12
@Enerian
Justement, je fais cela sur des morceaux de codes que je désactive / réactive à la main. Typiquement des affichages permettant de tracer ce qui se passe de façon localisé. En général je finis par tout effacer, mais si l'affichage n'est pas trivial je peux le laisser.
_
En PHP j'ai en tête de chacun des fichiers qui peuvent être appelé indépendamment (typiquement AJAX) un
if ( false ) {
}
Si j'ai un code qui pose problème, je change le false par '?' dans le fichier que je veux ausculter, farfouille jusqu'à trouver le problème, le corrige, puis remet un false. (Par habitude je laisse des '?' aux endroits qui doivent être changé, je peu ainsi faire une recherche globale pour voir si je n'en ai pas oublié. Et j'utilise le "truc" que '???' est une valeur true.)
_
Il m'arrive aussi d'utiliser un if ( false ) { ... } pour supprimer temporairement du code que je ne peux pas mettre en commentaire facilement. Par exemple un bout de code qui contient déjà des commentaires /* ... */ ne peut être mis en commentaire de la même façon (si on imbrique des /* ... */ on a droit à une syntax error).
_
Mais bon, peu importe ce que l'on fait, si cela n'est pas totalement transparent il faut l'expliquer en commentant.
_
P.-S. : L'affichage de ce site change mes trois points d'interrogations en un seul ! (C'est du moins ce que me donne la prévisualisation de mon message.)