
Depuis le début de 2018, je suis le leader / chef / développeur principal de l'équipe - appelez-le comme vous voulez, mais l'essentiel est que je suis entièrement responsable de l'un des modules et de tous les développeurs qui y travaillent. Ce poste me donne un nouveau regard sur le processus de développement, car je suis impliqué dans plus de projets et participe plus activement à la prise de décision. Récemment, grâce à ces deux circonstances, j'ai soudainement réalisé à quel point une mesure de la compréhension affecte le code et l'application.
La pensée que je veux exprimer est que la qualité du code (et du produit final) est étroitement liée à la mesure dans laquelle les personnes qui conçoivent et écrivent le code sont conscientes de ce qu'elles font.
Vous pensez peut-être maintenant: «Merci, cap. Bien sûr, ce serait bien de comprendre ce que vous écrivez. Sinon, avec le même succès, vous pouvez engager un groupe de singes pour marteler des touches arbitraires et vous calmer. " Et vous avez absolument raison. En conséquence, je tiens pour acquis: vous vous rendez compte qu'il est nécessaire d'avoir une idée générale de ce que vous faites. Cela peut être appelé un niveau de compréhension nul, et nous ne l’analyserons pas en détail. Nous analyserons en détail ce qui doit être compris exactement et comment cela affecte les décisions que vous prenez chaque jour. Si je savais ces choses à l'avance, cela me ferait économiser une tonne de temps perdu et de code douteux.
Bien que vous ne verrez pas une seule ligne de code ci-dessous, je pense toujours que tout ce qui est dit ici est d'une grande importance pour écrire du code expressif de haute qualité.
Premier niveau de compréhension: pourquoi ça ne marche pas?
Les développeurs arrivent généralement à ce niveau au tout début de leur carrière, parfois même sans l'aide des autres - du moins selon mes observations. Imaginez que vous ayez un rapport de bogue: certaines fonctions de l'application ne fonctionnent pas, vous devez le corriger. Comment allez-vous agir?
Le schéma standard ressemble à ceci:
- Trouvez le morceau de code qui cause le problème (comment cela se fait est un sujet distinct, je le divulgue dans mon livre sur le code obsolète)
- Apportez des modifications à cet extrait
- Assurez-vous que le bug est corrigé et qu'il n'y a pas d'erreurs régressives
Concentrons-nous maintenant sur le deuxième point - apporter des modifications au code. Il existe deux approches à ce processus. Tout d'abord: pour explorer ce qui se passe exactement dans le code actuel, identifier l'erreur et la corriger. Deuxièmement: passez au toucher - ajoutez, disons, +1 à une instruction ou une boucle conditionnelle, voyez si cette fonction a fonctionné dans le bon scénario, puis essayez autre chose et ainsi de suite à l'infini.
La première approche est correcte. Comme l'explique Steve McConnell dans son livre Code Complete (en passant, je le recommande vivement), chaque fois que nous changeons quelque chose dans le code, nous devrions être en mesure de prédire en toute confiance comment cela affectera l'application. Je cite de mémoire, mais si le correctif ne fonctionne pas comme prévu, il devrait être très prudent pour vous, vous devriez remettre en question l'ensemble de votre plan d'action.
Pour résumer ce qui précède, afin d'effectuer une correction de bogue solide qui ne dégrade pas la qualité du code, vous devez comprendre toute la structure du code et la source d'un problème spécifique.
Deuxième niveau de compréhension: pourquoi ça marche?
Ce niveau est compris beaucoup moins intuitivement que le précédent. Étant un développeur novice, je l'ai appris grâce à mon patron, et plus tard j'ai expliqué à plusieurs reprises l'essence de la question aux débutants.
Cette fois, imaginons que vous ayez reçu deux rapports de bogue à la fois: le premier concerne le scénario A, le second concerne le scénario B. Quelque chose ne va pas dans les deux scénarios. En conséquence, vous êtes pris en premier pour le premier bogue. Guidé par les principes que nous avons introduits pour le premier niveau de compréhension, vous plongez dans le code pertinent au problème, découvrez pourquoi il oblige l'application à se comporter exactement comme dans le scénario A et effectuez des ajustements raisonnables qui donnent exactement le résultat que vous attendus. Tout va bien.
Ensuite, vous passez au scénario B. Vous répétez le script pour tenter de provoquer une erreur, mais - une surprise! - maintenant tout fonctionne comme il se doit. Pour confirmer votre supposition, vous annulez les modifications apportées lors du traitement de l'erreur A et le bug B revient à nouveau. Votre correction de bogue a résolu les deux problèmes. Heureusement!
Vous ne comptiez pas du tout dessus. Vous avez trouvé un moyen de corriger l'erreur dans le scénario A et vous ne savez pas pourquoi cela a fonctionné pour le scénario B. À ce stade, il y a une grande tentation de décider que les deux tâches ont été accomplies avec succès. C'est tout à fait logique: il s'agissait d'éliminer les erreurs, n'est-ce pas? Mais le travail n'est pas encore terminé: vous devez encore comprendre pourquoi vos actions ont corrigé l'erreur dans le scénario B. Pourquoi? Ensuite, qu'il travaille peut-être sur les mauvais principes, et alors vous devrez chercher une autre façon. Voici quelques exemples de tels cas:
- étant donné que la solution n'a pas pu être ciblée spécifiquement pour l'erreur B, compte tenu de tous les facteurs, il se peut que vous ayez rompu la fonction C. sans le savoir
- il est possible que quelque part le troisième bug lié à la même fonction se cache également, et votre correction de bug fait fonctionner correctement le système dans le script B. Maintenant, tout semble bien, mais un beau jour, ce troisième bug sera remarqué et corrigé. Ensuite, dans le scénario B, une erreur se produit à nouveau, et bien, si ce n'est que là.
Tout cela introduit de l'aléatoire dans le code et un jour il vous tombera dessus - très probablement, au moment le plus inopportun. Vous devrez rassembler votre volonté en un poing pour vous forcer à passer du temps à comprendre pourquoi tout semble fonctionner, mais ça vaut le coup.
Troisième niveau de compréhension: pourquoi ça marche?
Mes connaissances récentes sont précisément liées à ce niveau, et cela m'aurait probablement procuré le plus d'avantages si j'étais venu à cette idée plus tôt.
Pour le rendre plus clair, regardons un exemple: votre module doit être rendu compatible avec la fonction X. Vous n'êtes pas particulièrement familier avec la fonction X, mais on vous a dit que vous devez utiliser le cadre F. pour sa compatibilité. Les autres modules qui s'intègrent avec X fonctionnent exactement avec lui.
Depuis le premier jour de votre vie, votre code n'est plus du tout entré en contact avec le framework F, il ne sera donc pas si facile de le mettre en œuvre. Cela aura de graves conséquences pour certains composants du module. Néanmoins, vous vous lancez dans le développement: écrivez du code pendant des semaines, testez, déployez des versions pilotes, obtenez des commentaires, corrigez des erreurs de régression, trouvez des complications imprévues, ne rentrez pas dans le délai initialement convenu, écrivez un peu plus de code, testez, obtenez le contraire connexion, corriger les erreurs de régression - tout cela pour mettre en œuvre le cadre F.
Et à un moment donné, vous réalisez soudain - ou peut-être entendre quelqu'un - que peut-être le cadre F ne vous donnera pas du tout de compatibilité avec la fonction X. Peut-être que tout ce temps et ces efforts n'ont pas été appliqués du tout à cela.
Quelque chose de similaire s'est produit une fois au cours du travail sur un projet dont j'étais responsable. Pourquoi est-ce arrivé? Parce que j'ai mal compris ce qu'est l'essence de la fonction X et comment elle se rapporte au cadre F. Que dois-je faire? Demandez à la personne qui définit la tâche de développement d'expliquer clairement comment le plan d'action prévu conduit au résultat souhaité, au lieu de simplement répéter ce qui a été fait pour d'autres modules, ou de prendre le mot qu'il est nécessaire pour que la fonction X fonctionne.
L'expérience de ce projet m'a appris à refuser de démarrer le processus de développement jusqu'à ce que nous comprenions clairement pourquoi nous sommes invités à effectuer certaines actions. Refuser le texte brut. Lorsque vous recevez une tâche, la première impulsion est de la reprendre immédiatement afin de ne pas perdre de temps en vain. Mais la politique de «gel du projet jusqu'à ce que nous entrions dans tous les détails» peut réduire le temps perdu par des ordres de grandeur.
Même s'ils essaient de vous mettre la pression, de vous forcer à commencer à travailler, même si vous ne comprenez pas comment cela se justifie, résistez. Tout d'abord, déterminez le but pour lequel vous êtes affecté à une telle tâche et décidez si c'est le bon chemin vers l'objectif. J'ai dû apprendre tout cela par une expérience amère - j'espère que pour ceux qui liront ceci, mon exemple rendra la vie plus facile.
Quatrième niveau de compréhension: ???
Il y a toujours quelque chose à apprendre en programmation, et je suppose que je n'ai touché qu'aux couches supérieures du sujet de la compréhension. Quels autres niveaux de compréhension avez-vous découvert au cours des années de travail avec le code? Quelles décisions ont été prises qui ont eu un bon effet sur la qualité du code et de l'application? Quelles décisions se sont révélées erronées et vous ont enseigné une leçon précieuse? Partagez vos expériences dans les commentaires.