Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe

Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe
Il est facile d'essayer un analyseur de code statique. Mais sa mise en œuvre, notamment dans le cadre du développement d’un grand projet ancien, nécessite des compétences. S'il n'est pas effectué correctement, l'analyseur peut ajouter du travail, ralentir le développement et démotiver l'équipe. Parlons brièvement de la façon d'aborder correctement l'intégration de l'analyse statique dans le processus de développement et de commencer à l'utiliser dans le cadre de CI/CD.

introduction

Récemment, mon attention a été attirée sur la publication "Démarrer avec l'analyse statique sans surcharger l'équipe". D'une part, c'est un bon article qui mérite d'être lu. D'un autre côté, il me semble qu'il ne fournit toujours pas de réponse complète sur la façon de mettre en œuvre sans douleur l'analyse statique dans un projet avec beaucoup du code existant. L'article dit que vous pouvez accepter une dette technique et travailler uniquement sur du nouveau code, mais il n'y a pas de réponse sur ce qu'il faudra faire de cette dette technique plus tard.

Notre équipe PVS-Studio vous donne son point de vue sur ce sujet. Voyons comment se pose en premier lieu le problème de la mise en œuvre d'un analyseur de code statique, comment surmonter ce problème et comment éliminer progressivement et sans douleur la dette technique.

Problèmes

Il n'est généralement pas difficile de lancer et de voir comment fonctionne un analyseur statique [1]. Vous pouvez voir des erreurs intéressantes ou même des vulnérabilités potentielles effrayantes dans le code. Vous pouvez même réparer quelque chose, mais de nombreux programmeurs abandonnent.

Tous les analyseurs statiques produisent des faux positifs. Il s’agit d’une caractéristique de la méthodologie d’analyse de code statique, et on ne peut rien y faire. Dans le cas général, il s’agit d’un problème insoluble, comme le confirme le théorème de Rice [2]. Les algorithmes d’apprentissage automatique n’aideront pas non plus [3]. Même si une personne ne peut pas toujours dire si tel ou tel code est faux, vous ne devez pas vous attendre à cela de la part du programme :).

Les faux positifs ne posent pas de problème si l'analyseur statique est déjà configuré :

  • Ensembles de règles non pertinents désactivés ;
  • Certains diagnostics non pertinents ont été désactivés ;
  • Si nous parlons de C ou de C++, les macros sont balisées et contiennent des constructions spécifiques qui provoquent l'apparition d'avertissements inutiles à chaque endroit où de telles macros sont utilisées ;
  • Les fonctions propres sont marquées qui effectuent des actions similaires aux fonctions du système (ses propres fonctions analogiques mémcpy ou printf) [4];
  • Les faux positifs sont spécifiquement désactivés à l'aide de commentaires ;
  • Et ainsi de suite.

Dans ce cas, on peut s’attendre à un faible taux de faux positifs d’environ 10 à 15 % [5]. En d’autres termes, 9 avertissements de l’analyseur sur 10 indiqueront un problème réel dans le code, ou au moins un « code à forte odeur ». D'accord, ce scénario est extrêmement agréable, et l'analyseur est un véritable ami du programmeur.

Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe
En réalité, dans un grand projet, l’image initiale sera complètement différente. L'analyseur émet des centaines ou des milliers d'avertissements pour le code existant. Il est impossible de comprendre rapidement lesquels de ces avertissements sont pertinents et lesquels ne le sont pas. Il est irrationnel de s'asseoir et de commencer à traiter tous ces avertissements, car le travail principal dans ce cas s'arrêtera pendant des jours ou des semaines. Généralement, une équipe ne peut pas se permettre un tel scénario. Il y aura également un grand nombre de différences qui gâcheront l'historique des modifications. Et une édition massive et rapide d’un si grand nombre de fragments du code entraînera inévitablement de nouvelles fautes de frappe et erreurs.

Et surtout, un tel exploit dans la lutte contre les avertissements n’a pas de sens. Convenez que depuis que le projet fonctionne avec succès depuis de nombreuses années, la plupart des erreurs critiques ont déjà été corrigées. Oui, ces correctifs étaient très coûteux, devaient être débogués, recevaient des commentaires négatifs des utilisateurs sur les bogues, etc. Un analyseur statique aiderait à corriger bon nombre de ces erreurs au stade du codage, rapidement et à moindre coût. Mais pour le moment, d'une manière ou d'une autre, ces erreurs ont été corrigées et l'analyseur détecte principalement les erreurs non critiques dans l'ancien code. Ce code ne peut pas être utilisé, il peut être utilisé très rarement et une erreur dans celui-ci peut ne pas entraîner de conséquences notables. Peut-être que quelque part l’ombre du bouton n’est pas de la bonne couleur, mais cela n’interfère pas avec l’utilisation du produit par quiconque.

Bien entendu, même des erreurs mineures restent des erreurs. Et parfois, une erreur peut cacher une réelle vulnérabilité. Cependant, tout abandonner et passer des jours/semaines à gérer des défauts qui se manifestent à peine semble une idée douteuse.

Les programmeurs regardent, regardent, regardent tous ces avertissements concernant l'ancien code fonctionnel... Et ils pensent : nous pouvons nous passer de l'analyse statique. Allons écrire de nouvelles fonctionnalités utiles.

À leur manière, ils ont raison. Ils pensent qu’ils doivent d’abord se débarrasser de tous ces avertissements. Ce n’est qu’alors qu’ils pourront bénéficier d’une utilisation régulière de l’analyseur de code. Sinon, les nouveaux avertissements se noieront simplement dans les anciens et personne n’y prêtera attention.

C'est la même analogie qu'avec les avertissements du compilateur. Ce n'est pas pour rien qu'ils recommandent de maintenir le nombre d'avertissements du compilateur à 0. S'il y a 1000 1001 avertissements, alors lorsqu'il y en aura XNUMX XNUMX, personne n'y prêtera attention et il n'est pas clair où chercher ce nouvel avertissement.

Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe
Le pire dans cette histoire, c'est si quelqu'un d'en haut vous oblige à utiliser l'analyse de code statique. Cela ne fera que démotiver l'équipe, car de leur point de vue, il y aura une complexité bureaucratique supplémentaire qui ne fera que gêner. Personne ne consultera les rapports de l’analyseur et toute utilisation se fera uniquement « sur papier ». Ceux. Formellement, l'analyse est intégrée au processus DevOps, mais dans la pratique, cela ne profite à personne. Nous avons entendu des histoires détaillées sur les stands des participants à la conférence. Une telle expérience peut décourager les programmeurs d’utiliser les outils d’analyse statique pendant longtemps, voire pour toujours.

Mettre en œuvre et éliminer la dette technique

En fait, il n’y a rien de difficile ou d’effrayant à introduire l’analyse statique, même dans un grand projet ancien.

CI / CD

De plus, l’analyseur peut immédiatement être intégré au processus de développement continu. Par exemple, la distribution PVS-Studio contient des utilitaires permettant de visualiser facilement le rapport dans le format dont vous avez besoin et des notifications aux développeurs qui ont écrit des sections problématiques du code. Pour ceux qui sont plus intéressés par le lancement de PVS-Studio à partir de systèmes CI/CD, je vous recommande de vous familiariser avec le correspondant section une documentation et une série d'articles :

Mais revenons sur la problématique du grand nombre de faux positifs dès les premières étapes de mise en œuvre des outils d’analyse de code.

Réparer la dette technique existante et gérer les nouveaux avertissements

Les analyseurs statiques commerciaux modernes vous permettent d'étudier uniquement les nouveaux avertissements qui apparaissent dans un code nouveau ou modifié. La mise en œuvre de ce mécanisme varie, mais l’essence est la même. Dans l'analyseur statique PVS-Studio, cette fonctionnalité est implémentée comme suit.

Pour commencer rapidement à utiliser l'analyse statique, nous suggérons aux utilisateurs de PVS-Studio d'utiliser le mécanisme de suppression massive des avertissements [6]. L'idée générale est la suivante. L'utilisateur a lancé l'analyseur et a reçu de nombreux avertissements. Étant donné qu'un projet en développement depuis de nombreuses années est vivant, se développe et rapporte de l'argent, il n'y aura probablement pas beaucoup d'avertissements dans le rapport indiquant des défauts critiques. En d’autres termes, les bugs critiques ont déjà été corrigés d’une manière ou d’une autre en utilisant des méthodes plus coûteuses ou grâce aux retours des clients. En conséquence, tout ce que l'analyseur trouve actuellement peut être considéré comme une dette technique, qu'il n'est pas pratique d'essayer d'éliminer immédiatement.

Vous pouvez demander à PVS-Studio de considérer ces avertissements comme non pertinents pour le moment (conservez la dette technique pour plus tard), et il ne les affichera plus. L'analyseur crée un fichier spécial dans lequel il enregistre des informations sur les erreurs qui ne sont pas encore intéressantes. Et désormais, PVS-Studio émettra des avertissements uniquement pour le code nouveau ou modifié. De plus, tout cela est intelligemment mis en œuvre. Si, par exemple, une ligne vide est ajoutée au début du fichier de code source, alors l'analyseur comprend qu'en fait rien n'a changé et restera silencieux. Ce fichier de balisage peut être placé dans un système de contrôle de version. Le fichier est volumineux, mais ce n'est pas un problème, car il ne sert à rien de le stocker souvent.

Désormais, tous les programmeurs verront des avertissements liés uniquement au code nouveau ou modifié. Ainsi, vous pouvez commencer à utiliser l'analyseur, comme on dit, dès le lendemain. Et vous pourrez revenir à la dette technique plus tard, corriger progressivement les erreurs et configurer l'analyseur.

Ainsi, le premier problème lié à la mise en œuvre de l'analyseur dans un grand projet ancien a été résolu. Voyons maintenant quoi faire de la dette technique.

Corrections de bugs et refactorisations

Le plus simple et le plus naturel est de prévoir du temps pour analyser les avertissements massivement supprimés de l'analyseur et de les traiter progressivement. Quelque part, vous devez corriger les erreurs dans le code, quelque part, vous devez refactoriser pour indiquer à l'analyseur que le code ne pose pas de problème. Exemple simple :

if (a = b)

La plupart des compilateurs et analyseurs C++ se plaignent de ce type de code, car il y a une forte probabilité qu'ils aient réellement voulu écrire (un == b). Mais il existe un accord tacite, et cela est généralement noté dans la documentation, selon lequel s'il y a des parenthèses supplémentaires, on considère que le programmeur a délibérément écrit un tel code, et il n'est pas nécessaire de jurer. Par exemple, dans la documentation PVS-Studio pour les diagnostics V559 (CWE-481) il est clairement écrit que la ligne suivante sera considérée comme correcte et sûre :

if ((a = b))

Un autre exemple. Est-il oublié dans ce code C++ ? pause ou pas?

case A:
  foo();
case B:
  bar();
  break;

L'analyseur PVS-Studio émettra un avertissement ici V796 (CWE-484). Il se peut qu'il ne s'agisse pas d'une erreur, auquel cas vous devez donner un indice à l'analyseur en ajoutant l'attribut [[tomber dans]] ou par exemple __attribute__((échec)):

case A:
  foo();
  [[fallthrough]];
case B:
  bar();
  break;

On peut dire que de telles modifications de code ne corrigent pas le bug. Oui, c’est vrai, mais cela fait deux choses utiles. Premièrement, le rapport de l’analyseur élimine les faux positifs. Deuxièmement, le code devient plus compréhensible pour les personnes impliquées dans sa maintenance. Et c'est très important ! Rien que pour cela, cela vaut la peine d’effectuer des refactorisations mineures pour rendre le code plus clair et plus facile à maintenir. Étant donné que l’analyseur ne comprend pas si une « pause » est nécessaire ou non, cela ne sera pas non plus clair pour les autres programmeurs.

En plus des corrections de bugs et des refactorisations, vous pouvez spécifiquement supprimer les avertissements manifestement faux de l'analyseur. Certains diagnostics non pertinents peuvent être désactivés. Par exemple, quelqu’un pense que les avertissements sont inutiles V550 à propos de la comparaison des valeurs float/double. Et certains les classent comme importants et dignes d’être étudiés [7]. C'est à l'équipe de développement de décider quels avertissements sont considérés comme pertinents et lesquels ne le sont pas.

Il existe d'autres moyens de supprimer les fausses alertes. Par exemple, le balisage macro a été mentionné plus tôt. Tout cela est décrit plus en détail dans la documentation. Le plus important est de comprendre que si vous abordez progressivement et systématiquement le travail avec des faux positifs, il n'y a rien de mal à cela. La grande majorité des avertissements inintéressants disparaissent après la configuration, et seuls les endroits qui nécessitent vraiment une étude approfondie et quelques modifications dans le code restent.

De plus, nous aidons toujours nos clients à configurer PVS-Studio en cas de difficultés. De plus, il y a eu des cas où nous avons nous-mêmes éliminé les faux avertissements et corrigé les erreurs [8]. Juste au cas où, j'ai décidé de mentionner que cette option de coopération étendue est également possible :).

Méthode à cliquet

Il existe une autre approche intéressante pour améliorer progressivement la qualité du code en éliminant l'avertissement de l'analyseur statique. L’essentiel est que le nombre d’avertissements ne peut que diminuer.

Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe

Le nombre d'avertissements émis par l'analyseur statique est enregistré. Le portail qualité est configuré de telle manière que vous ne pouvez désormais saisir qu'un code qui n'augmente pas le nombre d'opérations. En conséquence, le processus de réduction progressive du nombre d'alarmes commence par l'ajustement de l'analyseur et la correction des erreurs.

Même si une personne veut tricher un peu et décide de franchir le cap de la qualité non pas en éliminant les avertissements dans son nouveau code, mais en améliorant l'ancien code tiers, cela n'a pas peur. Tout de même, le cliquet tourne dans un sens, et progressivement le nombre de défauts va diminuer. Même si une personne ne veut pas corriger elle-même ses nouveaux défauts, elle devra quand même améliorer quelque chose dans le code voisin. À un moment donné, les moyens simples de réduire le nombre d’avertissements prennent fin, et il arrive un moment où les vrais bugs seront corrigés.

Cette méthodologie est décrite plus en détail dans un article très intéressant d'Ivan Ponomarev "Implémentez l'analyse statique dans le processus, plutôt que de l'utiliser pour trouver des bogues", que je recommande de lire à toute personne intéressée par l'amélioration de la qualité du code.

L'auteur de l'article dispose également d'un rapport sur ce sujet : "Analyse statique continue".

Conclusion

J'espère qu'après cet article, les lecteurs accepteront davantage les outils d'analyse statique et voudront les implémenter dans le processus de développement. Si vous avez des questions, nous sommes toujours prêts consulter utilisateurs de notre analyseur statique PVS-Studio et aider à sa mise en œuvre.

Il existe d'autres doutes typiques quant à savoir si l'analyse statique peut réellement être pratique et utile. J'ai essayé de dissiper la plupart de ces doutes dans la publication « Raisons d'introduire l'analyseur de code statique PVS-Studio dans le processus de développement » [9].

Merci de votre attention et venez скачать et essayez l'analyseur PVS-Studio.

Liens supplémentaires

  1. Andreï Karpov. Comment puis-je voir rapidement les avertissements intéressants que l'analyseur PVS-Studio produit pour le code C et C++ ?
  2. Wikipedia. Théorème de Rice.
  3. Andreï Karpov, Victoria Khanieva. Utiliser l'apprentissage automatique dans l'analyse statique du code source du programme.
  4. PVS-Studio. Documentation. Paramètres de diagnostic supplémentaires.
  5. Andreï Karpov. Caractéristiques de l'analyseur PVS-Studio sur l'exemple des EFL Core Libraries, 10-15% de faux positifs.
  6. PVS-Studio. Documentation. Suppression massive des messages de l'analyseur.
  7. Ivan Andriachine. À propos de la façon dont nous avons testé l'analyse statique sur notre projet de simulateur pédagogique de chirurgie endovasculaire à rayons X.
  8. Pavel Eremeev, Sviatoslav Razmyslov. Comment l'équipe PVS-Studio a amélioré le code de l'Unreal Engine.
  9. Andreï Karpov. Raisons d'introduire l'analyseur de code statique PVS-Studio dans le processus de développement.

Comment implémenter un analyseur de code statique dans un projet existant sans démotiver l'équipe

Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien de traduction : Andrey Karpov. Comment introduire un analyseur de code statique dans un projet existant et ne pas décourager l'équipe.

Source: habr.com

Ajouter un commentaire