10 mauvaises habitudes de programmation que nous aimons secrètement

Nous l'avons tous fait: accroché un biscuit quand maman ne regardait pas, bu un peu trop de vin pour le dîner, laisser la voiture s'asseoir sur une place de parking après l'expiration du compteur. Nous avons même contourné Deadman's Curve un peu trop vite. Et oui, nous avons tous violé un certain nombre de règles cardinales de la programmation, celles que tout le monde considère comme mauvaises. Et nous l'avons secrètement aimé.

Nous avons ignoré les règles d'une bonne programmation, tapé du code qui est totalement mauvais - et nous avons vécu. Il n'y avait aucun éclair des dieux de la programmation. Nos bureaux n'ont pas explosé. En fait, notre code a été compilé et expédié, et les clients semblaient assez heureux.

C'est parce qu'une mauvaise programmation n'est pas dans la même ligue que, par exemple, lécher une clôture électrique ou tirer la queue d'un tigre. La plupart du temps, ça marche. Les règles sont plus souvent des lignes directrices ou des suggestions stylistiques, pas des directives strictes qui doivent être respectées ou la mort du code suivra. Bien sûr, votre code pourrait être ridiculisé, peut-être même publiquement. Mais le fait de contourner les conventions ajoute un peu de frisson à subvertir, même par inadvertance, ce qui équivaut (le plus souvent) aux mœurs sociales du code agréable.

Pour rendre les choses plus complexes, il vaut parfois mieux enfreindre les règles. (Shhhh!) Le code est plus propre. Cela peut même être plus rapide et plus simple. Les règles sont généralement un peu trop larges, et un programmeur astucieux peut améliorer le code en les cassant. Ne le dites pas à votre patron, mais il est parfois logique de coder à votre façon.

Ce qui suit est une liste de neuf règles que certains peuvent considérer comme irréprochables, mais que nous sommes nombreux à rompre souvent, avec succès et plaisir.

Mauvaise habitude de programmation n ° 1: la copie 

C'est mal de le faire à l'école. Au travail, les règles ne sont pas si claires. Il y a certainement des blocs de code qui ne devraient pas être volés. S'il provient d'un code propriétaire, ne le pliez pas dans votre pile, surtout s'il est marqué d'un message de copyright. Écrivez votre propre version. C'est ce pour quoi ils vous paient.

La question la plus délicate vient du moment où le créateur original veut partager. C'est peut-être sur l'un de ces forums de programmation en ligne. C'est peut-être du code open source avec une licence (BSD, MIT) qui permet d'acquérir une fonction ou trois. Il n'y a aucune raison légale qui vous arrête. Et vous êtes payé pour résoudre les problèmes, pas pour réinventer la roue.

La plupart du temps, les avantages de la copie sont convaincants et les inconvénients peuvent être limités avec un peu de soin. Le code que vous obtenez d'une source réputée a déjà fait l'objet d'au moins une réflexion. L'auteur original a cherché une solution et a trouvé quelque chose. Les invariants de boucle et le flux de données ont été élaborés.

Les questions délicates sont de savoir s'il existe des bogues non résolus ou des hypothèses différentes sur le rôle ou les données sous-jacentes. Peut-être que votre code se mélange à des pointeurs nuls alors que le code d'origine ne les a jamais vérifiés. Si vous pouvez résoudre les problèmes, c'est comme si votre patron recevait les commentaires de deux programmeurs. C'est une programmation en binôme sans les pupitres sophistiqués.

Mauvaise habitude de programmation n ° 2: code non fonctionnel

Depuis une dizaine d'années, le paradigme fonctionnel est en hausse. Les acolytes qui construisent votre programme à partir d'appels de fonctions imbriquées aiment citer des études montrant à quel point le code est plus sûr et plus exempt de bogues que l'ancien style de variables et de boucles, le tout lié de quelque manière que ce soit qui rend le programmeur heureux. Les dévots parlent avec le zèle des vrais croyants, réprimandant les approches non fonctionnelles dans les révisions de code et les pull requests. Ils peuvent même avoir raison sur les avantages.

Mais parfois, il vous suffit de sortir un rouleau de ruban adhésif. Un code merveilleusement conçu et bien planifié prend du temps, non seulement à imaginer mais aussi à construire et plus tard à naviguer. Toutes ces couches ajoutent de la complexité et la complexité coûte cher. Les développeurs d'un beau code fonctionnel doivent planifier à l'avance et s'assurer que toutes les données sont transmises le long des voies appropriées. Parfois, il est simplement plus facile d'atteindre et de modifier une variable. Peut-être mettre un commentaire pour l'expliquer. Même l'ajout de longues excuses rampantes aux générations futures dans le commentaire est plus rapide que de restructurer l'ensemble du système pour le faire de la bonne manière.

Mauvaise habitude de programmation n ° 3: Espacement non standard

La plupart des espaces dans les logiciels n'ont pas d'effet sur les performances du programme. À l'exception de quelques langages comme Python qui utilisent l'espacement pour indiquer des blocs de code, la plupart des espaces n'ont aucun effet sur le comportement du programme. Pourtant, il y a des programmeurs obsessionnels qui les comptent et insistent sur leur importance. L'un d'eux a dit un jour à mon patron avec le ton le plus sérieux que j'écrivais «Non Standard Code» et il pouvait le voir immédiatement. Mon péché? Violation de la règle ESLint space-infix-ops en ne mettant pas d'espace des deux côtés d'un signe égal.

Parfois, il suffit de penser à quelque chose de plus profond que le placement des espaces. Peut-être que vous vous inquiétez de la surcharge de la base de données. Peut-être que vous vous inquiétez d'une manière dont un pointeur nul pourrait planter votre code. À peu près n'importe quelle partie du code est plus importante que les espaces, même si les comités de normalisation puissants et autoritaires ont rempli des pages de règles sur le placement de ces espaces ou onglets.

Ce qui est étonnant, c'est qu'il existe plusieurs bons outils qui reformateront automatiquement votre code pour adhérer à toutes les règles de linting bien définies. Les humains n'ont pas besoin de passer du temps à y penser. Si c'est si important, ils peuvent l'exécuter via l'outil pour résoudre le problème.

Mauvaise habitude de programmation n ° 4: Utilisation goto

L'interdiction d'utiliser des gotodates datant de l'époque antérieure à l'existence de nombreux outils de programmation structurée. Si les programmeurs voulaient créer une boucle ou passer à une autre routine, ils devraient taper GOTOsuivi d'un numéro de ligne. Après quelques années, les équipes de compilation laissent les programmeurs utiliser une étiquette de chaîne au lieu d'un numéro de ligne. À l'époque, cela était considéré comme une nouvelle fonctionnalité.

Certains ont appelé le résultat «code spaghetti». Il était impossible pour quiconque de lire votre code plus tard et de suivre le chemin de l'exécution. C'était un fouillis de fils, à jamais emmêlés. Edsger Dijkstra a interdit la commande avec un manuscrit intitulé drôlement «Goto Statement Considered Harmful».

Mais le branchement absolu n'est pas le problème. C'est l'enchevêtrement qui en résulte. Souvent astucieux breakou returnproposera une déclaration très claire sur ce que le code fait à cet endroit. Parfois, l'ajout gotoà une instruction case produira quelque chose de plus simple à comprendre qu'une liste plus correctement structurée de blocs if-then-else en cascade.

Il y a des contre-exemples. Le trou de sécurité «goto fail» dans la pile SSL d'Apple est l'un des meilleurs exemples. Mais si nous prenons soin d'éviter certains des problèmes épineux des déclarations de cas et des boucles, nous pouvons insérer de bons sauts absolus qui permettent au lecteur de comprendre plus facilement ce qui se passe. Nous pouvons mettre un breakou un returnqui est plus propre et plus agréable pour tout le monde - sauf peut-être les gotohaters.

Mauvaise habitude de programmation n ° 5: ne pas déclarer de types

Les gens qui aiment les langues dactylographiées ont raison. Nous écrivons mieux, plus de code sans bogue lorsque nous ajoutons des déclarations claires du type de données de chaque variable. Faire une pause pour épeler le type aide le compilateur à signaler les erreurs stupides avant que le code ne commence à s'exécuter. Cela peut être pénible, mais cela aide. C'est une approche de programmation par ceintures et bretelles qui arrête les bugs.

Les temps ont changé. La plupart des nouveaux compilateurs sont suffisamment intelligents pour déduire le type en regardant le code. Ils peuvent travailler en arrière et en avant dans le code jusqu'à ce qu'ils puissent être sûrs que la variable doit être a stringou an intou autre. Et si ces types inférés ne s'alignent pas, les compilateurs peuvent déclencher un indicateur d'erreur. Ils n'ont plus besoin de nous pour taper les variables.

Cela signifie qu'il est maintenant plus facile d'enregistrer quelques bits en supprimant certaines des déclarations les plus simples. Le code devient un peu plus propre et le lecteur est généralement capable de deviner que la variable nommée idans une boucle for est un entier.

Mauvaise habitude de programmation n ° 6: code Yo-yo

Les programmeurs aiment l'appeler "code yo-yo". Tout d'abord, les valeurs sont stockées sous forme de chaînes. Ensuite, ils sont analysés en nombres entiers. Ensuite, ils sont reconvertis en chaînes. C'est terriblement inefficace. Vous pouvez presque sentir le CPU lutter sous toute la charge supplémentaire. Les programmeurs intelligents qui écrivent du code rapide conçoivent leurs architectures pour minimiser les conversions. Leur code s'exécute plus rapidement en raison de leur planification.

Mais croyez-le ou non, parfois cela a du sens. Parfois, vous avez une bibliothèque whiz-bang qui fait un bazillion de choses intelligentes dans sa boîte noire propriétaire. Parfois, le patron écrivait un chèque à sept chiffres pour autoriser tout le génie à l'intérieur de cette boîte noire. Si la bibliothèque veut les données sous forme de chaînes, vous les donnez à la bibliothèque sous forme de chaînes même si vous les avez récemment converties en entiers.

Bien sûr, vous pouvez réécrire tout votre code pour minimiser la conversion, mais cela prendrait du temps. Parfois, il est normal que le code s'exécute une minute, une heure, un jour ou même une semaine supplémentaires, car la réécriture du code prendrait encore plus de temps. Parfois, augmenter la dette technique est moins chère que la construire en premier lieu.

Parfois, la bibliothèque n'est pas du code propriétaire, mais du code que vous avez écrit vous-même il y a longtemps. Parfois, il est plus rapide de convertir les données une fois de plus que de tout réécrire dans cette bibliothèque. Alors vous continuez et vous écrivez du code yo-yo. C'est OK - nous avons tous été là.

Mauvaise habitude de programmation n ° 7: écrire vos propres structures de données

L'une des règles standard est qu'un programmeur ne doit jamais écrire de code pour stocker des données après avoir terminé le cours sur les structures de données au cours de leur deuxième année. Quelqu'un d'autre a déjà écrit toutes les structures de données dont nous aurons besoin, et leur code a été testé et retesté au fil des ans. Il est fourni avec la langue et c'est probablement gratuit. Votre code ne peut contenir que des bogues.

Mais parfois, les bibliothèques de structures de données sont un peu lentes. Parfois, ils nous obligent à adopter une structure qui peut être standard mais qui ne correspond pas à notre code. Parfois, les bibliothèques nous poussent à reconfigurer nos données avant d'utiliser la structure. Parfois, les bibliothèques incluent des protections de ceintures et de bretelles avec des fonctionnalités telles que le verrouillage des threads, et notre code n'en a pas besoin.

Lorsque cela se produit, il est temps d'écrire nos propres structures de données. Parfois, c'est beaucoup, beaucoup plus rapide. Et parfois, cela rend notre code beaucoup plus propre car nous n'incluons pas tout le code supplémentaire pour reformater les données exactement.

Mauvaise habitude de programmation n ° 8: boucles à l'ancienne

Il y a longtemps, quelqu'un qui créait le langage C voulait encapsuler toutes les possibilités abstraites dans une construction simple. Il y avait des choses à faire au début, des choses à faire à chaque fois dans la boucle et un moyen de savoir quand tout était terminé. À l'époque, cela semblait être une syntaxe parfaitement propre pour capturer des possibilités infinies.

C'était alors. Maintenant, certains grondeurs modernes ne voient que des problèmes. Il se passe trop de choses. Toutes ces possibilités de bonté sont également capables de mal. Cela rend la lecture et le grokking encore plus difficiles. Ils aiment le paradigme plus fonctionnel où il n'y a pas de boucles, juste des fonctions appliquées à des listes, des modèles de calcul mappés à certaines données.

Il y a des moments où le mode sans boucle est plus propre, en particulier lorsqu'il n'y a qu'une seule fonction et un tableau. Mais il y a des moments où la boucle à l'ancienne est beaucoup plus simple car elle peut faire beaucoup plus. La recherche de la première correspondance, par exemple, est plus simple lorsque vous pouvez vous arrêter dès qu'elle est trouvée.

De plus, les fonctions de mappage encouragent un codage plus bâclé lorsqu'il y a plusieurs choses à faire sur les données. Imaginez que vous vouliez prendre la valeur absolue, puis la racine carrée de chaque nombre. La solution la plus rapide consiste à mapper la première fonction, puis la seconde, en boucle deux fois sur les données. 

Mauvaise habitude de programmation n ° 9: sortir des boucles au milieu

Quelque part le long de la ligne, un groupe d'élaboration de règles a déclaré que chaque boucle devrait avoir un «invariant», c'est-à-dire une déclaration logique qui est vraie tout au long de la boucle. Lorsque l'invariant n'est plus vrai, la boucle se termine. C'est une bonne façon de penser aux boucles complexes, mais cela conduit à des interdictions folles - comme nous interdire d'utiliser a returnou a breakau milieu de la boucle. Il s'agit d'un sous-ensemble de la règle interdisant les gotoinstructions.

Cette théorie est bonne, mais elle conduit généralement à un code plus complexe. Considérez ce cas simple qui analyse un tableau pour une entrée qui passe un test:

alors que je
   
    

   ...

   if (test (a [i]) alors retourne a [i];

   ...

}

Les amateurs d'invariants de boucle préféreraient que nous ajoutions une autre variable booléenne, l'appelions notFoundet l'utilisions comme ceci:

tandis que ((notFound) && (i
   
    

...

if (test (a [i])) then notFound = false;

...

}

Si ce booléen porte bien son nom, c'est un excellent morceau de code auto-documenté. Cela peut aider tout le monde à comprendre. Mais c'est aussi une complexité supplémentaire. Et cela signifie allouer une autre variable locale et obstruer un registre que le compilateur peut ou non être assez intelligent pour corriger.

Parfois, un gotoou un saut est plus propre.

Mauvaise habitude de programmation n ° 10: Redéfinition des opérateurs et des fonctions

Certains des langages les plus amusants vous permettent de faire des choses vraiment sournoises, comme redéfinir la valeur d'éléments qui semblent devoir être constants. Python, par exemple, vous permet de taper TRUE=FALSE, au moins dans la version 2.7 et avant. Cela ne crée pas une sorte d'effondrement logique et la fin de l'univers; il échange simplement le sens de TRUEet FALSE. Vous pouvez également jouer à des jeux dangereux comme celui-ci avec des préprocesseurs C et d'autres langages. D'autres langages vous permettent de redéfinir des opérateurs comme le signe plus.

C'est un peu compliqué, mais il y aura des points dans un gros bloc de code lorsqu'il sera plus rapide de redéfinir une ou plusieurs de ces soi-disant constantes. Parfois, le patron veut que le code fasse quelque chose de complètement différent. Bien sûr, vous pouvez travailler sur le code et changer chaque occurrence, ou vous pouvez redéfinir la réalité. Cela peut vous faire passer pour un génie. Au lieu de réécrire une énorme bibliothèque, vous retournez simplement un peu et cela fait le contraire.

Il est peut-être bon de tracer la ligne ici. Vous ne devriez pas essayer cela à la maison, aussi intelligent et amusant que cela puisse être. C'est trop dangereux - vraiment ... honnête.