Implementearje statyske analyse yn it proses, ynstee fan it te brûken om bugs te finen

Ik waard frege om dit artikel te skriuwen troch de grutte hoemannichte materialen oer statyske analyse dy't hieltyd mear ûnder myn oandacht komme. Earst, dit PVS-studio blog, dy't himsels aktyf befoarderet op Habré mei help fan resinsjes fan flaters fûn troch har ark yn iepen boarneprojekten. Koartlyn PVS-studio ymplementearre Java stipe, en, fansels, de ûntwikkelders fan IntelliJ IDEA, waans ynboude analyzer is wierskynlik de meast avansearre foar Java hjoed, koe net fuortbliuwe.

By it lêzen fan sokke resinsjes krije jo it gefoel dat wy it hawwe oer in magysk elixir: druk op de knop, en hjir is it - in list fan defekten foar jo eagen. It liket derop dat as analysatoren ferbetterje, mear en mear bugs automatysk sille wurde fûn, en de produkten dy't troch dizze robots wurde skansearre sille better en better wurde, sûnder ynspanning fan ús kant.

Mar d'r binne gjin magyske elixirs. Ik wol graach prate oer wat normaal net oer praat wurdt yn berjochten lykas "hjir binne de dingen dy't ús robot kin fine": wat analysatoren net kinne dwaan, wat is har wirklike rol en plak yn it softwareferlieningsproses, en hoe't se se korrekt ymplementearje .

Implementearje statyske analyse yn it proses, ynstee fan it te brûken om bugs te finen
Ratchet (boarne: Wikipedia).

Wat statyske analyzers noait kinne dwaan

Wat is boarne koade analyze, út in praktysk eachpunt? Wy jouwe wat boarnekoade as ynfier, en as útfier, yn in koarte tiid (folle koarter as rinnende tests) krije wy wat ynformaasje oer ús systeem. De fûnemintele en wiskundich ûnoerwinbere beheining is dat wy op dizze manier mar in frij smelle klasse fan ynformaasje krije kinne.

It meast ferneamde foarbyld fan in probleem dat kin net oplost wurde mei help fan statyske analyze is shutdown probleem: Dit is in stelling dy't bewiist dat it ûnmooglik is om in algemien algoritme te ûntwikkeljen dat út 'e boarnekoade fan in programma kin bepale oft it yn in einige tiid in loop of einiget. In útwreiding fan dizze stelling is Rice's stelling, dy't stelt dat foar elke net-triviale eigenskip fan berekkenbere funksjes, bepale oft in willekeurich programma in funksje evaluearret mei sa'n eigenskip is in algoritmysk intractable probleem. It is bygelyks ûnmooglik om in analysator te skriuwen dy't út elke boarnekoade kin bepale oft it programma dat wurdt analysearre in ymplemintaasje is fan in algoritme dat bygelyks it kwadraat fan in hiel getal berekkent.

Sa hat de funksjonaliteit fan statyske analysatoren ûnoerkombere beheiningen. In statyske analysator sil nea yn alle gefallen sokke dingen kinne opspoare as bygelyks it foarkommen fan in "nul pointer útsûndering" yn talen dy't de wearde fan nul tastean, of yn alle gefallen it foarkommen fan in " attribút net fûn" yn dynamysk typte talen. Alles wat de meast avansearre statyske analysator kin dwaan is spesjale gefallen markearje, wêrfan it oantal, ûnder alle mooglike problemen mei jo boarnekoade, sûnder oerdriuwing in drip yn 'e oseaan is.

Statyske analyze giet net oer it finen fan bugs

Ut it boppesteande folget de konklúzje: statyske analyze is gjin middel om it oantal defekten yn in programma te ferminderjen. Ik soe weagje om te sizzen: as jo foar it earst tapast wurde op jo projekt, sil it "ynteressante" plakken fine yn 'e koade, mar nei alle gedachten sil it gjin defekten fine dy't de kwaliteit fan jo programma beynfloedzje.

De foarbylden fan defekten dy't automatysk fûn wurde troch analysators binne yndrukwekkend, mar wy moatte net ferjitte dat dizze foarbylden waarden fûn troch it scannen fan in grutte set fan grutte koadebases. Troch itselde prinsipe fine hackers dy't de kâns hawwe om ferskate ienfâldige wachtwurden op in grut oantal akkounts te besykjen, úteinlik dy akkounts dy't in ienfâldich wachtwurd hawwe.

Betsjut dit dat statyske analyze net brûkt wurde moat? Fansels net! En om krekt deselde reden dat it wurdich is om elk nij wachtwurd te kontrolearjen om te soargjen dat it is opnommen yn 'e stoplist fan "ienfâldige" wachtwurden.

Statyske analyze is mear dan it finen fan bugs

Yn feite binne de problemen praktysk oplost troch analyse folle breder. Ommers, yn 't algemien is statyske analyse elke ferifikaasje fan boarnekoades útfierd foardat se wurde lansearre. Hjir binne wat dingen dy't jo dwaan kinne:

  • Koadestyl kontrolearje yn 'e breedste sin fan it wurd. Dit omfettet sawol it kontrolearjen fan opmaak, it sykjen nei it brûken fan lege/ekstra heakjes, it ynstellen fan drompels op metriken lykas oantal rigels/sykomatyske kompleksiteit fan in metoade, ensfh. Yn Java is sa'n ark Checkstyle, yn Python - flake8. Programma's fan dizze klasse wurde meastal "linters" neamd.
  • Net allinich útfierbere koade kin wurde analysearre. Boarnebestannen lykas JSON, YAML, XML, .properties kinne (en moatte!) automatysk wurde kontrolearre op jildigens. It is ommers better om út te finen dat de JSON-struktuer is brutsen troch guon unpaired quotes yn in ier stadium fan automatyske Pull Request-ferifikaasje dan tidens testútfiering of runtiid? Passende ark binne beskikber: bgl. YAMLlint, JSONLint.
  • Kompilaasje (of parsearjen foar dynamyske programmeartalen) is ek in soarte fan statyske analyze. Yn 't algemien binne kompilers yn steat om warskôgingen te produsearjen dy't problemen mei boarnekoadekwaliteit oanjaan en moatte net negearre wurde.
  • Soms is kompilaasje mear dan allinich it kompilearjen fan útfierbere koade. Bygelyks, as jo dokumintaasje hawwe yn it formaat AsciiDoctor, dan op it momint fan it feroarjen fan it yn HTML/PDF de AsciiDoctor handler (Maven plugin) kin warskôgings jaan, bygelyks oer brutsen ynterne keppelings. En dit is in goede reden om it Pull Request net te akseptearjen mei dokumintaasjewizigingen.
  • Stavering kontrôle is ek in soarte fan statyske analyze. Utility aspell is by steat om te kontrolearjen stavering net allinnich yn dokumintaasje, mar ek yn programma boarne koades (kommentaar en letterlik) yn ferskate programmeartaal, ynklusyf C / C ++, Java en Python. In staveringsflater yn de brûkersynterface of dokumintaasje is ek in defekt!
  • Konfiguraasjetests (oer wat se binne - sjoch. dit и dit rapporten), hoewol útfierd yn in runtime foar ienheidstest lykas pytest, binne yn feite ek in soarte fan statyske analyse, om't se gjin boarnekoades útfiere tidens har útfiering.

Sa't jo sjen kinne, spilet sykjen nei bugs yn dizze list de minst wichtige rol, en al it oare is beskikber troch it brûken fan fergese iepen boarne-ark.

Hokker fan dizze soarten statyske analyse moatte jo brûke yn jo projekt? Fansels, hoe mear hoe better! It wichtichste is om it goed út te fieren, dat sil fierder besprutsen wurde.

Leveringspipeline as in multi-stage filter en statyske analyse as syn earste etappe

De klassike metafoar foar trochgeande yntegraasje is in pipeline wêrby't feroaringen streame, fan boarnekoadewizigingen oant levering oant produksje. De standert folchoarder fan stadia yn dizze pipeline sjocht der sa út:

  1. statyske analyze
  2. kompilaasje
  3. ienheid tests
  4. yntegraasje tests
  5. UI tests
  6. hânmjittich kontrôle

Feroarings dy't ôfwiisd binne yn 'e N-e faze fan' e pipeline wurde net oerbrocht nei poadium N + 1.

Wêrom krekt sa en net oars? Yn it testdiel fan 'e pipeline sille testers de bekende testpiramide werkenne.

Implementearje statyske analyse yn it proses, ynstee fan it te brûken om bugs te finen
Test piramide. Boarne: artikel Martin Fowler.

Oan 'e ûnderkant fan dizze piramide binne tests dy't makliker te skriuwen binne, flugger út te fieren en gjin oanstriid hawwe om te mislearjen. Dêrom moatte d'r mear fan wêze, se moatte mear koade dekke en earst wurde útfierd. Oan 'e boppekant fan' e piramide is it tsjinoerstelde wier, dus it oantal yntegraasje- en UI-tests moatte wurde fermindere nei it nedige minimum. De persoan yn dizze keten is de djoerste, trage en ûnbetroubere boarne, dus hy is oan 'e ein en docht allinich it wurk as de foarige stadia gjin mankeminten fûnen. Deselde prinsipes wurde lykwols brûkt om in pipeline te bouwen yn dielen dy't net direkt relatearre binne oan testen!

Ik soe graach biede in analogy yn 'e foarm fan in multi-stage wetter filtration systeem. Smoarge wetter (feroarings mei mankeminten) wurdt levere oan de ynput; by de útgong moatte wy skjin wetter krije, wêryn alle net-winske fersmoargingen fuorthelle binne.

Implementearje statyske analyse yn it proses, ynstee fan it te brûken om bugs te finen
Multi-stage filter. Boarne: Wikimedia Commons

Lykas jo witte, binne skjinmeitsjen filters ûntwurpen sadat elke folgjende kaskade kin filterje út in hieltyd fyner fraksje fan kontaminanten. Tagelyk hawwe kaskaden fan grouwe suvering hegere trochset en legere kosten. Yn ús analogy betsjut dit dat poarten fan ynputkwaliteit rapper binne, minder ynspanning nedich binne om te begjinnen en sels pretentielozer binne yn wurking - en dit is de folchoarder wêryn se binne boud. De rol fan statyske analyze, dy't, sa't wy no begripe, allinich de grutste defekten kinne ferwiderje, is de rol fan it "modder" raster oan it begjin fan 'e filterkaskade.

Statyske analyze op himsels ferbettert de kwaliteit fan it einprodukt net, lykas in "modderfilter" wetter net drinkber makket. En dochs, yn kombinaasje mei oare eleminten fan 'e pipeline, is it belang dúdlik. Hoewol't yn in multistage filter de útfier stadia binne mooglik yn steat om te fangen alles dat de ynfier stadia dogge, it is dúdlik hokker gefolgen sille resultearje út in besykjen om te dwaan mei fyn-suvering stadia allinnich, sûnder ynfier stadia.

It doel fan 'e "modderfal" is om folgjende kaskaden te ûntlêsten fan it fangen fan heul grouwe defekten. Bygelyks, op syn minst, de persoan dy't de koade beoardieling docht, moat net ôfliede wurde troch ferkeard opmakke koade en oertredings fan fêststelde kodearringsnoarmen (lykas ekstra heakjes of te djip nestele tûken). Bugs lykas NPE's moatte wurde fongen troch ienheidstests, mar as sels foar de test de analysator ús oanjout dat in brek moat barre, sil dit it reparearjen signifikant fersnelle.

Ik leau dat it no dúdlik is wêrom't statyske analyse de kwaliteit fan it produkt net ferbetteret as it sa no en dan brûkt wurdt, en moat konstant brûkt wurde om wizigingen mei grutte defekten út te filterjen. De fraach oft it brûken fan in statyske analysator de kwaliteit fan jo produkt sil ferbetterje is sawat gelyk oan de fraach: "Sil wetter nommen út in smoarge fiver wurde ferbettere yn drinkkwaliteit as it troch in vergiet wurdt trochjûn?"

Ymplemintaasje yn in legacy projekt

In wichtige praktyske fraach: hoe kinne statyske analyse yn it trochgeande yntegraasjeproses as "kwaliteitspoarte" ymplementearje? Yn it gefal fan automatyske testen is alles dúdlik: d'r is in set fan tests, it mislearjen fan ien fan har is genôch reden om te leauwen dat de gearkomste de kwaliteitspoarte net passe. In besykjen om in poarte op deselde manier te ynstallearjen op basis fan de resultaten fan in statyske analyze mislearret: d'r binne tefolle analyze warskôgings yn 'e legacy koade, jo wolle se net folslein negearje, mar it is ek ûnmooglik om te stopjen mei it ferstjoeren fan in produkt gewoan om't it analysator warskôgings befettet.

As it foar it earst brûkt wurdt, produseart de analysator in enoarm oantal warskôgingen op elk projekt, wêrfan de grutte mearderheid net relatearre is oan it goede funksjonearjen fan it produkt. It is ûnmooglik om al dizze opmerkingen tagelyk te korrigearjen, en in protte binne net nedich. Wy witte ommers dat ús produkt as gehiel wurket, sels foardat wy statyske analyse yntrodusearje!

As gefolch, in protte binne beheind ta ynsidintele gebrûk fan statyske analyze, of brûk it allinnich yn ynformaasje modus, doe't in analyzer rapport wurdt gewoan útjûn tidens gearkomste. Dit is lykweardich oan it ûntbrekken fan elke analyze, want as wy al in protte warskôgings hawwe, dan is it foarkommen fan in oar (net as hoe serieus) by it feroarjen fan de koade ûngemurken.

De folgjende metoaden foar it ynfieren fan kwaliteitspoarten binne bekend:

  • It ynstellen fan in limyt op it totale oantal warskôgings of it oantal warskôgings dield troch it oantal rigels koade. Dit wurket min, om't sa'n poarte frij feroarings mei nije mankeminten trochjaan lit, salang't har limyt net oerhelle wurdt.
  • Fixing, op in bepaald momint, alle âlde warskôgings yn 'e koade as negearre, en wegerje te bouwen as nije warskôgings foarkomme. Dizze funksjonaliteit wurdt fersoarge troch PVS-studio en guon online boarnen, bygelyks Codacy. Ik hie net de kâns om te wurkjen yn PVS-studio, lykas foar myn ûnderfining mei Codacy, har haadprobleem is dat it bepalen fan wat in "âlde" en wat in "nije" flater is in frij komplekse algoritme is dat net altyd wurket korrekt, benammen as triemmen binne swier wizige of omneamd. Yn myn ûnderfining koe Codacy negearje nije warskôgings yn in pull fersyk, wylst tagelyk net trochjaan in pull fersyk fanwege warskôgings dy't wiene net yn ferbân mei feroarings yn de koade fan in opjûne PR.
  • Neffens my is de meast effektive oplossing dejinge dy't yn it boek beskreaun is Trochgeande levering "ratcheting metoade". De basis idee is dat it oantal statyske analyse warskôgings is in eigendom fan eltse release, en allinnich feroarings binne tastien dy't net tanimme it totale oantal warskôgings.

Ratchet

It wurket op dizze manier:

  1. Yn 'e earste faze wurdt in rekord makke yn' e metadata oer de frijlitting fan it oantal warskôgings yn 'e koade fûn troch de analysatoren. Dus, as jo streamop bouwe, skriuwt jo repository manager net allinich "frijlitte 7.0.2", mar "frijlitte 7.0.2 mei 100500 warskôgings foar kontrôlestyl." As jo ​​in avansearre repository manager brûke (lykas Artifactory), is it opslaan fan sokke metadata oer jo frijlitting maklik.
  2. No elk pull-fersyk, as boud, fergeliket it oantal resultearjende warskôgings mei it oantal warskôgings beskikber yn 'e hjoeddeistige release. As PR liedt ta in tanimming fan dit oantal, dan passeart de koade de kwaliteitspoarte net foar statyske analyze. As it oantal warskôgings ôfnimt of net feroaret, dan giet it foarby.
  3. By de folgjende release sil it op 'e nij berekkene oantal warskôgings opnij wurde opnommen yn' e release-metadata.

Sa stadichoan, mar stadichoan (lykas as in ratchet wurket), sil it oantal warskôgingen nei nul neigean. Fansels kin it systeem ferrifelje troch in nije warskôging yn te fieren, mar dy fan in oar te korrigearjen. Dit is normaal, om't it oer in lange ôfstân resultaten jout: warskôgingen wurde korrizjearre, yn 'e regel, net yndividueel, mar tagelyk yn in groep fan in bepaald type, en alle maklik te ferwiderjen warskôgings wurde frij fluch elimineare.

Dizze grafyk toant it totale oantal Checkstyle warskôgings foar seis moannen fan wurking fan sa'n "ratchet" op ien fan ús OpenSource-projekten. It oantal warskôgings is ôfnommen mei in folchoarder fan grutte, en dit barde fansels, parallel mei produktûntwikkeling!

Implementearje statyske analyse yn it proses, ynstee fan it te brûken om bugs te finen

Ik brûk in oanpaste ferzje fan dizze metoade, apart telle warskôgings troch projekt module en analyse ark, resultearret yn in YAML triem mei build metadata dat sjocht der sa út:

celesta-sql:
  checkstyle: 434
  spotbugs: 45
celesta-core:
  checkstyle: 206
  spotbugs: 13
celesta-maven-plugin:
  checkstyle: 19
  spotbugs: 0
celesta-unit:
  checkstyle: 0
  spotbugs: 0

Yn elk avansearre CI-systeem kin ratchet wurde ymplementearre foar elke statyske analyse-ark sûnder te fertrouwen op plugins en ark fan tredden. Elke analysator produseart in eigen rapport yn in ienfâldige tekst- as XML-formaat dat maklik te analysearjen is. Alles wat oerbliuwt is de nedige logika yn it CI-skript te skriuwen. Jo kinne sjen hoe't dit wurdt ymplementearre yn ús iepen boarne projekten basearre op Jenkins en Artifactory hjir of hjir. Beide foarbylden binne ôfhinklik fan de biblioteek ratchetlib: metoade countWarnings() telt xml-tags yn bestannen generearre troch Checkstyle en Spotbugs op 'e gewoane manier, en compareWarningMaps() ymplemintearret deselde ratchet, smyt in flater as it oantal warskôgings yn ien fan de kategoryen nimt ta.

In nijsgjirrige ymplemintaasje fan 'e "ratchet" is mooglik foar it analysearjen fan de stavering fan opmerkingen, letterlike teksten en dokumintaasje mei aspell. Lykas jo witte, binne by it kontrolearjen fan stavering net alle wurden dy't ûnbekend binne yn it standertwurdboek ferkeard; se kinne tafoege wurde oan it brûkerswurdboek. As jo ​​in oanpast wurdboek diel meitsje fan de boarnekoade fan it projekt, dan kin de staveringskwaliteitspoarte sa formulearre wurde: aspell útfiere mei in standert en oanpast wurdboek moatte net fine gjin stavering flaters.

Oer it belang fan it reparearjen fan de analysatorferzje

Ta beslút, it punt om op te merken is dat nettsjinsteande hoe't jo analyse ymplementearje yn jo leveringpipeline, de ferzje fan 'e analysator moat wurde reparearre. As jo ​​de analysator spontaan bywurkje kinne, dan kinne by it gearstallen fan it folgjende pull-oanfraach nije defekten "opkomme" dy't net relatearre binne oan koadewizigingen, mar binne relatearre oan it feit dat de nije analysator gewoan mear defekten kin fine - en dit sil jo proses fan it akseptearjen fan pull-oanfragen brekke. It opwurdearjen fan in analysator moat in bewuste aksje wêze. Lykwols, stive fixaasje fan de ferzje fan elke gearkomste komponint is oer it algemien in needsaaklike eask en in ûnderwerp foar in aparte diskusje.

befinings

  • Statyske analyse sil gjin bugs foar jo fine en sil de kwaliteit fan jo produkt net ferbetterje as gefolch fan ien applikaasje. In posityf effekt op kwaliteit kin allinich berikt wurde troch syn konstante gebrûk yn 'e leveringsproses.
  • It finen fan bugs is hielendal net de haadtaak fan analyse; de ​​grutte mearderheid fan nuttige funksjes is beskikber yn opensource-ark.
  • Implementearje kwaliteitspoarten basearre op de resultaten fan statyske analyse yn 'e heulste etappe fan' e leveringspipeline, mei in "ratchet" foar legacy-koade.

referinsjes

  1. Trochgeande levering
  2. A. Kudryavtsev: Programma analyze: hoe te begripen dat jo in goede programmeur binne rapportearje oer ferskate metoaden fan koade-analyze (net allinich statysk!)

Boarne: www.habr.com

Add a comment