{"id":32848,"date":"2019-10-31T21:49:16","date_gmt":"2019-10-31T18:49:16","guid":{"rendered":"https:\/\/prohoster.info\/blog\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi\/"},"modified":"2019-10-31T21:49:16","modified_gmt":"2019-10-31T18:49:16","slug":"vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","status":"publish","type":"post","link":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","title":{"rendered":"Integr\u00e9r statisk analyse i processen, i stedet for at bruge den til at finde fejl.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>At skrive denne artikel blev jeg opmuntret af det store antal materialer om statisk analyse, som jeg oftere st\u00f8der p\u00e5. For det f\u00f8rste er det <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/\">bloggen PVS-studio<\/a><\/noindex>, som aktivt promoverer sig selv p\u00e5 Habr ved hj\u00e6lp af anmeldelser af fejl, som deres v\u00e6rkt\u00f8j har fundet i open source-projekter. For nylig implementerede PVS-studio <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/436496\/\">underst\u00f8ttelse af Java<\/a><\/noindex>, og selvf\u00f8lgelig kunne udviklerne af IntelliJ IDEA, hvis indbyggede analyserer i dag sandsynligvis er den mest avancerede for Java, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/JetBrains\/blog\/436278\/\">ikke forblive udenfor<\/a><\/noindex>. <\/p>\n<p>N\u00e5r man l\u00e6ser s\u00e5danne anmeldelser, f\u00e5r man indtryk af, at der er tale om en magisk elixir: tryk p\u00e5 knappen, og voila \u2014 listen over defekter dukker op foran en. Det virker som om, at efterh\u00e5nden som analysatorerne forbedres, vil fejl blive fundet i st\u00f8rre og st\u00f8rre omfang, og de produkter, der er scannet af disse robotter, vil blive bedre og bedre uden nogen anstrengelse fra vores side.<\/p>\n<p>Men der findes ikke nogen magiske elixirer. Jeg vil gerne tale om, hvad der normalt ikke n\u00e6vnes i indl\u00e6g som \u00abher er hvad vores robot kan finde\u00bb: hvad analysev\u00e6rkt\u00f8jer ikke kan, hvilken reel rolle de spiller, og hvordan man implementerer dem korrekt i softwareleveringsprocessen.<\/p>\n<p><img decoding=\"async\" alt=\"Integr\u00e9r statisk analyse i processen, i stedet for at bruge den til at finde fejl.\" src=\"\/wp-content\/uploads\/2019\/05\/2a0339f10edcaed3310676ab6e2f975a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Katalysator (kilde: <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A5%D1%80%D0%B0%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9_%D0%BC%D0%B5%D1%85%D0%B0%D0%BD%D0%B8%D0%B7%D0%BC#\/media\/File:Sperrklinke_Schema.svg\">wikipedia<\/a><\/noindex>).<\/i><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Hvad statiske analysatorer aldrig vil kunne g\u00f8re<\/h2>\n<p>\nHvad er, set fra et praktisk synspunkt, analysen af kildekoden? Vi indsender nogle kildefiler, og p\u00e5 kort tid (voldsomt hurtigere end at k\u00f8re tests) f\u00e5r vi nogle oplysninger om vores system. Det grundl\u00e6ggende og matematisk uoverkommelige begr\u00e6nsning er, at vi kun kan f\u00e5 en relativt smal klasse af oplysninger p\u00e5 denne m\u00e5de.<\/p>\n<p>Det mest ber\u00f8mte eksempel p\u00e5 et problem, der ikke kan l\u00f8ses ved hj\u00e6lp af statisk analyse \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Halting_problem\">stopproblemet<\/a><\/noindex>: det er en s\u00e6tning, der beviser, at det er umuligt at udvikle en generel algoritme, der kan bestemme p\u00e5 baggrund af kildekoden, om et program vil k\u00f8re i en uendelig l\u00f8kke eller afslutte p\u00e5 et begr\u00e6nset tidsrum. En udvidelse af denne s\u00e6tning er <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Rice%27s_theorem\">Rices s\u00e6tning<\/a><\/noindex>, der for ethvert ikke-trivielt egenskab ved beregnelige funktioner angiver, om et vilk\u00e5rligt program beregner en funktion med denne egenskab, er en algoritmisk uopsl\u00e5elig opgave. For eksempel er det umuligt at skrive en analyser, der for enhver kildekode kan bestemme, om det analyserede program er en implementering af en algoritme, der beregner for eksempel kvadratet af et helt tal.<\/p>\n<p>Dermed har funktionaliteten af statiske analysev\u00e6rkt\u00f8jer uoverkommelige begr\u00e6nsninger. En statisk analysator vil aldrig kunne bestemme s\u00e5danne ting i alle tilf\u00e6lde, som for eksempel forekomsten af \u201cnull pointer exception\u201d i sprog, der tillader null-v\u00e6rdier, eller i alle tilf\u00e6lde bestemme forekomsten af \u201cattribute not found\u201d i sprog med dynamisk typificering. Alt, hvad den mest avancerede statiske analysator kan g\u00f8re, er at fremh\u00e6ve s\u00e6rtilf\u00e6lde, antallet af hvilke blandt alle mulige problemer med din kildekode er, uden overdrivelse, en dr\u00e5be i havet.<\/p>\n<h2>Statisk analyse er ikke fejlfinding<\/h2>\n<p>\nAf det ovenst\u00e5ende f\u00f8lger konklusionen: statisk analyse er ikke et redskab til at reducere antallet af defekter i programmet. Jeg vover at p\u00e5st\u00e5, at n\u00e5r det f\u00f8rst anvendes p\u00e5 dit projekt, vil det finde 'interessante' steder i koden, men sandsynligvis ikke finde nogen defekter, der p\u00e5virker kvaliteten af dit programs drift.<\/p>\n<p>Eksempler p\u00e5 defekter, der automatisk er fundet af analyser, er imponerende, men man skal ikke glemme, at disse eksempler er fundet ved at scanne et stort s\u00e6t store kodebaser. P\u00e5 samme m\u00e5de som hackere, der har mulighed for at gennemg\u00e5 flere enkle adgangskoder p\u00e5 et stort antal konti, til sidst finder de konti, hvor der er en simpel adgangskode.<\/p>\n<p>Betyder det, at statisk analyse ikke skal anvendes? Naturligvis ikke! Og netop af den samme grund, som det er vigtigt at kontrollere hver ny adgangskode mod listen over 'simple' adgangskoder.<\/p>\n<h2>Statisk analyse er mere end fejlfinding<\/h2>\n<p>\nI virkeligheden er de praktisk l\u00f8selige opgaver, der kan analyseres, meget bredere. For statisk analyse er generelt enhver kontrol af kildekoden, der udf\u00f8res inden deres k\u00f8rsel. Her er nogle ting, man kan g\u00f8re:<\/p>\n<ul>\n<li> Kontrol af kodestil i ordets brede forstand. Dette inkluderer b\u00e5de kontrol af formatering samt s\u00f8gning efter brug af tomme\/un\u00f8dvendige parenteser, fasts\u00e6ttelse af t\u00e6rskelv\u00e6rdier for metrikker som antal linjer \/ cyklo-matisk kompleksitet af metoden osv. \u2014 alt, hvad der potentielt kan g\u00f8re koden vanskeligere at l\u00e6se og vedligeholde. I Java er et s\u00e5dant v\u00e6rkt\u00f8j Checkstyle, i Python er det flake8. Programmer af denne type kaldes normalt \"linters.\"<\/li>\n<li>Ikke kun eksekverbar kode kan analyseres. Resursefiler som JSON, YAML, XML, .properties kan (og b\u00f8r!) automatisk kontrolleres for gyldighed. Det er bedre at opdage, at strukturen i JSON er brudt p\u00e5 grund af uparrede citationstegn p\u00e5 et tidligt stadium af automatisk kontrol af Pull Request end ved testeksekvering eller runtime. De relevante v\u00e6rkt\u00f8jer findes: for eksempel, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/adrienverge\/yamllint\">YAMLlint<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zaach\/jsonlint\">JSONLint<\/a><\/noindex>.<\/li>\n<li> Kompilering (eller parsing for dynamiske programmeringssprog) er ogs\u00e5 en form for statisk analyse. Generelt er compilere i stand til at give advarsler, der signalerer problemer med kvaliteten af kildekoden, og disse b\u00f8r ikke ignoreres.<\/li>\n<li>Nogle gange er kompilering ikke kun kompilering af eksekverbar kode. For eksempel, hvis du har dokumentation i formatet <noindex><a rel=\"nofollow\" href=\"https:\/\/asciidoctor.org\/\">AsciiDoctor<\/a><\/noindex>, s\u00e5 kan ved transformationen til HTML\/PDF behandleren AsciiDoctor (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/asciidoctor\/asciidoctor-maven-plugin\">Maven plugin<\/a><\/noindex>) generere advarsler, fx om brudte interne links. Og dette er en v\u00e6gtig grund til ikke at acceptere en Pull Request med \u00e6ndringer i dokumentationen.<\/li>\n<li>Stavekontrol er ogs\u00e5 en form for statisk analyse. V\u00e6rkt\u00f8jet <noindex><a rel=\"nofollow\" href=\"http:\/\/aspell.net\/\">aspell<\/a><\/noindex> kan kontrollere stavem\u00e5den ikke kun i dokumentationen, men ogs\u00e5 i kildekode (kommentarer og litteraler) p\u00e5 forskellige programmeringssprog, herunder C\/C++, Java og Python. En stavefejl i brugergr\u00e6nsefladen eller i dokumentationen er ogs\u00e5 en defekt!<\/li>\n<li>Konfigurationstest (om hvad det er \u2014 se <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KaeEjsAjV6A&amp;index=30&amp;list=PLsVTVVvrKX9tuYyCtL8mASB6IOaa-kRCA&amp;t=0s\">denne<\/a><\/noindex> og <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=Tk_nmV-mWOA\">denne<\/a><\/noindex> foresl\u00e5r), selvom de udf\u00f8res i runtime-milj\u00f8et for modul\u00e6rtest som pytest, er de faktisk ogs\u00e5 en form for statisk analyse, da de ikke eksekverer kildekoden under deres udf\u00f8relse.<\/li>\n<\/ul>\n<p>\nSom vi kan se, spiller fejlfindingsprocessen den mindst vigtige rolle i denne liste, mens alt det andet er tilg\u00e6ngeligt ved hj\u00e6lp af gratis open source-v\u00e6rkt\u00f8jer.<\/p>\n<p>Hvilke typer statisk analyse skal anvendes i dit projekt? Selvf\u00f8lgelig alle, jo flere desto bedre! Det vigtigste er at implementere det korrekt, hvilket vi vil tale om senere.<\/p>\n<h2>Leveringspipeline som et flertrinsfilter og statisk analyse som dets f\u00f8rste kaskade<\/h2>\n<p>\nDen klassiske metafor for kontinuerlig integration er en pipeline, hvor \u00e6ndringer str\u00f8mmer fra \u00e6ndringen af kildekoden til levering til produktion. Standard r\u00e6kkef\u00f8lge af trin i denne pipeline ser s\u00e5ledes ud:<\/p>\n<ol>\n<li>statisk analyse<\/li>\n<li>kompilering<\/li>\n<li>modultests<\/li>\n<li>integrationstests<\/li>\n<li>UI-tests<\/li>\n<li>manuel kontrol<\/li>\n<\/ol>\n<p>\n\u00c6ndringer, der afvises p\u00e5 N-te trin af pipelinen, overf\u00f8res ikke til trin N+1.<\/p>\n<p>Hvorfor netop s\u00e5dan og ikke anderledes? I den del af pipelinen, der vedr\u00f8rer test, opdager testere den velkendte testpyramide.<\/p>\n<p><img decoding=\"async\" alt=\"Integr\u00e9r statisk analyse i processen, i stedet for at bruge den til at finde fejl.\" src=\"\/wp-content\/uploads\/2019\/05\/f155307fd4c1663800843c394098ea6f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Testpyramiden. Kilde: <noindex><a rel=\"nofollow\" href=\"https:\/\/martinfowler.com\/bliki\/TestPyramid.html\">artikel<\/a><\/noindex> Martin Fowler.<\/i><\/p>\n<p>I bunden af denne pyramide findes tests, der er lettere at skrive, hurtigere at udf\u00f8re og har f\u00e6rre falske alarmer. Derfor b\u00f8r der v\u00e6re flere af dem, de b\u00f8r d\u00e6kke mere kode og udf\u00f8res f\u00f8rst. I toppen af pyramiden er situationen den stik modsatte, s\u00e5 antallet af integrations- og UI-tests b\u00f8r reduceres til et n\u00f8dvendigt minimum. Mennesker i denne k\u00e6de er den dyreste, langsomste og mest usikre ressource, derfor er de placeret bagerst og udf\u00f8rer kun arbejde, hvis de tidligere trin ikke har opdaget nogen defekter. Men samme principper g\u00e6lder for pipelinen ogs\u00e5 i de dele, der ikke er direkte relateret til test!<\/p>\n<p>Jeg vil gerne foresl\u00e5 en analogi i form af et flertrins vandfiltreringssystem. Den indkommende vand er beskidt (\u00e6ndringer med defekter), og vi skal f\u00e5 rent vand ud, hvor alle u\u00f8nskede forurenende stoffer er blevet filtreret fra.<\/p>\n<p><img decoding=\"async\" alt=\"Integr\u00e9r statisk analyse i processen, i stedet for at bruge den til at finde fejl.\" src=\"\/wp-content\/uploads\/2019\/05\/76b5be8f13d55c16970d67e09767a045.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Multitrinsfilter. Kilde: <noindex><a rel=\"nofollow\" href=\"https:\/\/commons.wikimedia.org\/wiki\/File:Milli-Q_Water_filtration_station.JPG\">Wikimedia Commons<\/a><\/noindex><\/i><\/p>\n<p>Som bekendt designes reng\u00f8ringsfiltre s\u00e5ledes, at hvert efterf\u00f8lgende niveau kan sortere stadig finere fraktioner af forurening. Dette betyder, at grovere oprydningsniveauer har en h\u00f8jere kapacitet og lavere omkostninger. I vores analogi betyder det, at indgangsquality gates har st\u00f8rre ydeevne, kr\u00e6ver mindre indsats for at blive aktiveret og i sig selv er mere ubesv\u00e6rede i drift \u2014 og de er organiseret i netop denne r\u00e6kkef\u00f8lge. Rollen af statisk analyse, som vi nu forst\u00e5r, kun er i stand til at filtrere de groveste fejl \u2014 er ligesom en gitter-\"snavsefanger\" i starten af filtrenes cascade.<\/p>\n<p>Statisk analyse forbedrer ikke kvaliteten af det endelige produkt i sig selv, ligesom en snavsefanger ikke g\u00f8r vandet drikkeligt. Ikke desto mindre er dens betydning \u00e5benlys i den samlede sammenh\u00e6ng med andre elementer i produktionslinjen. Selvom den udg\u00e5ende cascade i en multicascade-filterpotentiale er i stand til at opfange det samme, som indgangene g\u00f8r \u2014 er det klart, hvilke konsekvenser det vil have at fors\u00f8ge at klare sig kun med finere oprydningsniveauer uden de indg\u00e5ende niveauer.<\/p>\n<p>M\u00e5let med \"snavsefanger\" er at lette de efterf\u00f8lgende cascades for at opfange de mest grove fejl. For eksempel b\u00f8r en person, der udf\u00f8rer code review, ikke blive distraheret af forkert formateret kode og overtr\u00e6delse af fastsatte kodestandarder (som un\u00f8dvendige parenteser eller for dybe indlejrede forgreninger). Fejl som NPE b\u00f8r fanges af enhedstest, men hvis analysatoren allerede viser os, at fejlen uundg\u00e5eligt vil ske, inden testen \u2014 vil det klart fremskynde reparationen.<\/p>\n<p>Jeg mener, det er klart nu, hvorfor statisk analyse ikke forbedrer produktkvaliteten, hvis den anvendes sporadisk, og at det skal anvendes konstant for at filtrere \u00e6ndringer med grove fejl. Sp\u00f8rgsm\u00e5let om, hvorvidt anvendelsen af en statisk analysator vil forbedre kvaliteten af dit produkt, svarer omtrent til sp\u00f8rgsm\u00e5let \"vil drikkevandskvaliteten forbedres, hvis vandet fra en beskidt dam passes gennem en sigte?\"<\/p>\n<h2>Implementering i legacy-projekt<\/h2>\n<p>\nEt vigtigt praktisk sp\u00f8rgsm\u00e5l: hvordan implementerer man statisk analyse i processen for kontinuerlig integration som en \"quality gate\"? N\u00e5r det kommer til automatiserede tests, er det klart: der er et s\u00e6t tests, og hvis en af dem fejler, er det en tilstr\u00e6kkelig grund til at anse, at bygningen ikke har best\u00e5et quality gate. At fors\u00f8ge at etablere en gate baseret p\u00e5 resultaterne af statisk analyse mislykkes: p\u00e5 legacy-kode er der alt for mange advarsler fra analysen, man vil ikke helt ignorere dem, men det er umuligt at stoppe leveringen af produktet bare fordi der er advarsler fra analysatoren.<\/p>\n<p>N\u00e5r analysatoren anvendes for f\u00f8rste gang p\u00e5 et hvilket som helst projekt, genererer den et enormt antal advarsler, hvoraf de fleste ikke har noget at g\u00f8re med produktets korrekte funktion. Det er umuligt at rette alle disse bem\u00e6rkninger p\u00e5 \u00e9n gang, og mange er ikke engang n\u00f8dvendige at rette. I sidste ende ved vi jo, at vores produkt fungerer generelt, selv f\u00f8r vi implementerer statisk analyse!<\/p>\n<p>Som et resultat begr\u00e6nser mange sig til sporadisk brug af statisk analyse, eller de bruger det kun i informationsmode, hvor der blot genereres en rapport fra analysatoren ved bygning. Dette er det samme som at have ingen analyse overhovedet, fordi hvis vi allerede har mange advarsler, forbliver forekomsten af endnu en (uanset hvor alvorlig) ved kodemodifikation uset.<\/p>\n<p>F\u00f8lgende m\u00e5der til at indf\u00f8re quality gates er kendt:<\/p>\n<ul>\n<li>Indstilling af en gr\u00e6nse for det samlede antal advarsler eller antallet af advarsler divideret med antallet af kodelinjer. Dette fungerer d\u00e5rligt, da s\u00e5dan en gate let tillader \u00e6ndringer med nye fejl, s\u00e5 l\u00e6nge deres gr\u00e6nse ikke er overskredet.<\/li>\n<li>Registrering af alle tidligere advarsler i koden som ignorerede p\u00e5 et bestemt tidspunkt og afvisning af opbygning ved nye advarsler. Denne funktionalitet tilbydes af PVS-studio og nogle online-resurser, s\u00e5som Codacy. Jeg har ikke arbejdet med PVS-studio, men med hensyn til min erfaring med Codacy er deres st\u00f8rste problem, at det er ret kompliceret at afg\u00f8re, hvad der er en \"gammel\" og hvad der er en \"ny\" fejl \u2014 is\u00e6r n\u00e5r filer \u00e6ndres eller omd\u00f8bes kraftigt. Efter min hukommelse kunne Codacy overse nye advarsler i en pull request, mens de samtidig kunne afvise pull requesten p\u00e5 grund af advarsler, der ikke relaterede sig til \u00e6ndringerne i denne PR.<\/li>\n<li>Efter min mening er den mest effektive l\u00f8sning beskrevet i bogen <noindex><a rel=\"nofollow\" href=\"https:\/\/www.amazon.com\/Continuous-Delivery-Deployment-Automation-Addison-Wesley\/dp\/0321601912\">Continuous Delivery<\/a><\/noindex> metoden med tandhjul (\"ratcheting\"). Hovedideen er, at egenskaben ved hver udgivelse er antallet af advarsler fra statisk analyse, og at kun \u00e6ndringer, der ikke \u00f8ger det samlede antal advarsler, er tilladt.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Tandhjul<\/h2>\n<p>\nDet fungerer p\u00e5 den m\u00e5de:<\/p>\n<ol>\n<li>I den indledende fase registreres antallet af advarsler i koden, der er fundet af analyserne, i metadatasystemet om udgivelsen. S\u00e5ledes registreres ikke blot \"udgivelse 7.0.2\", men \"udgivelse 7.0.2, der indeholder 100500 Checkstyle-advarsler\" i din repositories manager. Hvis du bruger en avanceret repositories manager (s\u00e5som Artifactory), er det let at gemme s\u00e5danne metadata om din udgivelse.<\/li>\n<li>Nu sammenligner hver pull request ved opbygning antallet af opn\u00e5ede advarsler med det antal, der findes i den aktuelle udgivelse. Hvis PR'en f\u00f8rer til en stigning i dette antal, passerer koden ikke quality gate ved den statiske analyse. Hvis antallet af advarsler mindskes eller ikke \u00e6ndres \u2014 s\u00e5 best\u00e5r den.<\/li>\n<li>Ved n\u00e6ste udgivelse vil det genberegnede antal advarsler igen blive registreret i metadataene for udgivelsen.<\/li>\n<\/ol>\n<p>\nS\u00e5dan set, men stille og roligt (som ved brug af en tandhjul), vil antallet af advarsler til gradvist n\u00e6rme sig nul. Selvf\u00f8lgelig kan systemet narres ved at tilf\u00f8je en ny advarsel, mens man retter en andens. Det er i orden, da det p\u00e5 lang sigt giver resultater: advarsler rettes som regel ikke enkeltvis, men i grupper af en bestemt type, og alle let-udrettede advarsler bliver ret hurtigt l\u00f8st.<\/p>\n<p>P\u00e5 denne graf ses det samlede antal Checkstyle-advarsler over et halvt \u00e5rs drift af en s\u00e5dan \"tandhjul\" p\u00e5 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\">et af vores OpenSource-projekter<\/a><\/noindex>. Antallet af advarsler er faldet med en orden, og dette skete p\u00e5 en naturlig m\u00e5de, parallelt med produktudviklingen!<\/p>\n<p><img decoding=\"async\" alt=\"Integr\u00e9r statisk analyse i processen, i stedet for at bruge den til at finde fejl.\" src=\"\/wp-content\/uploads\/2019\/05\/9529bb2fb32187057088e8d2c4203333.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJeg anvender en modificeret version af denne metode, hvor jeg separat t\u00e6ller advarsler opdelt efter projektmoduler og analysev\u00e6rkt\u00f8jer. Den genererede YAML-fil med metadata om buildet ser cirka s\u00e5dan ud:<\/p>\n<pre><code class=\"plaintext\">celesta-sql:\n  checkstyle: 434\n  spotbugs: 45\ncelesta-core:\n  checkstyle: 206\n  spotbugs: 13\ncelesta-maven-plugin:\n  checkstyle: 19\n  spotbugs: 0\ncelesta-unit:\n  checkstyle: 0\n  spotbugs: 0\n<\/code><\/pre>\n<p>\nI ethvert avanceret CI-system kan \"tandhjulet\" implementeres for enhver statisk analysev\u00e6rkt\u00f8j, uden at man er afh\u00e6ngig af plugins og tredjeparts v\u00e6rkt\u00f8jer. Hver af analyserne giver sin rapport i et simpelt tekst- eller XML-format, som er let at analysere. Det kr\u00e6ver kun at skrive den n\u00f8dvendige logik i CI-scriptet. Man kan se, hvordan dette er implementeret i vores open source-projekter baseret p\u00e5 Jenkins og Artifactory, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/2bass\/blob\/dev\/Jenkinsfile\">her<\/a><\/noindex> eller <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/dev\/Jenkinsfile\">her<\/a><\/noindex>. Begge eksempler afh\u00e6nger af biblioteket <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/inponomarev\/ratchetlib\">ratchetlib<\/a><\/noindex>: metoden <code>countWarnings()<\/code> t\u00e6ller almindeligvis xml-tags i de filer, som Checkstyle og Spotbugs genererer, og <code>compareWarningMaps()<\/code> implementerer det n\u00e6vnte tandhjul, hvilket kaster en fejl, hvis antallet af advarsler i en hvilken som helst kategori stiger.<\/p>\n<p>En interessant implementeringsmulighed for 'ratchet'-systemet er til analyse af stavning i kommentarer, tekstliteraler og dokumentation ved hj\u00e6lp af aspell. Som bekendt er det ikke alle ord, der ikke er anerkendt af standardordbogen, der er forkerte; de kan tilf\u00f8jes til brugerordbogen. Hvis du g\u00f8r brugerordbogen til en del af projektets kode, kan kvalitetsticketet for stavning formuleres s\u00e5ledes: udf\u00f8re aspell med b\u00e5de standard- og brugerordbogen. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/271dcfc8dc3ad65ac2d1dcaa39b7fd3ea8fb5891\/Jenkinsfile#L36\">m\u00e5 ikke<\/a><\/noindex> finde nogen stavefejl.<\/p>\n<h2>Om vigtigheden af at fastl\u00e5se versionen af analysatoren<\/h2>\n<p>\nAfslutningsvis skal det bem\u00e6rkes, at uanset hvordan du implementerer analysen i din leveringslinje, b\u00f8r versionen af analysatoren v\u00e6re fastl\u00e5st. Hvis analysatoren opdateres af sig selv, kan der 'opst\u00e5' nye defekter ved sammens\u00e6tningen af en pull request, som ikke er relateret til kode\u00e6ndringer, men til at den nye analysator simpelthen er i stand til at finde flere defekter - hvilket vil forstyrre din proces med godkendelse af pull requests. Opgradering af analysatoren skal v\u00e6re en bevidst handling. For \u00f8vrigt er fastl\u00e5sning af versionen af hver komponent i bygningen i det hele taget et n\u00f8dvendigt krav og emnet for en separat samtale.<\/p>\n<h2>Konklusioner<\/h2>\n<p><\/p>\n<ul>\n<li>Statisk analyse finder ikke bugs og forbedrer ikke kvaliteten af dit produkt ved blot at blive anvendt \u00e9n gang. Den positive effekt p\u00e5 kvaliteten opn\u00e5s kun ved dens konstante anvendelse i leveringsprocessen.<\/li>\n<li>At finde bugs er slet ikke hovedopgaven for analysen; stort set alle nyttige funktioner er tilg\u00e6ngelige i open source-v\u00e6rkt\u00f8jer.<\/li>\n<li>Implementer kvalitetsgate ved resultaterne af statisk analyse i den allerf\u00f8rste fase af leveringslinjen ved at bruge 'ratchet' til legacy-kode.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Links<\/h2>\n<p><\/p>\n<ol>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.amazon.com\/Continuous-Delivery-Deployment-Automation-Addison-Wesley\/dp\/0321601912\">Continuous Delivery<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=8Cx3LHNjI24\">A. Kudrjavtsev: Programmeranalyse: hvordan man forst\u00e5r, at du er en god programm\u00f8r<\/a><\/noindex> en rapport om forskellige metoder til kodeanalyse (ikke kun statisk!)<\/li>\n<\/ol>\n<p>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/436868\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435, \u0432\u0441\u0451 \u0447\u0430\u0449\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043d\u0430 \u0433\u043b\u0430\u0437\u0430. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u044d\u0442\u043e \u0431\u043b\u043e\u0433 PVS-studio, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u043f\u0440\u043e\u0434\u0432\u0438\u0433\u0430\u0435\u0442 \u0441\u0435\u0431\u044f \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u0431\u0437\u043e\u0440\u043e\u0432 \u043e\u0448\u0438\u0431\u043e\u043a, \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u043a\u043e\u0434\u043e\u043c. \u041d\u0435\u0434\u0430\u0432\u043d\u043e PVS-studio \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 Java, \u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 IntelliJ IDEA, \u0447\u0435\u0439 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":24622,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-32848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435, \u0432\u0441\u0451 \u0447\u0430\u0449\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043d\u0430 \u0433\u043b\u0430\u0437\u0430.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0412\u043d\u0435\u0434\u0440\u044f\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0430 \u043d\u0435 \u0438\u0449\u0438\u0442\u0435 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0430\u0433\u0438 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435, \u0432\u0441\u0451 \u0447\u0430\u0449\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043d\u0430 \u0433\u043b\u0430\u0437\u0430.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:49:16+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:49:16+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Implementer statisk analyse i processen, i stedet for at s\u00f8ge efter bugs med den | ProHoster","description":"At skrive denne artikel blev udl\u00f8st af den store m\u00e6ngde materiale om statisk analyse, der i stigende grad falder i \u00f8jnene.","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0412\u043d\u0435\u0434\u0440\u044f\u0439\u0442\u0435 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u0438\u0437 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0430 \u043d\u0435 \u0438\u0449\u0438\u0442\u0435 \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0430\u0433\u0438 | ProHoster","og:description":"\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u0435\u043d\u044f \u0441\u043f\u043e\u0434\u0432\u0438\u0433\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0435, \u0432\u0441\u0451 \u0447\u0430\u0449\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043d\u0430 \u0433\u043b\u0430\u0437\u0430.","og:url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:49:16+00:00","article:modified_time":"2019-10-31T18:49:16+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"32848","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 12:50:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 02:51:27","updated":"2026-01-21 12:50:20","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/32848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=32848"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/32848\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/24622"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=32848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=32848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=32848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}