Ota staattinen analyysi käyttöön prosessissa sen sijaan, että käytät sitä virheiden etsimiseen

Minut sai tämän artikkelin kirjoittamaan suuri määrä staattista analyysiä käsittelevää materiaalia, joka on tullut tietooni. Ensinnäkin tämä PVS-studion blogi, joka mainostaa itseään aktiivisesti Habrén avulla avoimen lähdekoodin projekteissa työkalunsa löytämien virheiden arvioiden avulla. Äskettäin otettu käyttöön PVS-studio Java tuki, ja tietysti IntelliJ IDEA:n kehittäjät, jonka sisäänrakennettu analysaattori on luultavasti edistynein Javalla nykyään, ei voinut pysyä poissa.

Kun luet tällaisia ​​arvosteluja, saat tunteen, että puhumme maagisesta eliksiiristä: paina painiketta, ja tässä se on - luettelo vioista silmiesi edessä. Näyttää siltä, ​​että analysaattoreiden parantuessa yhä enemmän vikoja löydetään automaattisesti ja näiden robottien skannaamat tuotteet muuttuvat yhä paremmiksi ilman meidän ponnistelujamme.

Mutta maagisia eliksiirejä ei ole olemassa. Haluaisin puhua siitä, mistä ei yleensä puhuta viesteissä, kuten "tästä robottimme voi löytää": mitä analysaattorit eivät voi tehdä, mikä on niiden todellinen rooli ja paikka ohjelmistojen toimitusprosessissa ja kuinka ne toteutetaan oikein .

Ota staattinen analyysi käyttöön prosessissa sen sijaan, että käytät sitä virheiden etsimiseen
Räikkä (lähde: wikipedia).

Mitä staattiset analysaattorit eivät voi koskaan tehdä

Mitä on lähdekoodianalyysi käytännön näkökulmasta? Annamme jonkin verran lähdekoodia syötteenä ja ulostulona, ​​lyhyessä ajassa (paljon lyhyemmässä ajassa kuin suoritettavat testit) saamme tietoa järjestelmästämme. Perimmäinen ja matemaattisesti ylitsepääsemätön rajoitus on se, että voimme saada tällä tavalla vain melko kapeaa luokkaa tietoa.

Tunnetuin esimerkki ongelmasta, jota ei voida ratkaista staattisen analyysin avulla, on sammutusongelma: Tämä on lause, joka todistaa, että on mahdotonta kehittää yleistä algoritmia, joka voi määrittää ohjelman lähdekoodista, onko se silmukka vai päättyykö rajallisessa ajassa. Tämän lauseen laajennus on Ricen lause, jossa todetaan, että minkä tahansa laskettavien funktioiden ei-triviaalien ominaisuuden osalta sen määrittäminen, arvioiko mielivaltainen ohjelma funktion, jolla on tällainen ominaisuus, on algoritmisesti ratkaisematon ongelma. On esimerkiksi mahdotonta kirjoittaa analysaattoria, joka voi määrittää mistä tahansa lähdekoodista, onko analysoitava ohjelma sellaisen algoritmin toteutus, joka laskee esimerkiksi kokonaisluvun neliöinnin.

Näin ollen staattisten analysaattoreiden toimivuudella on ylitsepääsemättömiä rajoituksia. Staattinen analysaattori ei koskaan pysty havaitsemaan kaikissa tapauksissa esimerkiksi "nollaosoittimen poikkeuksen" esiintymistä kielissä, jotka sallivat nollan arvon, tai kaikissa tapauksissa määrittämään " attribuuttia ei löydy" dynaamisesti kirjoitetuilla kielillä. Edistyksellisin staattinen analysaattori voi vain korostaa erikoistapauksia, joiden lukumäärä kaikkien mahdollisten lähdekoodisi ongelmien joukossa on liioittelematta pisara meressä.

Staattisella analyysillä ei ole tarkoitus löytää virheitä

Edellä olevasta seuraa johtopäätös: staattinen analyysi ei ole keino vähentää ohjelman vikojen määrää. Uskaltaisin sanoa: kun sitä sovelletaan projektiisi ensimmäistä kertaa, se löytää "mielenkiintoisia" paikkoja koodista, mutta todennäköisimmin se ei löydä vikoja, jotka vaikuttavat ohjelmasi laatuun.

Esimerkit analysaattoreiden automaattisesti löytämistä vioista ovat vaikuttavia, mutta emme saa unohtaa, että nämä esimerkit löydettiin skannaamalla suuri joukko suuria koodikantoja. Samalla periaatteella hakkerit, joilla on mahdollisuus kokeilla useita yksinkertaisia ​​salasanoja suurella määrällä tilejä, löytävät lopulta ne tilit, joilla on yksinkertainen salasana.

Tarkoittaako tämä, että staattista analyysiä ei pitäisi käyttää? Ei tietenkään! Ja täsmälleen samasta syystä, että jokainen uusi salasana kannattaa tarkistaa varmistaakseen, että se sisältyy "yksinkertaisten" salasanojen lopetusluetteloon.

Staattinen analyysi on enemmän kuin vikojen etsiminen

Itse asiassa analyysin avulla käytännössä ratkaistavat ongelmat ovat paljon laajempia. Loppujen lopuksi staattinen analyysi on yleensä mitä tahansa lähdekoodien tarkistamista, joka suoritetaan ennen niiden käynnistämistä. Tässä on joitain asioita, joita voit tehdä:

  • Koodaustyylin tarkistaminen sanan laajimmassa merkityksessä. Tämä sisältää sekä muotoilun tarkistamisen, tyhjien/ylimääräisten sulkeiden käytön etsimisen, kynnysarvojen asettamisen mittareille, kuten rivien lukumäärälle/menetelmän syklomaattiselle monimutkaiselle jne. - kaiken, mikä mahdollisesti haittaa koodin luettavuutta ja ylläpidettävyyttä. Javassa tällainen työkalu on Checkstyle, Pythonissa - flake8. Tämän luokan ohjelmia kutsutaan yleensä "linteriksi".
  • Ei vain suoritettavaa koodia voida analysoida. Resurssitiedostot, kuten JSON, YAML, XML, .properties, voidaan (ja pitäisikin!) tarkistaa automaattisesti niiden kelpoisuuden osalta. Loppujen lopuksi on parempi selvittää, että JSON-rakenne on rikki joidenkin parittomien lainausten vuoksi automaattisen Pull Request -vahvistuksen varhaisessa vaiheessa kuin testin suorittamisen tai ajon aikana? Käytettävissä on sopivat työkalut: mm. YAMLlint, JSONLint.
  • Kääntäminen (tai jäsentäminen dynaamisille ohjelmointikielille) on myös eräänlainen staattinen analyysi. Yleensä kääntäjät pystyvät tuottamaan varoituksia, jotka osoittavat lähdekoodin laatuongelmia, eikä niitä pidä jättää huomiotta.
  • Joskus kääntäminen on muutakin kuin vain suoritettavan koodin kääntämistä. Esimerkiksi, jos sinulla on dokumentaatio muodossa AsciiDoctor, sitten kun se muutetaan HTML/PDF:ksi AsciiDoctor-käsittelijä (Maven-laajennus) voi antaa varoituksia esimerkiksi rikkinäisistä sisäisistä linkeistä. Ja tämä on hyvä syy olla hyväksymättä vetopyyntöä dokumentaatiomuutoksineen.
  • Oikoluku on myös eräänlainen staattinen analyysi. Apuohjelma loitsu osaa tarkistaa oikeinkirjoituksen paitsi dokumentaation, myös ohjelmien lähdekoodien (kommentit ja literaalit) eri ohjelmointikielillä, mukaan lukien C/C++, Java ja Python. Myös käyttöliittymässä tai dokumentaatiossa oleva kirjoitusvirhe on vika!
  • Konfigurointitestit (mitä ne ovat - katso. tämä и tämä raportit), vaikka ne suoritetaan yksikkötestin ajon aikana, kuten pytest, ovat itse asiassa myös eräänlainen staattinen analyysi, koska ne eivät suorita lähdekoodeja suorituksensa aikana.

Kuten näet, virheiden etsiminen tässä luettelossa on vähiten tärkeä rooli, ja kaikki muu on saatavilla käyttämällä ilmaisia ​​avoimen lähdekoodin työkaluja.

Mitä näistä staattisen analyysin tyypeistä sinun tulisi käyttää projektissasi? Tietysti mitä enemmän sen parempi! Tärkeintä on toteuttaa se oikein, josta keskustellaan edelleen.

Toimitusputki monivaiheisena suodattimena ja staattinen analyysi sen ensimmäisenä vaiheena

Jatkuvan integroinnin klassinen metafora on putki, jonka läpi muutokset kulkevat lähdekoodin muutoksista toimitukseen tuotantoon. Tämän liukuhihnan standardi vaihejärjestys näyttää tältä:

  1. staattinen analyysi
  2. kokoelma
  3. yksikkötestit
  4. integraatiotestejä
  5. UI testit
  6. manuaalinen tarkistus

Liukulinjan N:ssä vaiheessa hylättyjä muutoksia ei siirretä vaiheeseen N+1.

Miksi juuri näin eikä toisin? Putkilinjan testausosassa testaajat tunnistavat tunnetun testauspyramidin.

Ota staattinen analyysi käyttöön prosessissa sen sijaan, että käytät sitä virheiden etsimiseen
Testipyramidi. Lähde: artikkeli Martin Fowler.

Tämän pyramidin alaosassa on testejä, jotka on helpompi kirjoittaa, nopeampi suorittaa ja joilla ei ole taipumusta epäonnistua. Siksi niitä pitäisi olla enemmän, niiden tulisi kattaa enemmän koodia ja ne on suoritettava ensin. Pyramidin huipulla asia on päinvastoin, joten integraatio- ja käyttöliittymätestien määrä tulisi vähentää välttämättömään minimiin. Tämän ketjun henkilö on kallein, hitain ja epäluotettavin resurssi, joten hän on aivan lopussa ja suorittaa työn vain, jos edellisissä vaiheissa ei havaittu vikoja. Samoja periaatteita käytetään kuitenkin putkilinjan rakentamiseen osissa, jotka eivät liity suoraan testaukseen!

Haluaisin tarjota analogian monivaiheisen vedensuodatusjärjestelmän muodossa. Likainen vesi (muutoksia viallisilla) syötetään tuloon, ulostulossa on saatava puhdasta vettä, josta kaikki ei-toivotut epäpuhtaudet on eliminoitu.

Ota staattinen analyysi käyttöön prosessissa sen sijaan, että käytät sitä virheiden etsimiseen
Monivaiheinen suodatin. Lähde: Wikimedia Commons

Kuten tiedät, puhdistussuodattimet on suunniteltu siten, että jokainen seuraava kaskadi voi suodattaa pois yhä hienomman osan epäpuhtauksista. Samaan aikaan karkeammilla puhdistuskaskadeilla on suurempi suorituskyky ja alhaisemmat kustannukset. Analogiamme mukaan tämä tarkoittaa, että tulolaatuportit ovat nopeampia, vaativat vähemmän vaivaa käynnistääkseen ja ovat itse vaatimattomampia toiminnassa - ja tässä järjestyksessä ne rakennetaan. Staattisen analyysin rooli, joka, kuten nyt ymmärrämme, pystyy karsimaan pois vain karkeimmat viat, on "muta"-ruudukon rooli suodatinkaskadin alussa.

Staattinen analyysi ei sinänsä paranna lopputuotteen laatua, kuten ei "mutasuodatin" tee vedestä juomakelpoista. Ja kuitenkin, yhdessä putkilinjan muiden osien kanssa, sen merkitys on ilmeinen. Vaikka monivaiheisessa suodattimessa lähtöasteet pystyvät potentiaalisesti kaappaamaan kaiken, mitä tuloasteet tekevät, on selvää, mitä seurauksia on, jos yritetään tyytyä pelkillä hienopuhdistusasteikoilla, ilman syöttöasteita.

"Mutaloukun" tarkoituksena on vapauttaa myöhemmät kaskadit tarttumasta erittäin vakaviin vioihin. Esimerkiksi väärin muotoillun koodin ja vakiintuneiden koodausstandardien rikkomukset (kuten ylimääräiset sulut tai liian syvälle sisäkkäiset haarat) eivät saa häiritä koodin tarkistavaa henkilöä. Virheet, kuten NPE:t, tulisi saada kiinni yksikkötesteillä, mutta jos analysaattori jo ennen testiä ilmoittaa meille, että vian väistämättä tapahtuu, se nopeuttaa merkittävästi sen korjaamista.

Uskon, että nyt on selvää, miksi staattinen analyysi ei paranna tuotteen laatua, jos sitä käytetään satunnaisesti, ja sitä tulisi käyttää jatkuvasti suodattamaan muutoksia, joissa on suuria vikoja. Kysymys siitä, parantaako staattisen analysaattorin käyttö tuotteesi laatua, vastaa suunnilleen kysymystä: "Parantuuko likaisesta lammikosta otetun veden juomalaatu, jos se johdetaan siivilän läpi?"

Toteutus vanhaksi projektiksi

Tärkeä käytännön kysymys: miten staattinen analyysi voidaan ottaa osaksi jatkuvaa integraatioprosessia "laatuporttina"? Automaattisten testien tapauksessa kaikki on selvää: testejä on sarja, minkä tahansa epäonnistuminen on riittävä syy uskoa, että kokoonpano ei läpäissyt laatuporttia. Yritys asentaa portti samalla tavalla staattisen analyysin tulosten perusteella epäonnistuu: vanhassa koodissa on liikaa analyysivaroituksia, et halua jättää niitä kokonaan huomioimatta, mutta tuotteen toimitusta on myös mahdotonta lopettaa. vain siksi, että se sisältää analysaattorin varoituksia.

Kun analysaattoria käytetään ensimmäistä kertaa, se tuottaa valtavan määrän varoituksia mistä tahansa projektista, joista suurin osa ei liity tuotteen moitteettomaan toimintaan. On mahdotonta korjata kaikkia näitä kommentteja kerralla, ja monet eivät ole tarpeellisia. Loppujen lopuksi tiedämme, että tuotteemme kokonaisuutena toimii, jopa ennen staattisen analyysin käyttöönottoa!

Tämän seurauksena monet rajoittuvat satunnaiseen staattisen analyysin käyttöön tai käyttävät sitä vain informaatiotilassa, kun analysaattoriraportti yksinkertaisesti annetaan kokoonpanon aikana. Tämä vastaa minkään analyysin puuttumista, koska jos meillä on jo monia varoituksia, toisen (riippumatta siitä kuinka vakavasta) esiintyminen koodia vaihdettaessa jää huomaamatta.

Seuraavat menetelmät laadukkaiden porttien käyttöönottamiseksi tunnetaan:

  • Varoitusten kokonaismäärän rajan asettaminen tai varoitusten lukumäärä jaettuna koodirivien määrällä. Tämä toimii huonosti, koska tällainen portti päästää vapaasti läpi uusia vikoja sisältäviä muutoksia, kunhan niiden rajaa ei ylitetä.
  • Korjataan tietyllä hetkellä kaikki koodin vanhat varoitukset huomiotta jätetyiksi ja kieltäytyvät rakentamasta uusia varoituksia. Tämän toiminnon tarjoavat PVS-studio ja jotkut verkkoresurssit, kuten Codacy. Minulla ei ollut mahdollisuutta työskennellä PVS-studiossa, koska kokemukseni Codacysta heidän suurin ongelmansa on, että sen määrittäminen mikä on "vanha" ja mikä "uusi" virhe on melko monimutkainen algoritmi, joka ei aina toimi. oikein, varsinkin jos tiedostoja on muutettu tai nimetty uudelleen. Kokemukseni mukaan Codacy saattoi jättää huomioimatta vetopyynnön uudet varoitukset, mutta ei samalla välittänyt vetopyyntöä varoitusten vuoksi, jotka eivät liittyneet tietyn PR:n koodin muutoksiin.
  • Mielestäni tehokkain ratkaisu on kirjassa kuvattu Jatkuva Toimitus "räikkämenetelmä". Perusajatuksena on, että staattisen analyysin varoitusten määrä on jokaisen julkaisun ominaisuus ja sallitaan vain muutokset, jotka eivät lisää varoitusten kokonaismäärää.

Räikkä

Se toimii näin:

  1. Alkuvaiheessa metatietoihin kirjataan analysaattoreiden löytämän koodin varoitusmäärän julkaisu. Joten, kun rakennat alkupään, arkiston hallinta ei kirjoita vain "julkaisu 7.0.2", vaan "julkaisu 7.0.2, joka sisältää 100500 XNUMX tarkistustyylivaroitusta". Jos käytät kehittynyttä arkistonhallintaohjelmaa (kuten Artifactory), tällaisten julkaisusi metatietojen tallentaminen on helppoa.
  2. Nyt jokainen vetopyyntö, kun se on rakennettu, vertaa tuloksena olevien varoitusten määrää nykyisessä julkaisussa saatavilla olevien varoitusten määrään. Jos PR johtaa tämän luvun kasvuun, koodi ei läpäise staattisen analyysin laatuporttia. Jos varoitusten määrä vähenee tai ei muutu, se menee ohi.
  3. Seuraavassa julkaisussa uudelleen laskettu varoitusten määrä kirjataan uudelleen julkaisun metatietoihin.

Joten pikkuhiljaa, mutta tasaisesti (kuten räikkä toimii), varoitusten määrä on yleensä nolla. Tietysti järjestelmää voidaan pettää ottamalla käyttöön uusi varoitus, mutta korjaamalla jonkun muun varoitus. Tämä on normaalia, koska pitkällä matkalla se antaa tuloksia: varoitukset korjataan pääsääntöisesti ei yksittäin, vaan tietyntyyppisessä ryhmässä kerralla, ja kaikki helposti poistettavat varoitukset poistetaan melko nopeasti.

Tämä kaavio näyttää Checkstyle-varoitusten kokonaismäärän kuuden kuukauden aikana, kun tällainen "räikkä" on käytössä yksi OpenSource-projekteistamme. Varoitusten määrä on vähentynyt suuruusluokkaa, ja tämä tapahtui luonnollisesti tuotekehityksen rinnalla!

Ota staattinen analyysi käyttöön prosessissa sen sijaan, että käytät sitä virheiden etsimiseen

Käytän tämän menetelmän muokattua versiota, joka laskee varoitukset erikseen projektimoduulin ja analyysityökalun mukaan, jolloin tuloksena on YAML-tiedosto koontitietojen kanssa, joka näyttää suunnilleen tältä:

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

Kaikissa kehittyneissä CI-järjestelmissä räikkä voidaan toteuttaa kaikille staattisille analyysityökaluille ilman lisäosien ja kolmannen osapuolen työkalujen käyttöä. Jokainen analysaattori tuottaa oman raportin yksinkertaisessa teksti- tai XML-muodossa, joka on helppo analysoida. Jää vain kirjoittaa tarvittava logiikka CI-skriptiin. Voit nähdä, kuinka tämä toteutetaan avoimen lähdekoodin projekteissamme, jotka perustuvat Jenkinsiin ja Artifactoryyn täällä tai täällä. Molemmat esimerkit riippuvat kirjastosta ratchetlib: menetelmä countWarnings() laskee xml-tunnisteet Checkstylen ja Spotbugin luomissa tiedostoissa tavalliseen tapaan, ja compareWarningMaps() käyttää samaa räikkää ja antaa virheen, kun varoitusten määrä missä tahansa luokassa kasvaa.

Mielenkiintoinen "räikkä"-toteutus on mahdollinen kommenttien oikeinkirjoituksen, tekstin literaalien ja dokumentaation analysointiin aspellilla. Kuten tiedät, oikeinkirjoitusta tarkistettaessa kaikki tavallisessa sanakirjassa tuntemattomat sanat eivät ole virheellisiä, vaan ne voidaan lisätä käyttäjän sanakirjaan. Jos teet mukautetun sanakirjan osaksi projektin lähdekoodia, oikeinkirjoituksen laatuportti voidaan muotoilla näin: ajaa aspell tavallisen ja mukautetun sanakirjan kanssa ei pitäisi ei löydä kirjoitusvirheitä.

Analysaattoriversion korjaamisen tärkeydestä

Yhteenvetona totean, että riippumatta siitä, kuinka otat analyysin käyttöön toimitusputkessasi, analysaattorin versio on korjattava. Jos annat analysaattorin päivittää spontaanisti, seuraavaa vetopyyntöä koottaessa voi "ponnahtaa" uusia vikoja, jotka eivät liity koodin muutoksiin, vaan liittyvät siihen, että uusi analysaattori pystyy yksinkertaisesti löytämään lisää vikoja - ja tämä katkaisee vetopyyntöjen hyväksymisprosessin. Analysaattorin päivittämisen tulee olla tietoista toimintaa. Jokaisen kokoonpanokomponentin version jäykkä kiinnitys on kuitenkin yleensä välttämätön vaatimus ja erillisen keskustelun aihe.

Tulokset

  • Staattinen analyysi ei löydä sinulle virheitä eikä paranna tuotteesi laatua yhden sovelluksen seurauksena. Positiivinen vaikutus laatuun voidaan saavuttaa vain jatkuvalla käytöllä toimitusprosessin aikana.
  • Virheiden etsiminen ei ole ollenkaan analyysin päätehtävä, vaan suurin osa hyödyllisistä toiminnoista on saatavilla avoimen lähdekoodin työkaluissa.
  • Toteuta laatuportit staattisen analyysin tulosten perusteella toimitusputken aivan ensimmäisessä vaiheessa käyttämällä "räikkää" vanhalle koodille.

viittaukset

  1. Jatkuva Toimitus
  2. A. Kudrjavtsev: Ohjelmaanalyysi: kuinka ymmärtää, että olet hyvä ohjelmoija raportti erilaisista koodianalyysimenetelmistä (ei vain staattisista!)

Lähde: will.com

Lisää kommentti