Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo

Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo
É doado probar un analizador de código estático. Pero para implementalo, especialmente no desenvolvemento dun proxecto antigo grande, require habilidade. Se se fai incorrectamente, o analizador pode engadir traballo, ralentizar o desenvolvemento e desmotivar o equipo. Falemos brevemente sobre como abordar correctamente a integración da análise estática no proceso de desenvolvemento e comezar a usala como parte do CI/CD.

Introdución

Recentemente chamoume a atención a publicación "Comezando coa análise estática sen abrumar ao equipo". Por unha banda, este é un bo artigo co que paga a pena familiarizarse. Por outra banda, paréceme que aínda non ofrece unha resposta completa sobre como implementar sen dor a análise estática nun proxecto con moito O artigo di que Podes aceptar a débeda técnica e traballar só en código novo, pero non hai resposta sobre que facer con esta débeda técnica máis tarde.

O noso equipo de PVS-Studio ofrece a súa opinión sobre este tema. Vexamos como xorde o problema de implementar un analizador de código estático en primeiro lugar, como superar este problema e como eliminar gradualmente a débeda técnica sen dor.

Problemas

Normalmente non é difícil lanzar e ver como funciona un analizador estático [1]. Podes ver erros interesantes ou incluso potenciales vulnerabilidades asustados no código. Incluso podes arranxar algo, pero entón moitos programadores renuncian.

Todos os analizadores estáticos producen falsos positivos. Esta é unha característica da metodoloxía de análise de código estático e non se pode facer nada ao respecto. No caso xeral, este é un problema irresoluble, como confirma o teorema de Rice [2]. Os algoritmos de aprendizaxe automática tampouco axudarán [3]. Aínda que unha persoa non sempre poida dicir se este ou aquel código está mal, entón non deberías esperar isto do programa :).

Os falsos positivos non son un problema se o analizador estático xa está configurado:

  • Desactiváronse conxuntos de regras irrelevantes;
  • Desactiváronse algúns diagnósticos irrelevantes;
  • Se estamos a falar de C ou C++, as macros están marcadas que conteñen construcións específicas que fan que aparezan avisos inútiles en todos os lugares onde se usan ditas macros;
  • Márcanse funcións propias que realizan accións similares ás funcións do sistema (o seu propio análogo memcpy ou imprimirf) [4];
  • Os falsos positivos están desactivados especificamente mediante comentarios;
  • E así por diante.

Neste caso, podemos esperar unha baixa taxa de falsos positivos de aproximadamente 10-15% [5]. Noutras palabras, 9 de cada 10 avisos do analizador indicarán un problema real no código, ou polo menos un "código con cheiro forte". De acordo, este escenario é moi agradable e o analizador é un verdadeiro amigo do programador.

Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo
En realidade, nun proxecto grande, a imaxe inicial será completamente diferente. O analizador emite centos ou miles de avisos para o código heredado. É imposible comprender rapidamente cales destes avisos son relevantes e cales non. É irracional sentarse e comezar a tratar con todos estes avisos, xa que o traballo principal neste caso parará durante días ou semanas. Normalmente, un equipo non pode permitirse tal escenario. Tamén haberá unha gran cantidade de diferenzas que estraguen o historial de cambios. E a rápida edición masiva de tantos fragmentos do código dará lugar inevitablemente a novos erros tipográficos e erros.

E o máis importante, tal fazaña na loita contra as advertencias ten pouco sentido. Coinciden en que, dado que o proxecto leva moitos anos funcionando con éxito, a maioría dos erros críticos do mesmo xa foron corrixidos. Si, estas correccións eran moi caras, tiñan que ser depuradas, recibiron comentarios negativos dos usuarios sobre erros, etc. Un analizador estático axudaría a corrixir moitos destes erros na fase de codificación, de forma rápida e económica. Pero polo momento, dun xeito ou doutro, estes erros foron solucionados, e o analizador detecta principalmente erros non críticos no código antigo. É posible que este código non se utilice, é posible que se use moi raramente e un erro nel pode non levar a consecuencias notables. Quizais nalgún lugar a sombra do botón teña a cor incorrecta, pero isto non interfire co uso do produto por parte de ninguén.

Por suposto, incluso os pequenos erros seguen sendo erros. E ás veces un erro pode ocultar unha vulnerabilidade real. Non obstante, renunciar a todo e dedicar días/semanas a tratar defectos que apenas se manifestan parece unha idea dubidosa.

Os programadores miran, miran, miran todas estas advertencias sobre o vello código de traballo... E pensan: podemos prescindir da análise estática. Imos escribir algunha nova funcionalidade útil.

Ao seu xeito, teñen razón. Pensan que primeiro teñen que desfacerse dalgún xeito de todas estas advertencias. Só así poderán beneficiarse do uso regular do analizador de código. En caso contrario, as novas advertencias simplemente afogaranse nas antigas e ninguén lles prestará atención.

Esta é a mesma analoxía que coas advertencias do compilador. Non por ello recomendan manter o número de avisos do compilador en 0. Se hai 1000 avisos, cando hai 1001, ninguén lle prestará atención e non está claro onde buscar este aviso máis recente.

Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo
O peor desta historia é se alguén de arriba neste momento te obriga a usar a análise de código estático. Isto só desmotivará ao equipo, xa que dende o seu punto de vista haberá unha complexidade burocrática adicional que só se interpone. Ninguén mirará os informes do analizador e todo o uso será só "en papel". Eses. Formalmente, a análise está integrada no proceso DevOps, pero na práctica isto non beneficia a ninguén. Escoitamos historias detalladas nos postos dos asistentes á conferencia. Tal experiencia pode desanimar aos programadores a usar ferramentas de análise estática durante moito tempo, se non para sempre.

Implantación e eliminación da débeda técnica

De feito, non hai nada difícil ou asustado en introducir análise estática mesmo nun proxecto antigo grande.

CI / CD

Ademais, o analizador pódese facer inmediatamente parte do proceso de desenvolvemento continuo. Por exemplo, a distribución PVS-Studio contén utilidades para ver convenientemente o informe no formato que necesites e notificacións aos desenvolvedores que escribiron seccións problemáticas do código. Para aqueles que estean máis interesados ​​en lanzar PVS-Studio desde sistemas CI/CD, recoméndovos que se familiaricen co correspondente sección documentación e unha serie de artigos:

Pero volvamos á cuestión dunha gran cantidade de falsos positivos nas primeiras fases de implementación de ferramentas de análise de código.

Corrixir a débeda técnica existente e xestionar novos avisos

Os analizadores estáticos comerciais modernos permítenche estudar só avisos novos que aparecen en código novo ou modificado. A implementación deste mecanismo varía, pero a esencia é a mesma. No analizador estático PVS-Studio, esta funcionalidade implícase do seguinte xeito.

Para comezar rapidamente a usar a análise estática, suxerímoslle que os usuarios de PVS-Studio utilicen o mecanismo para a supresión masiva de avisos [6]. A idea xeral é a seguinte. O usuario lanzou o analizador e recibiu moitos avisos. Dado que un proxecto que estivo en desenvolvemento durante moitos anos está vivo, desenvolvendo e gañando cartos, o máis probable é que non haxa moitas advertencias no informe que indiquen defectos críticos. Noutras palabras, os erros críticos xa se solucionaron dun xeito ou doutro mediante métodos máis caros ou grazas aos comentarios dos clientes. En consecuencia, todo o que atopa actualmente o analizador pode considerarse débeda técnica, cousa que resulta impracticable para tratar de eliminar inmediatamente.

Podes dicirlle a PVS-Studio que considere estes avisos irrelevantes polo momento (garda a débeda técnica para máis tarde) e xa non os mostrará. O analizador crea un ficheiro especial onde garda información sobre erros que aínda non son interesantes. E agora PVS-Studio emitirá avisos só para o código novo ou modificado. Ademais, todo isto implícase de forma intelixente. Se, por exemplo, se engade unha liña baleira ao comezo do ficheiro de código fonte, entón o analizador comprende que, de feito, nada cambiou e seguirá en silencio. Este ficheiro de marcado pódese poñer nun sistema de control de versións. O ficheiro é grande, pero isto non é un problema, xa que non ten sentido gardalo a miúdo.

Agora todos os programadores verán avisos relacionados só co código novo ou modificado. Así, podes comezar a usar o analizador, como din, a partir do día seguinte. E pode volver á débeda técnica máis tarde, corrixir erros gradualmente e configurar o analizador.

Así, resolveuse o primeiro problema coa implementación do analizador nun gran proxecto antigo. Agora imos descubrir que facer coa débeda técnica.

Corrección de erros e refactorizacións

O máis sinxelo e natural é reservar un tempo para analizar os avisos do analizador suprimidos de forma masiva e tratalos gradualmente. Nalgún lugar deberías corrixir os erros no código, nalgún lugar deberías refactorizar para dicirlle ao analizador que o código non é problemático. Exemplo sinxelo:

if (a = b)

A maioría dos compiladores e analizadores de C++ quéixanse de tal código, xa que hai unha alta probabilidade de que realmente quixesen escribir (a == b). Pero hai un acordo tácito, e isto adoita indicarse na documentación, que se hai parénteses adicionais, considérase que o programador escribiu deliberadamente tal código e non hai que xurar. Por exemplo, na documentación de PVS-Studio para diagnósticos V559 (CWE-481) está claramente escrito que a seguinte liña será considerada correcta e segura:

if ((a = b))

Outro exemplo. Esquécese neste código C++? break ou non?

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

O analizador PVS-Studio emitirá unha advertencia aquí V796 (CWE-484). Isto pode non ser un erro, nese caso debería darlle unha pista ao analizador engadindo o atributo [[caer]] ou por exemplo __atributo__((fallthrough)):

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

Pódese dicir que tales cambios de código non solucionan o erro. Si, isto é certo, pero fai dúas cousas útiles. En primeiro lugar, o informe do analizador elimina os falsos positivos. En segundo lugar, o código faise máis comprensible para as persoas implicadas no seu mantemento. E isto é moi importante! Só por isto, paga a pena realizar pequenas refactorizacións para facer o código máis claro e máis fácil de manter. Dado que o analizador non entende se é necesario "romper" ou non, tampouco estará claro para os compañeiros programadores.

Ademais das correccións de erros e as refactorizacións, pode suprimir especificamente os avisos do analizador obviamente falsos. Pódense desactivar algúns diagnósticos irrelevantes. Por exemplo, alguén pensa que as advertencias non teñen sentido V550 sobre a comparación de valores float/double. E algúns os clasifican como importantes e dignos de estudo [7]. Que avisos se consideran relevantes e cales non o son, correspóndelle ao equipo de desenvolvemento decidir.

Hai outras formas de suprimir as alertas falsas. Por exemplo, o marcado macro mencionouse anteriormente. Todo isto descríbese con máis detalle na documentación. O máis importante é entender que se te achegas de forma gradual e sistemática a traballar con falsos positivos, non hai nada de malo con eles. A gran maioría dos avisos pouco interesantes desaparecen despois da configuración e só quedan os lugares que realmente requiren un estudo coidadoso e algúns cambios no código.

Ademais, sempre axudamos aos nosos clientes a configurar PVS-Studio se xorde algunha dificultade. Ademais, houbo casos nos que nós mesmos eliminamos falsas advertencias e corriximos erros [8]. Por se acaso, decidín mencionar que esta opción de cooperación estendida tamén é posible :).

Método de trinquete

Hai outro enfoque interesante para mellorar gradualmente a calidade do código eliminando a advertencia do analizador estático. A conclusión é que o número de avisos só pode diminuír.

Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo

Rexístrase o número de avisos emitidos polo analizador estático. A porta de calidade está configurada de tal xeito que agora só pode introducir un código que non aumente o número de operacións. Como resultado, o proceso de redución gradual do número de alarmas comeza axustando o analizador e corrixindo erros.

Aínda que unha persoa queira facer trampas un pouco e decide pasar a porta de calidade non eliminando os avisos no seu novo código, senón mellorando o antigo código de terceiros, isto non dá medo. De todos os xeitos, o trinquete xira nunha dirección e, gradualmente, o número de defectos irá diminuíndo. Aínda que unha persoa non queira corrixir os seus propios novos defectos, aínda terá que mellorar algo no código veciño. Nalgún momento, as formas sinxelas de reducir o número de avisos rematan e chega un momento no que se corrixirán os erros reais.

Esta metodoloxía descríbese con máis detalle nun artigo moi interesante de Ivan Ponomarev "Implementa análise estática no proceso, en lugar de usala para atopar erros", que recomendo ler a calquera persoa interesada en mellorar a calidade do código.

O autor do artigo tamén ten un informe sobre este tema: "Análise estática continua".

Conclusión

Espero que despois deste artigo, os lectores acepten máis as ferramentas de análise estática e queiran implementalas no proceso de desenvolvemento. Se tes algunha dúbida, sempre estamos preparados aconsellar usuarios do noso analizador estático PVS-Studio e axuda coa súa implementación.

Hai outras dúbidas típicas sobre se a análise estática pode ser realmente conveniente e útil. Tentei disipar a maioría destas dúbidas na publicación "Razóns para introducir o analizador de código estático PVS-Studio no proceso de desenvolvemento" [9].

Grazas pola túa atención e ven descargar e proba o analizador PVS-Studio.

Ligazóns adicionais

  1. Andrei Karpov. Como podo ver rapidamente avisos interesantes que produce o analizador PVS-Studio para o código C e C++?
  2. Wikipedia. Teorema de Rice.
  3. Andrey Karpov, Victoria Khanieva. Usar a aprendizaxe automática na análise estática do código fonte do programa.
  4. PVS-Estudio. Documentación. Configuración adicional de diagnóstico.
  5. Andrei Karpov. Características do analizador PVS-Studio usando o exemplo de bibliotecas básicas de EFL, 10-15% de falsos positivos.
  6. PVS-Estudio. Documentación. Supresión masiva de mensaxes do analizador.
  7. Ivan Andryashin. Sobre como probamos a análise estática no noso proxecto dun simulador educativo de cirurxía endovascular de raios X.
  8. Pavel Eremeev, Svyatoslav Razmyslov. Como o equipo de PVS-Studio mellorou o código de Unreal Engine.
  9. Andrei Karpov. Razóns para introducir o analizador de código estático PVS-Studio no proceso de desenvolvemento.

Como implementar un analizador de código estático nun proxecto legado sen desmotivar o equipo

Se queres compartir este artigo cun público de fala inglesa, utiliza a ligazón de tradución: Andrey Karpov. Como introducir un analizador de código estático nun proxecto legado e non desanimar ao equipo.

Fonte: www.habr.com

Engadir un comentario