{"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\/ro\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","title":{"rendered":"Implementa\u021bi analiza static\u0103 \u00een proces, nu o c\u0103uta\u021bi pentru a descoperi erori","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Articolul acestui subiect a fost inspirat de cantitatea mare de materiale despre analiza static\u0103, care apar din ce \u00een ce mai des. \u00cen primul r\u00e2nd, este vorba despre <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/\">blogul PVS-studio<\/a><\/noindex>, care se promoveaz\u0103 activ pe Habr prin recenzii ale erorilor descoperite de instrumentul lor \u00een proiecte open-source. Recent, PVS-studio a implementat <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/436496\/\">suport pentru Java<\/a><\/noindex>, iar, desigur, dezvoltatorii IntelliJ IDEA, al c\u0103ror analizor \u00eencorporat este, probabil, cel mai avansat pentru Java, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/JetBrains\/blog\/436278\/\">nu putea r\u0103m\u00e2ne pe margine<\/a><\/noindex>. <\/p>\n<p>Citind astfel de recenzii, ai senza\u021bia c\u0103 este vorba despre un elixir magic: apas\u0103 pe un buton \u0219i iat\u0103-l - o list\u0103 de defecte \u00een fa\u021ba ta. Se pare c\u0103, pe m\u0103sur\u0103 ce analizorii devin mai perfec\u021biona\u021bi, bug-urile vor fi g\u0103site din ce \u00een ce mai multe, iar produsele scanate de ace\u0219ti robo\u021bi vor deveni din ce \u00een ce mai bune, f\u0103r\u0103 niciun efort din partea noastr\u0103.<\/p>\n<p>Dar nu exist\u0103 elixire magice. A\u0219 dori s\u0103 discut despre ceea ce de obicei nu se men\u021bioneaz\u0103 \u00een posturi de genul \u201eiat\u0103 ce poate g\u0103si robotul nostru\u201d: ce nu pot face analizorii, care este rolul \u0219i locul lor real \u00een procesul de livrare a software-ului \u0219i cum s\u0103 \u00eei implement\u0103m corect.<\/p>\n<p><img decoding=\"async\" alt=\"Implementa\u021bi analiza static\u0103 \u00een proces, nu o c\u0103uta\u021bi pentru a descoperi erori\" src=\"\/wp-content\/uploads\/2019\/05\/2a0339f10edcaed3310676ab6e2f975a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Zg\u00e2rci (sursa: <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>Ce nu vor putea face niciodat\u0103 analizorii statici<\/h2>\n<p>\nCe \u00eenseamn\u0103, din punct de vedere practic, analiza codului surs\u0103? Introducem anumite surse, iar la ie\u0219ire, \u00eentr-un timp foarte scurt (mult mai scurt dec\u00e2t rularea testelor), ob\u021binem anumite informa\u021bii despre sistemul nostru. O limitare principial\u0103 \u0219i matematic imposibil de dep\u0103\u0219it este c\u0103 putem ob\u021bine astfel doar o clas\u0103 destul de restr\u00e2ns\u0103 de informa\u021bii.<\/p>\n<p>Cea mai cunoscut\u0103 problem\u0103 care nu poate fi rezolvat\u0103 prin analiza static\u0103 este <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Halting_problem\">problema opririi<\/a><\/noindex>: aceasta este o teorem\u0103 care dovede\u0219te c\u0103 nu este posibil s\u0103 dezvol\u021bi un algoritm general care, pe baza codului surs\u0103 al unui program, s\u0103 determine dac\u0103 se va bloca \u00eentr-un ciclu sau se va finaliza \u00eentr-un timp finit. O extensie a acestei teoreme este <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Rice%27s_theorem\">teorema Rice<\/a><\/noindex>, afirm\u00e2nd c\u0103 pentru orice proprietate non-trivial\u0103 a func\u021biilor computabile, defini\u021bia dac\u0103 un program oarecare calculeaz\u0103 o func\u021bie cu aceast\u0103 proprietate este o sarcin\u0103 algoritmic imposibil de rezolvat. De exemplu, este imposibil s\u0103 scrii un analizator care, pentru orice cod surs\u0103, s\u0103 determine dac\u0103 programul analizat este o implementare a unui algoritm care calculeaz\u0103, s\u0103 zicem, ridicarea la p\u0103trat a unui num\u0103r \u00eentreg.<\/p>\n<p>Astfel, func\u021bionalitatea analizatorilor statici are limit\u0103ri greu de dep\u0103\u0219it. Un analizator static nu va putea niciodat\u0103 s\u0103 determine \u00een toate cazurile aspecte precum, de exemplu, apari\u021bia \u00abnull pointer exception\u00bb \u00een limbaje care permit valoarea null, sau \u00een toate cazurile s\u0103 determine apari\u021bia \u00abattribute not found\u00bb \u00een limbaje cu tipizare dinamic\u0103. Tot ce poate face cel mai sofisticat analizator static este s\u0103 eviden\u021bieze cazuri particulare, num\u0103rul c\u0103rora \u00een r\u00e2ndul tuturor problemelor posibile cu codul t\u0103u surs\u0103 este, f\u0103r\u0103 exagerare, o pic\u0103tur\u0103 \u00een mare.<\/p>\n<h2>Analiz\u0103 static\u0103 \u2014 nu este c\u0103utarea bug-urilor<\/h2>\n<p>\nDin cele spuse mai sus reiese o concluzie: analiza static\u0103 nu este un mijloc de reducere a num\u0103rului de defecte din program. \u00cemi permit s\u0103 afirm c\u0103, atunci c\u00e2nd este aplicat\u0103 pentru prima dat\u0103 \u00een proiectul t\u0103u, va g\u0103si \u00een cod locuri \u00abinteresante\u00bb, dar, cel mai probabil, nu va determina defecte care influen\u021beaz\u0103 calitatea func\u021bion\u0103rii programului t\u0103u.<\/p>\n<p>Exemplele de defecte, g\u0103site automat de analizatori, sunt impresionante, dar nu trebuie s\u0103 uit\u0103m c\u0103 aceste exemple au fost g\u0103site prin scanarea unui set mare de baze de cod mari. Dup\u0103 aceea\u0219i idee, hackeri care au posibilitatea de a verifica c\u00e2teva parole simple pe un num\u0103r mare de conturi ajung, \u00een cele din urm\u0103, s\u0103 g\u0103seasc\u0103 acele conturi care au o parol\u0103 simpl\u0103.<\/p>\n<p>\u00censeamn\u0103 asta c\u0103 analiza static\u0103 nu trebuie aplicat\u0103? Desigur c\u0103 nu! \u0218i din acela\u0219i motiv pentru care ar trebui s\u0103 verifici fiecare parol\u0103 nou\u0103 pentru a nu figura pe lista de \u00abparole simple\u00bb.<\/p>\n<h2>Analiz\u0103 static\u0103 \u2014 este mai mult dec\u00e2t c\u0103utarea bug-urilor<\/h2>\n<p>\n\u00cen realitate, problemele care sunt practic solu\u021bionabile prin analiz\u0103 sunt mult mai diverse. \u00cen general, analiza static\u0103 este orice verificare a codului surs\u0103 care se efectueaz\u0103 \u00eenainte de execu\u021bia acestuia. Iat\u0103 c\u00e2teva lucruri pe care le po\u021bi face:<\/p>\n<ul>\n<li> Verificarea stilului de codare \u00een sens larg al termenului. Aceasta include at\u00e2t verificarea format\u0103rii, c\u00e2t \u0219i c\u0103utarea utiliz\u0103rii parantezelor goale\/\u00eenn\u0103scute, stabilirea valorilor limit\u0103 pentru metrici precum num\u0103rul de linii\/complexitatea ciclomatic\u0103 a metodei etc. - tot ceea ce ar putea \u00eengreuna citibilitatea \u0219i \u00eentre\u021binerea codului. \u00cen Java, un astfel de instrument este Checkstyle, iar \u00een Python, flake8. Programele de acest tip sunt de obicei denumite \u201elintere\u201d.<\/li>\n<li>Analiza nu se poate limita doar la codul executabil. Fi\u0219ierele de resurse, cum ar fi JSON, YAML, XML, .properties pot (\u0219i ar trebui!) s\u0103 fie verificate automat pentru validitate. Este mai bine s\u0103 afli c\u0103 structura JSON este rupt\u0103 din cauza unor ghilimele nepereche \u00een stadiul ini\u021bial al verific\u0103rii automate a Pull Request-ului, dec\u00e2t \u00een timpul test\u0103rii sau al execu\u021biei? Instrumentele corespunz\u0103toare sunt disponibile: de exemplu, <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> Compilarea (sau parsarea pentru limbajele de programare dinamice) este de asemenea un tip de analiz\u0103 static\u0103. De obicei, compilatoarele sunt capabile s\u0103 emit\u0103 avertiz\u0103ri care semnaleaz\u0103 problemele legate de calitatea codului surs\u0103, \u0219i aceste avertiz\u0103ri nu ar trebui ignorate.<\/li>\n<li>Uneori, compilarea nu se refer\u0103 doar la compilarea codului executabil. De exemplu, dac\u0103 ai documenta\u021bie \u00een format <noindex><a rel=\"nofollow\" href=\"https:\/\/asciidoctor.org\/\">AsciiDoctor<\/a><\/noindex>, atunci \u00een momentul transform\u0103rii acesteia \u00een HTML\/PDF, procesorul AsciiDoctor (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/asciidoctor\/asciidoctor-maven-plugin\">plugin Maven<\/a><\/noindex>) poate emite avertiz\u0103ri, de exemplu, despre linkuri interne rupte. \u0218i acesta este un motiv valid pentru a respinge un Pull Request cu modific\u0103ri \u00een documenta\u021bie.<\/li>\n<li>Verificarea ortografiei este de asemenea un tip de analiz\u0103 static\u0103. Instrumentul <noindex><a rel=\"nofollow\" href=\"http:\/\/aspell.net\/\">aspell<\/a><\/noindex> poate verifica ortografia nu doar \u00een documenta\u021bie, ci \u0219i \u00een codurile surs\u0103 ale programelor (\u00een comentarii \u0219i litere) \u00een diferite limbaje de programare, inclusiv C\/C++, Java \u0219i Python. O gre\u0219eal\u0103 de ortografie \u00een interfa\u021ba utilizatorului sau \u00een documenta\u021bie reprezint\u0103 de asemenea un defect!<\/li>\n<li>Testele de configurare (pentru mai multe informa\u021bii, vezi <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KaeEjsAjV6A&amp;index=30&amp;list=PLsVTVVvrKX9tuYyCtL8mASB6IOaa-kRCA&amp;t=0s\">aceasta<\/a><\/noindex> \u0219i <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=Tk_nmV-mWOA\">aceasta<\/a><\/noindex> prezent\u0103rile), de\u0219i sunt executate \u00een medii de testare unit\u0103\u021bii de tip pytest, sunt de fapt \u0219i ele o form\u0103 de analiz\u0103 static\u0103, deoarece nu execut\u0103 codurile surs\u0103 \u00een timpul desf\u0103\u0219ur\u0103rii lor.<\/li>\n<\/ul>\n<p>\nA\u0219a cum se poate observa, identificarea erorilor din aceast\u0103 list\u0103 are un rol mai pu\u021bin important, \u00een timp ce restul este accesibil prin utilizarea instrumentelor open source gratuite.<\/p>\n<p>Care dintre aceste tipuri de analiz\u0103 static\u0103 ar trebui aplicate \u00een proiectul dumneavoastr\u0103? Cu siguran\u021b\u0103, cu c\u00e2t mai multe, cu at\u00e2t mai bine! Important este s\u0103 implementa\u021bi corect, despre ce vom discuta \u00een continuare.<\/p>\n<h2>Canalul de livrare ca un filtru \u00een mai multe etape \u0219i analiza static\u0103 ca primul s\u0103u cascade.<\/h2>\n<p>\nMetafora clasic\u0103 a integr\u0103rii continue este un canal (pipeline) prin care trec modific\u0103rile \u2014 de la schimbarea codului surs\u0103 p\u00e2n\u0103 la livrarea \u00een produc\u021bie. Secven\u021ba standard a etapelor acestui canal arat\u0103 astfel:<\/p>\n<ol>\n<li>analiza static\u0103<\/li>\n<li>compilare<\/li>\n<li>teste unitare<\/li>\n<li>teste de integrare<\/li>\n<li>teste UI<\/li>\n<li>verificare manual\u0103<\/li>\n<\/ol>\n<p>\nModific\u0103rile respinse la etapa N a canalului nu sunt transmise etapei N+1.<\/p>\n<p>De ce exact a\u0219a \u0219i nu altfel? \u00cen partea canalului care se ocup\u0103 cu testarea, testerele \u00eenva\u021b\u0103 despre binecunoscuta piramid\u0103 de testare.<\/p>\n<p><img decoding=\"async\" alt=\"Implementa\u021bi analiza static\u0103 \u00een proces, nu o c\u0103uta\u021bi pentru a descoperi erori\" src=\"\/wp-content\/uploads\/2019\/05\/f155307fd4c1663800843c394098ea6f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Piramida testelor. Sursa: <noindex><a rel=\"nofollow\" href=\"https:\/\/martinfowler.com\/bliki\/TestPyramid.html\">articol<\/a><\/noindex> Martin Fowler.<\/i><\/p>\n<p>\u00cen partea de jos a acestei piramide se afl\u0103 teste care sunt mai u\u0219or de scris, executate mai repede \u0219i nu au tendin\u021ba de a da alarme false. Prin urmare, ar trebui s\u0103 fie mai multe, ele ar trebui s\u0103 acopere mai mult cod \u0219i s\u0103 fie executate primele. \u00cen partea de sus a piramidei, lucrurile stau invers, astfel \u00eenc\u00e2t num\u0103rul testelor de integrare \u0219i UI ar trebui s\u0103 fie redus la minimul necesar. Persoana din aceast\u0103 lan\u021b este cea mai scump\u0103, lent\u0103 \u0219i nesigur\u0103 resurs\u0103, de aceea se afl\u0103 la sf\u00e2r\u0219it \u0219i \u00ee\u0219i desf\u0103\u0219oar\u0103 activitatea doar \u00een cazul \u00een care etapele anterioare nu au descoperit defecte. Totu\u0219i, conform acelora\u0219i principii se construie\u0219te canalul \u0219i \u00een p\u0103r\u021bile care nu sunt direct legate de testare!<\/p>\n<p>A\u0219 dori s\u0103 propun o analogie folosind un sistem multistadiu de filtrare a apei. Apa murdar\u0103 (modific\u0103rile cu defecte) este introdus\u0103, iar la ie\u0219ire trebuie s\u0103 ob\u021binem ap\u0103 curat\u0103, toate contamin\u0103rile nedorite fiind filtrate.<\/p>\n<p><img decoding=\"async\" alt=\"Implementa\u021bi analiza static\u0103 \u00een proces, nu o c\u0103uta\u021bi pentru a descoperi erori\" src=\"\/wp-content\/uploads\/2019\/05\/76b5be8f13d55c16970d67e09767a045.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Filtru multistadiu. Sursa: <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>Dup\u0103 cum se \u0219tie, filtrele de cur\u0103\u021bare sunt proiectate astfel \u00eenc\u00e2t fiecare urm\u0103torul stadiu s\u0103 poat\u0103 separa frac\u021biile de impurit\u0103\u021bi din ce \u00een ce mai fine. Astfel, stadiile de cur\u0103\u021bare mai grosiere au o capacitate de filtrare mai mare \u0219i un cost mai mic. \u00cen analogia noastr\u0103, aceasta \u00eenseamn\u0103 c\u0103 por\u021bile de calitate de intrare au o vitez\u0103 de reac\u021bie mai mare, necesit\u0103 mai pu\u021bin efort pentru a porni \u0219i sunt, de asemenea, mai pu\u021bin exigente \u00een func\u021bionare - \u0219i exact \u00een aceast\u0103 ordine sunt construite. Rolul analizei statice, care, a\u0219a cum am \u00een\u021beles acum, este capabil s\u0103 elimine doar cele mai grosiere defecte - este rolul grilei de \u201eprefiltru\u201d la \u00eenceputul cascadei de filtre.<\/p>\n<p>Analiza static\u0103 \u00een sine nu \u00eembun\u0103t\u0103\u021be\u0219te calitatea produsului final, a\u0219a cum un prefiltru nu face apa potabil\u0103. Totu\u0219i, \u00een contextul general al altor elemente din linia de produc\u021bie, importan\u021ba sa este evident\u0103. De\u0219i \u00een filtrele cu mai multe stadii stadiile de ie\u0219ire pot captura \u00een mod poten\u021bial acelea\u0219i impurit\u0103\u021bi ca \u0219i cele de intrare - este clar la ce consecin\u021be va duce \u00eencercarea de a folosi doar stadiile fine de cur\u0103\u021bare, f\u0103r\u0103 stadiile de intrare.<\/p>\n<p>Scopul prefiltrului este de a desc\u0103rca stadiile urm\u0103toare de captarea defectelor complet grosiere. De exemplu, cu siguran\u021b\u0103, persoana care efectueaz\u0103 revizuirea codului nu ar trebui s\u0103 fie distras\u0103 de un cod formatat gre\u0219it \u0219i de \u00eenc\u0103lc\u0103ri ale normelor de codare stabilite (precum paranteze inutile sau ramifica\u021bii prea ad\u00e2nci). Bug-urile, precum NPE, ar trebui s\u0103 fie capturate de testele de unitate, dar dac\u0103, \u00eenainte de test, analizatorul ne indic\u0103 faptul c\u0103 bug-ul va ap\u0103rea inevitabil - aceasta va accelera semnificativ corectarea sa.<\/p>\n<p>Cred c\u0103 acum este clar de ce analiza static\u0103 nu \u00eembun\u0103t\u0103\u021be\u0219te calitatea produsului atunci c\u00e2nd este aplicat\u0103 episodic \u0219i ar trebui aplicat\u0103 constant pentru a elimina modific\u0103rile cu defecte grosiere. \u00centrebarea dac\u0103 utilizarea analizorului static va \u00eembun\u0103t\u0103\u021bi calitatea produsului vostru este aproximativ echivalent\u0103 cu \u00eentrebarea \u201ese vor \u00eembun\u0103t\u0103\u021bi calit\u0103\u021bile de potabilitate ale apei prelevate dintr-un bazin murdar, dac\u0103 o treci printr-o sit\u0103?\u201d.<\/p>\n<h2>Implementarea \u00een proiecte legacy<\/h2>\n<p>\nO \u00eentrebare practic\u0103 important\u0103: cum putem integra analiza static\u0103 \u00een procesul de integrare continu\u0103 ca \u201ebarier\u0103 de calitate\u201d? \u00cen cazul testelor automate, totul este clar: exist\u0103 un set de teste, e\u0219ecul oric\u0103ruia dintre ele este un motiv suficient pentru a considera c\u0103 construc\u021bia nu a trecut barrier\u0103 de calitate. \u00cencercarea de a stabili o barier\u0103 pe baza rezultatelor analizei statice e\u0219ueaz\u0103: \u00een codul legacy, num\u0103rul de avertismente ale analizei este prea mare, nu dorim s\u0103 le ignor\u0103m complet, dar nici nu putem opri livrarea produsului doar pentru c\u0103 acesta con\u021bine avertismente ale analizoarelor.<\/p>\n<p>Atunci c\u00e2nd este aplicat pentru prima dat\u0103, pe orice proiect, analizoarele genereaz\u0103 o cantitate imens\u0103 de avertismente, majoritatea c\u0103rora nu au leg\u0103tur\u0103 cu func\u021bionarea corect\u0103 a produsului. Corectarea imediat\u0103 a tuturor acestor observa\u021bii este imposibil\u0103, iar multe dintre ele \u2014 nici nu sunt necesare. \u00cen fond, noi \u0219tim c\u0103 produsul nostru func\u021bioneaz\u0103 \u00een general \u0219i \u00eenainte de implementarea analizei statice!<\/p>\n<p>Din acest motiv, mul\u021bi se limiteaz\u0103 la utilizarea ocazional\u0103 a analizei statice sau o folosesc doar \u00een modul de informare, c\u00e2nd la construirea proiectului se emite pur \u0219i simplu un raport al analizei. Aceasta este echivalent\u0103 cu lipsa oric\u0103rei analize, deoarece dac\u0103 avem deja multe avertismente, apari\u021bia unui altul (indiferent de seriozitate) atunci c\u00e2nd se modific\u0103 codul r\u0103m\u00e2ne neobservat\u0103.<\/p>\n<p>Se cunosc urm\u0103toarele metode de introducere a barrierelor de calitate:<\/p>\n<ul>\n<li>Stabilirea unei limite a num\u0103rului total de avertismente sau a num\u0103rului de avertismente, \u00eemp\u0103r\u021bit la num\u0103rul de linii de cod. Aceasta func\u021bioneaz\u0103 prost, deoarece o astfel de barier\u0103 permite liber modific\u0103ri cu noi defecte, at\u00e2ta timp c\u00e2t limita nu este dep\u0103\u0219it\u0103.<\/li>\n<li>Fixarea, \u00eentr-un anumit moment, a tuturor avertismentelor vechi din cod ca fiind ignorate \u0219i refuzul compil\u0103rii \u00een cazul apari\u021biei unor avertismente noi. Aceast\u0103 func\u021bionalitate este oferit\u0103 de PVS-studio \u0219i unele resurse online, cum ar fi Codacy. Nu am avut ocazia s\u0103 lucrez cu PVS-studio, iar \u00een ceea ce prive\u0219te experien\u021ba mea cu Codacy, principala lor problem\u0103 const\u0103 \u00een faptul c\u0103 determinarea a ceea ce este un \u201evechi\u201d \u0219i ce este un \u201enou\u201d avertisment este un algoritm destul de complicat \u0219i care nu func\u021bioneaz\u0103 \u00eentotdeauna corect, mai ales dac\u0103 fi\u0219ierele sunt modificate sau redenumite semnificativ. Din cele ce-mi amintesc, Codacy putea s\u0103 sar\u0103 peste noi avertismente \u00eentr-un pull request \u0219i, \u00een acela\u0219i timp, s\u0103 nu permit\u0103 pull request-ul din cauza unor avertismente care nu aveau leg\u0103tur\u0103 cu modific\u0103rile din codul acestui PR.<\/li>\n<li>Din punctul meu de vedere, cea mai eficient\u0103 solu\u021bie este cea descris\u0103 \u00een cartea <noindex><a rel=\"nofollow\" href=\"https:\/\/www.amazon.com\/Continuous-Delivery-Deployment-Automation-Addison-Wesley\/dp\/0321601912\">Continuous Delivery<\/a><\/noindex> \u201emetoda ratchet-ului\u201d (\u201eratcheting\u201d). Ideea de baz\u0103 este c\u0103 proprietatea fiec\u0103rei versiuni este num\u0103rul de avertismente de analiz\u0103 static\u0103, iar schimb\u0103rile permise sunt doar acelea care nu cresc num\u0103rul total de avertismente.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Ratcheting<\/h2>\n<p>\nFunc\u021bioneaz\u0103 astfel:<\/p>\n<ol>\n<li>\u00cen etapa ini\u021bial\u0103, se realizeaz\u0103 \u00eenregistrarea \u00een metadatele versiunii a num\u0103rului de avertismente din cod, g\u0103site de analizatori. Astfel, la compilarea ramurii principale, \u00een managerul dvs. de repositorii se va \u00eenregistra nu doar \u201eversiunea 7.0.2\u201d, ci \u201eversiunea 7.0.2, care con\u021bine 100500 avertismente Checkstyle\u201d. Dac\u0103 utiliza\u021bi un manager avansat de repositorii (cum ar fi Artifactory), este u\u0219or s\u0103 salva\u021bi astfel de metadate despre versiunea dvs.<\/li>\n<li>Acum, fiecare pull request la compilare compar\u0103 num\u0103rul de avertismente ob\u021binute cu num\u0103rul care exist\u0103 \u00een versiunea curent\u0103. Dac\u0103 PR determin\u0103 o cre\u0219tere a acestui num\u0103r, atunci codul nu trece testul de calitate prin analiza static\u0103. Dac\u0103 num\u0103rul de avertismente scade sau r\u0103m\u00e2ne neschimbat, atunci trece.<\/li>\n<li>La urm\u0103toarea versiune, num\u0103rul recalculeaz\u0103 avertismentele va fi din nou \u00eenregistrat \u00een metadatele versiunii.<\/li>\n<\/ol>\n<p>\nAstfel, treptat, dar constant (ca la func\u021bionarea unui mecanism de tip ratchet), num\u0103rul de avertiz\u0103ri va tinde spre zero. Desigur, sistemul poate fi p\u0103c\u0103lit, introduc\u00e2nd o nou\u0103 avertizare, dar corect\u00e2nd una existent\u0103. Este \u00een regul\u0103, deoarece pe termen lung se ob\u021bine un rezultat: avertiz\u0103rile sunt corectate, de obicei, nu individual, ci simultan \u00eentr-un anumit grup, iar toate avertiz\u0103rile u\u0219or eliminabile sunt rezolvate destul de repede.<\/p>\n<p>\u00cen acest grafic este prezentat num\u0103rul total de avertiz\u0103ri Checkstyle pe parcursul a \u0219ase luni de lucru cu un astfel de \u201emecanism ratchet\u201d pe <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\">unul dintre proiectele noastre OpenSource<\/a><\/noindex>. Num\u0103rul de avertiz\u0103ri a sc\u0103zut cu o ordine de m\u0103rime, iar acest lucru s-a \u00eent\u00e2mplat natural, \u00een paralel cu dezvoltarea produsului!<\/p>\n<p><img decoding=\"async\" alt=\"Implementa\u021bi analiza static\u0103 \u00een proces, nu o c\u0103uta\u021bi pentru a descoperi erori\" src=\"\/wp-content\/uploads\/2019\/05\/9529bb2fb32187057088e8d2c4203333.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAplic o versiune modificat\u0103 a acestei metode, num\u0103r\u00e2nd separat avertiz\u0103rile \u00een func\u021bie de modulele proiectului \u0219i instrumentele de analiz\u0103, fi\u0219ierul YAML cu metadate despre construc\u021bie arat\u0103 aproximativ astfel:<\/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>\n\u00cen orice sistem CI avansat, \u201emecanismul ratchet\u201d poate fi implementat pentru orice instrumente de analiz\u0103 static\u0103, f\u0103r\u0103 a se baza pe plugin-uri \u0219i instrumente externe. Fiecare dintre analizatori produce propriul raport \u00eentr-un format text simplu sau XML, u\u0219or de analizat. R\u0103m\u00e2ne doar s\u0103 scriem logica necesar\u0103 \u00een scriptul CI. Putem observa cum este implementat \u00een proiectele noastre open source bazate pe Jenkins \u0219i Artifactory <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/2bass\/blob\/dev\/Jenkinsfile\">aici<\/a><\/noindex> sau <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/dev\/Jenkinsfile\">aici<\/a><\/noindex>. Ambele exemple depind de biblioteca <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/inponomarev\/ratchetlib\">ratchetlib<\/a><\/noindex>: metoda <code>countWarnings()<\/code> num\u0103r\u0103 \u00een mod obi\u0219nuit etichetele xml din fi\u0219ierele generate de Checkstyle \u0219i Spotbugs, iar <code>compareWarningMaps()<\/code> implementa acel mecanism ratchet, gener\u00e2nd o eroare \u00een cazul \u00een care num\u0103rul de avertiz\u0103ri din oricare dintre categorii cre\u0219te.<\/p>\n<p>O variant\u0103 interesant\u0103 de implementare a \u201erachet\u0103\u201d este posibil\u0103 pentru analiza ortografiei comentariilor, literelor text \u0219i documenta\u021biei cu ajutorul aspell. A\u0219a cum se \u0219tie, \u00een timpul verific\u0103rii ortografiei, nu toate cuvintele necunoscute pentru dic\u021bionarul standard sunt gre\u0219ite; acestea pot fi ad\u0103ugate \u00een dic\u021bionarul utilizatorului. Dac\u0103 facem dic\u021bionarul utilizatorului parte din codul surs\u0103 al proiectului, atunci quality gate pentru ortografie poate fi formulat astfel: rularea aspell cu dic\u021bionarul standard \u0219i cel personalizat. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/271dcfc8dc3ad65ac2d1dcaa39b7fd3ea8fb5891\/Jenkinsfile#L36\">nu ar trebui<\/a><\/noindex> s\u0103 g\u0103seasc\u0103 erori de ortografie.<\/p>\n<h2>Despre importan\u021ba fix\u0103rii versiunii analizoarelor<\/h2>\n<p>\n\u00cen concluzie, trebuie s\u0103 men\u021bion\u0103m urm\u0103toarele: indiferent de modul \u00een care implementa\u021bi analiza \u00een fluxul dvs. de livrare, versiunea analizoarelor trebuie s\u0103 fie fixat\u0103. Dac\u0103 permite\u021bi actualizarea spontan\u0103 a analizoarelor, atunci la compilarea urm\u0103torului pull request pot ap\u0103rea noi defecte, care nu sunt legate de modificarea codului, ci de faptul c\u0103 noul analizor poate descoperi mai multe defecte \u2014 \u0219i asta v\u0103 va afecta procesul de acceptare al pull request-urilor. Upgrade-ul analizoarelor ar trebui s\u0103 fie o ac\u021biune con\u0219tient\u0103. Totu\u0219i, fixarea strict\u0103 a versiunii fiec\u0103rei componente a compil\u0103rii este, \u00een general, o cerin\u021b\u0103 necesar\u0103 \u0219i un subiect pentru o discu\u021bie separat\u0103.<\/p>\n<h2>Conclusions<\/h2>\n<p><\/p>\n<ul>\n<li>Analiza static\u0103 nu va g\u0103si bug-uri \u0219i nu va \u00eembun\u0103t\u0103\u021bi calitatea produsului dvs. \u00een urma unei singure utiliz\u0103ri. Efectul pozitiv asupra calit\u0103\u021bii este dat doar de utilizarea constant\u0103 a acesteia \u00een procesul de livrare.<\/li>\n<li>C\u0103utarea bug-urilor nu este, \u00een general, principala sarcin\u0103 a analizei; majoritatea func\u021biilor utile sunt disponibile \u00een instrumentele open-source.<\/li>\n<li>Implementa\u021bi quality gates pe baza rezultatelor analizei statice \u00eenc\u0103 din prima etap\u0103 a fluxului de livrare, folosind \u201erachet\u0103\u201d pentru codul mo\u0219tenit.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Linkuri<\/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. Kudriav\u021bev: Analiza programelor: cum s\u0103 \u00een\u021belegi c\u0103 e\u0219ti un bun programator<\/a><\/noindex> prezentare despre diferite metode de analiz\u0103 a codului (nu doar static!)<\/li>\n<\/ol>\n<p>Sursa: <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.2.1 - 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\/ro\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Implementa\u021bi analiza static\u0103 \u00een proces, nu c\u0103uta\u021bi bug-uri cu ajutorul acesteia | ProHoster","description":"S\u0103 scriu acest articol m-a \u00eempins num\u0103rul mare de materiale despre analiza statica, tot mai frecvent \u00eent\u00e2lnite.","canonical_url":"https:\/\/prohoster.info\/ro\/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":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/32848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=32848"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/32848\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/24622"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=32848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=32848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=32848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}