Efektivigu statikan analizon en la procezon, anstataŭ uzi ĝin por trovi cimojn

Mi estis instigita skribi ĉi tiun artikolon pro la granda kvanto da materialoj pri statika analizo, kiuj ĉiam pli atentas mian atenton. Unue, ĉi tio PVS-studia blogo, kiu aktive reklamas sin sur Habré kun la helpo de recenzoj de eraroj trovitaj de ilia ilo en malfermkodaj projektoj. Lastatempe PVS-studio efektivigita Java subteno, kaj, kompreneble, la programistoj de IntelliJ IDEA, kies enkonstruita analizilo verŝajne estas la plej altnivela por Java hodiaŭ, ne povis resti for.

Legante tiajn recenzojn, vi havas la senton, ke ni parolas pri magia eliksiro: premu la butonon, kaj jen ĝi estas - listo de difektoj antaŭ viaj okuloj. Ŝajnas, ke dum analiziloj pliboniĝos, pli kaj pli da cimoj aŭtomate estos trovitaj, kaj la produktoj skanitaj de ĉi tiuj robotoj fariĝos pli kaj pli bonaj, sen ajna peno de nia flanko.

Sed ne ekzistas magiaj eliksiroj. Mi ŝatus paroli pri tio, pri kio kutime ne estas parolata en afiŝoj kiel "jen la aferoj, kiujn nia roboto povas trovi": kion analiziloj ne povas fari, kio estas ilia reala rolo kaj loko en la programara liveroprocezo, kaj kiel efektivigi ilin ĝuste. .

Efektivigu statikan analizon en la procezon, anstataŭ uzi ĝin por trovi cimojn
Kliko (fonto: Vikipedio).

Kion senmovaj analiziloj neniam povas fari

Kio estas fontkoda analizo, el praktika vidpunkto? Ni provizas iom da fontkodo kiel enigo, kaj kiel eligo, en mallonga tempo (multe pli mallonga ol ruli testoj) ni akiras iujn informojn pri nia sistemo. La fundamenta kaj matematike nesuperebla limigo estas ke ni povas akiri nur sufiĉe mallarĝan klason de informoj tiamaniere.

La plej fama ekzemplo de problemo kiu ne povas esti solvita per senmova analizo estas problemo de ĉesigo: Ĉi tio estas teoremo, kiu pruvas, ke estas neeble evoluigi ĝeneralan algoritmon, kiu povas determini el la fontkodo de programo ĉu ĝi buklos aŭ finiĝos en finia tempo. Etendo de ĉi tiu teoremo estas La teoremo de Rice, kiu deklaras ke por iu ne-triviala posedaĵo de komputeblaj funkcioj, determini ĉu arbitra programo taksas funkcion kun tia posedaĵo estas algoritme nesolvebla problemo. Ekzemple, estas maleble skribi analizilon kiu povas determini de iu fontkodo ĉu la programo estanta analizita estas efektivigo de algoritmo kiu kalkulas, ekzemple, la kvadraton de entjero.

Tiel, la funkcieco de senmovaj analiziloj havas nesupereblajn limigojn. Senmova analizilo neniam povos detekti en ĉiuj kazoj tiajn aferojn kiel, ekzemple, la aperon de "nula montrilo escepto" en lingvoj kiuj permesas la valoron de nulo, aŭ en ĉiuj kazoj determini la aperon de " atributo ne trovita" en dinamike tajpitaj lingvoj. Ĉio, kion povas fari la plej altnivela statika analizilo, estas reliefigi specialajn kazojn, kies nombro, inter ĉiuj eblaj problemoj kun via fontkodo, estas, sen troigo, guto en la oceano.

Statika analizo ne temas pri trovi cimojn

El la supre sekvas la konkludo: statika analizo ne estas rimedo por redukti la nombron da difektoj en programo. Mi kuraĝus diri: kiam aplikite al via projekto por la unua fojo, ĝi trovos "interesajn" lokojn en la kodo, sed, plej verŝajne, ĝi ne trovos iujn difektojn, kiuj influas la kvaliton de via programo.

La ekzemploj de difektoj aŭtomate trovitaj de analiziloj estas imponaj, sed ni ne forgesu, ke ĉi tiuj ekzemploj estis trovitaj per skanado de granda aro da grandaj kodbazoj. Laŭ la sama principo, piratoj, kiuj havas la ŝancon provi plurajn simplajn pasvortojn sur granda nombro da kontoj, fine trovas tiujn kontojn, kiuj havas simplan pasvorton.

Ĉu tio signifas, ke statika analizo ne estu uzata? Kompreneble ne! Kaj ĝuste pro la sama kialo, ke indas kontroli ĉiun novan pasvorton por certigi, ke ĝi estas inkluzivita en la haltlisto de "simplaj" pasvortoj.

Statika analizo estas pli ol trovi cimojn

Fakte, la problemoj praktike solvitaj per analizo estas multe pli larĝaj. Post ĉio, ĝenerale, statika analizo estas ajna konfirmo de fontkodoj efektivigita antaŭ ol ili estas lanĉitaj. Jen kelkaj aferoj, kiujn vi povas fari:

  • Kontrolante kodigan stilon en la plej larĝa signifo de la vorto. Ĉi tio inkluzivas ambaŭ kontroli formatadon, serĉi la uzon de malplenaj/kromaj krampoj, fiksi sojlojn pri metrikoj kiel nombro da linioj/ciklomata komplekseco de metodo, ktp. - ĉio, kio eble malhelpas la legeblecon kaj konserveblecon de la kodo. En Java, tia ilo estas Checkstyle, en Python - flake8. Programoj de ĉi tiu klaso estas kutime nomitaj "linteroj".
  • Ne nur plenumebla kodo povas esti analizita. Rimeddosieroj kiel JSON, YAML, XML, .properties povas (kaj devus!) esti aŭtomate kontrolitaj pri valideco. Post ĉio, estas pli bone ekscii, ke la JSON-strukturo estas rompita pro iuj neparigitaj citaĵoj en frua etapo de aŭtomata Pull Request-konfirmo ol dum testa ekzekuto aŭ rultempo? Taŭgaj iloj haveblas: ekz. YAMLint, JSONLint.
  • Kompilo (aŭ analizado por dinamikaj programlingvoj) ankaŭ estas speco de senmova analizo. Ĝenerale, kompililoj kapablas produkti avertojn kiuj indikas problemojn kun fontkodkvalito kaj ne devus esti ignoritaj.
  • Foje kompilo estas pli ol nur kompili plenumeblan kodon. Ekzemple, se vi havas dokumentadon en la formato AsciiDoktoro, tiam en la momento de igi ĝin HTML/PDF la prizorganto AsciiDoctor (Kromaĵo Maven) povas eligi avertojn, ekzemple, pri rompitaj internaj ligiloj. Kaj ĉi tio estas bona kialo por ne akcepti la Pull-Peton kun dokumentaj ŝanĝoj.
  • Literuma kontrolo estas ankaŭ speco de senmova analizo. Utilo aspell kapablas kontroli literumadon ne nur en dokumentaro, sed ankaŭ en programkodoj (komentoj kaj literoj) en diversaj programlingvoj, inkluzive de C/C++, Java kaj Python. Literuma eraro en la uzantinterfaco aŭ dokumentado ankaŭ estas difekto!
  • Agordaj testoj (pri kio ili estas - vidu. ĉi tio и ĉi tio raportoj), kvankam efektivigitaj en unutesta rultempo kiel ekzemple pytest, estas fakte ankaŭ speco de senmova analizo, ĉar ili ne efektivigas fontkodojn dum sia ekzekuto.

Kiel vi povas vidi, serĉi cimojn en ĉi tiu listo ludas la malplej gravan rolon, kaj ĉio alia estas disponebla per senpagaj malfermfontaj iloj.

Kiun el ĉi tiuj specoj de statika analizo vi uzu en via projekto? Kompreneble, ju pli des pli bone! La ĉefa afero estas efektivigi ĝin ĝuste, kio estos diskutita plu.

Livera dukto kiel plurŝtupa filtrilo kaj statika analizo kiel ĝia unua etapo

La klasika metaforo por kontinua integriĝo estas dukto tra kiu fluas ŝanĝoj, de fontkodŝanĝoj ĝis livero ĝis produktado. La norma sekvenco de stadioj en ĉi tiu dukto aspektas jene:

  1. statika analizo
  2. kompilo
  3. unuo testoj
  4. integrigaj testoj
  5. UI-testoj
  6. mana kontrolo

Ŝanĝoj malaprobitaj en la N-a stadio de la dukto ne estas transdonitaj al stadio N+1.

Kial ĝuste tiel kaj ne alie? En la testa parto de la dukto, testantoj rekonos la konatan testan piramidon.

Efektivigu statikan analizon en la procezon, anstataŭ uzi ĝin por trovi cimojn
Testa piramido. Fonto: artikolo Martin Fowler.

Ĉe la fundo de ĉi tiu piramido estas provoj, kiuj estas pli facile verkeblaj, pli rapide efektivigeblaj kaj ne emas malsukcesi. Tial, devus esti pli da ili, ili devus kovri pli da kodo kaj esti ekzekutitaj unue. Ĉe la supro de la piramido, la malo estas vera, do la nombro da integriĝo kaj UI-testoj devus esti reduktita al la necesa minimumo. La persono en ĉi tiu ĉeno estas la plej multekosta, malrapida kaj nefidinda rimedo, do li estas ĉe la fino kaj nur plenumas la laboron se la antaŭaj etapoj ne trovis neniun difekton. Tamen, la samaj principoj estas uzataj por konstrui dukton en partoj ne rekte rilataj al testado!

Mi ŝatus proponi analogion en formo de plurŝtupa akvofiltradsistemo. Malpura akvo (ŝanĝiĝas kun difektoj) estas liverita al la enigaĵo; ĉe la eligo ni devas ricevi puran akvon, en kiu ĉiuj nedezirataj poluaĵoj estis eliminitaj.

Efektivigu statikan analizon en la procezon, anstataŭ uzi ĝin por trovi cimojn
Plurŝtupa filtrilo. Fonto: Wikimedia Komunejo

Kiel vi scias, purigaj filtriloj estas dizajnitaj tiel ke ĉiu posta kaskado povas elfiltri ĉiam pli fajnan frakcion de poluaĵoj. En la sama tempo, pli krudaj purigaj kaskadoj havas pli altan trairon kaj pli malaltan koston. Laŭ nia analogio, ĉi tio signifas, ke eniga kvalitaj pordegoj estas pli rapidaj, postulas malpli da peno por komenci, kaj estas mem pli senpretendaj en funkciado - kaj ĉi tiu estas la sinsekvo en kiu ili estas konstruitaj. La rolo de senmova analizo, kiu, kiel ni nun komprenas, kapablas forigi nur la plej krudajn difektojn, estas la rolo de la "koto-" krado ĉe la komenco mem de la filtrila kaskado.

Senmova analizo per si mem ne plibonigas la kvaliton de la fina produkto, same kiel "kota filtrilo" ne igas akvon trinkebla. Kaj tamen, kune kun aliaj elementoj de la dukto, ĝia graveco estas evidenta. Kvankam en plurstadia filtrilo la produktaĵstadioj eble estas kapablaj je kaptado de ĉio kion la enirstadioj faras, estas klare kiaj sekvoj rezultos el provo fariĝi kun fajn-purigaj stadioj sole, sen enirstadioj.

La celo de la "kotokaptilo" estas malpezigi postajn kaskadojn de kaptado de tre krudaj difektoj. Ekzemple, minimume, la persono faranta la kodrevizion ne devus esti distrita per malĝuste formatita kodo kaj malobservoj de establitaj kodigaj normoj (kiel kromaj krampoj aŭ tro profunde nestitaj branĉoj). Cimoj kiel NPE-oj devus esti kaptitaj per unutestoj, sed se eĉ antaŭ la testo la analizilo indikas al ni, ke cimo nepre okazos, tio signife akcelos ĝian riparadon.

Mi kredas, ke nun estas klare kial statika analizo ne plibonigas la kvaliton de la produkto se uzata foje, kaj devus esti uzata konstante por filtri ŝanĝojn kun krudaj difektoj. La demando ĉu uzado de senmova analizilo plibonigos la kvaliton de via produkto estas proksimume ekvivalenta al demandi: "Ĉu akvo prenita el malpura lageto estos plibonigita en trinkkvalito, se ĝi estas trapasita tra koligilo?"

Efektivigo en heredan projekton

Grava praktika demando: kiel efektivigi statikan analizon en la kontinuan integrigan procezon kiel "kvalitan pordegon"? En la kazo de aŭtomataj provoj, ĉio estas evidenta: ekzistas aro da provoj, la malsukceso de iu el ili estas sufiĉa kialo por kredi, ke la asembleo ne pasis la kvalitan pordegon. Provo instali pordegon sammaniere surbaze de la rezultoj de statika analizo malsukcesas: estas tro da analizaj avertoj en la hereda kodo, oni ne volas tute ignori ilin, sed ankaŭ neeblas ĉesi sendi produkton. nur ĉar ĝi enhavas analizilajn avertojn.

Kiam oni uzas la unuan fojon, la analizilo produktas grandegan nombron da avertoj pri iu ajn projekto, la granda plimulto de kiuj ne rilatas al la ĝusta funkciado de la produkto. Estas neeble korekti ĉiujn ĉi tiujn komentojn samtempe, kaj multaj ne estas necesaj. Ja ni scias, ke nia produkto entute funkcias, eĉ antaŭ ol enkonduki statikan analizon!

Kiel rezulto, multaj estas limigitaj al foja uzo de senmova analizo, aŭ uzas ĝin nur en informreĝimo, kiam analizilraporto estas simple eldonita dum kunigo. Ĉi tio egalas al la foresto de ajna analizo, ĉar se ni jam havas multajn avertojn, tiam la apero de alia (kiel ajn grava) kiam oni ŝanĝas la kodon pasas nerimarkita.

La sekvaj metodoj por enkonduki kvalitajn pordegojn estas konataj:

  • Fiksi limon al la totala nombro da avertoj aŭ la nombro da avertoj dividita per la nombro da linioj de kodo. Ĉi tio funkcias malbone, ĉar tia pordego libere permesas trapasi ŝanĝojn kun novaj difektoj, kondiĉe ke ilia limo ne estas superita.
  • Ripari, en certa momento, ĉiujn malnovajn avertojn en la kodo kiel ignoritaj, kaj rifuzi konstrui kiam novaj avertoj okazas. Ĉi tiu funkcio estas provizita de PVS-studio kaj iuj interretaj rimedoj, ekzemple, Codacy. Mi ne havis la ŝancon labori en PVS-studio, pro mia sperto kun Codacy, ilia ĉefa problemo estas, ke determini kio estas "malnova" kaj kio estas "nova" eraro estas sufiĉe kompleksa algoritmo, kiu ne ĉiam funkcias. ĝuste, precipe se dosieroj estas peze modifitaj aŭ renomitaj. Laŭ mia sperto, Codacy povus ignori novajn avertojn en tira peto, samtempe ne pasante tirpeton pro avertoj, kiuj ne rilatis al ŝanĝoj en la kodo de donita PR.
  • Laŭ mi, la plej efika solvo estas tiu priskribita en la libro Kontinua Transdono "krata metodo". La baza ideo estas, ke la nombro da senmovaj analizaj avertoj estas propraĵo de ĉiu eldono, kaj nur ŝanĝoj estas permesitaj, kiuj ne pliigas la totalan nombron de avertoj.

Kliko

Ĝi funkcias jene:

  1. En la komenca etapo, rekordo estas farita en la metadatenoj pri la liberigo de la nombro da avertoj en la kodo trovita de la analiziloj. Do, kiam vi konstruas kontraŭflue, via deponejo skribas ne nur "eldono 7.0.2", sed "eldono 7.0.2 enhavanta 100500 kontrolstilaj avertoj." Se vi uzas altnivelan administranton de deponejo (kiel Artifactory), stoki tiajn metadatenojn pri via eldono estas facila.
  2. Nun ĉiu tira peto, kiam konstruita, komparas la nombron da rezultaj avertoj kun la nombro da avertoj disponeblaj en la nuna eldono. Se PR kondukas al pliigo de ĉi tiu nombro, tiam la kodo ne pasas la kvalitan pordegon por statika analizo. Se la nombro da avertoj malpliiĝas aŭ ne ŝanĝiĝas, tiam ĝi pasas.
  3. Ĉe la venonta eldono, la rekalkulita nombro da avertoj estos registrita denove en la eldonmetadatumoj.

Do iom post iom sed konstante (kiel kiam klako funkcias), la nombro da avertoj tendencos al nulo. Kompreneble oni povas trompi la sistemon enkondukante novan averton, sed korektante tiun de aliulo. Ĉi tio estas normala, ĉar sur longa distanco ĝi donas rezultojn: avertoj estas korektitaj, kutime, ne individue, sed en grupo de certa tipo samtempe, kaj ĉiuj facile forpreneblaj avertoj estas forigitaj sufiĉe rapide.

Ĉi tiu grafiko montras la totalan nombron de Checkstyle-avertoj dum ses monatoj da funkciado de tia "kliko" sur unu el niaj OpenSource-projektoj. La nombro da avertoj malpliiĝis je ordo de grandeco, kaj tio okazis nature, paralele al produkta disvolviĝo!

Efektivigu statikan analizon en la procezon, anstataŭ uzi ĝin por trovi cimojn

Mi uzas modifitan version de ĉi tiu metodo, aparte kalkulante avertojn per projektmodulo kaj analiza ilo, rezultigante YAML-dosieron kun konstrumetadatumoj, kiu aspektas kiel ĉi tio:

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

En iu ajn altnivela CI-sistemo, ratchet povas esti efektivigita por iuj statikaj analizaj iloj sen fidi al kromaĵoj kaj triaj iloj. Ĉiu analizilo produktas sian propran raporton en simpla teksto aŭ XML-formato, kiu estas facile analizebla. Restas nur skribi la necesan logikon en la CI-skripto. Vi povas vidi kiel ĉi tio estas efektivigita en niaj malfermkodaj projektoj bazitaj sur Jenkins kaj Artifactory tietie. Ambaŭ ekzemploj dependas de la biblioteko ratchetlib: metodo countWarnings() kalkulas xml-etikedojn en dosieroj generitaj de Checkstyle kaj Spotbugs laŭ la kutima maniero, kaj compareWarningMaps() efektivigas la saman klakon, ĵetante eraron kiam la nombro da avertoj en iu ajn el la kategorioj pliiĝas.

Interesa efektivigo de la "kliko" eblas por analizi la literumon de komentoj, tekstliteraĵoj kaj dokumentado uzante aspell. Kiel vi scias, dum kontrolado de literumo, ne ĉiuj vortoj nekonataj al la norma vortaro estas malĝustaj; ili povas esti aldonitaj al la uzantvortaro. Se vi faras propran vortaron parto de la fontkodo de la projekto, tiam la ortografikvalita pordego povas esti formulita jene: ruli aspell kun norma kaj kutima vortaro. ne devus trovi neniujn literumajn erarojn.

Pri la graveco ripari la analizilon-version

Konklude, la punkto por noti estas, ke kiom ajn vi efektivigas analizon en vian liveran dukton, la versio de la analizilo devas esti fiksita. Se vi permesas al la analizilo spontane ĝisdatigi, tiam, kiam oni kunmetas la sekvan tiran peton, novaj difektoj povas "aperos", kiuj ne rilatas al kodŝanĝoj, sed rilatas al la fakto, ke la nova analizilo simple kapablas trovi pliajn difektojn - kaj ĉi tio rompos vian procezon akcepti tirpetojn. Altgradigi analizilon devus esti konscia ago. Tamen, rigida fiksado de la versio de ĉiu kunigkomponento estas ĝenerale necesa postulo kaj temo por aparta diskuto.

trovoj

  • Statika analizo ne trovos cimojn por vi kaj ne plibonigos la kvaliton de via produkto kiel rezulto de ununura aplikaĵo. Pozitiva efiko al kvalito nur povas esti atingita per ĝia konstanta uzo dum la livera procezo.
  • Trovi cimojn tute ne estas la ĉefa analizo; la granda plimulto de utilaj funkcioj estas disponeblaj en malfermfontaj iloj.
  • Efektivigu kvalitajn pordegojn bazitajn sur la rezultoj de senmova analizo ĉe la unua etapo de la livera dukto, uzante "klikon" por hereda kodo.

referencoj

  1. Kontinua Transdono
  2. A. Kudryavtsev: Analizo de programoj: kiel kompreni, ke vi estas bona programisto raportu pri malsamaj metodoj de kodanalizo (ne nur senmova!)

fonto: www.habr.com

Aldoni komenton