{"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\/pl\/blog\/administrirovanie\/vnedryajte-staticheskij-analiz-v-protsess-a-ne-ishhite-s-ego-pomoshhyu-bagi","title":{"rendered":"Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj za jej pomoc\u0105 b\u0142\u0119d\u00f3w.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Napisanie tego artyku\u0142u zainspirowa\u0142a mnie ogromna liczba materia\u0142\u00f3w na temat analizy statycznej, kt\u00f3re coraz cz\u0119\u015bciej przyci\u0105gaj\u0105 moj\u0105 uwag\u0119. Po pierwsze, to <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/\">blog PVS-studio<\/a><\/noindex>, kt\u00f3ry aktywnie promuje si\u0119 na Habrze poprzez przegl\u0105dy b\u0142\u0119d\u00f3w znalezionych przez ich narz\u0119dzie w projektach z otwartym kodem. Niedawno PVS-studio wprowadzi\u0142o <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/pvs-studio\/blog\/436496\/\">wsparcie dla Javy<\/a><\/noindex>, i oczywi\u015bcie, deweloperzy IntelliJ IDEA, kt\u00f3rego wbudowany analizator jest obecnie prawdopodobnie najbardziej zaawansowany dla Javy, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/en\/company\/JetBrains\/blog\/436278\/\">nie mogli pozosta\u0107 oboj\u0119tni.<\/a><\/noindex>. <\/p>\n<p>Czytaj\u0105c takie przegl\u0105dy, ma si\u0119 wra\u017cenie, \u017ce m\u00f3wimy o magicznym eliksirze: naci\u015bnij przycisk, a oto lista defekt\u00f3w przed oczami. Wydaje si\u0119, \u017ce w miar\u0119 udoskonalania analizator\u00f3w, b\u0142\u0119d\u00f3w b\u0119dzie automatycznie znajdowa\u0107 si\u0119 coraz wi\u0119cej, a produkty skanowane przez te roboty b\u0119d\u0105 stawa\u0107 si\u0119 coraz lepsze, bez \u017cadnych wysi\u0142k\u00f3w z naszej strony.<\/p>\n<p>Ale magicznych eliksir\u00f3w nie ma. Chcia\u0142bym porozmawia\u0107 o tym, o czym zazwyczaj nie m\u00f3wi si\u0119 w postach typu \u201eoto, co nasz robot potrafi znale\u017a\u0107\u201d: czego analizatory nigdy nie b\u0119d\u0105 mog\u0142y zrobi\u0107, jaka jest ich rzeczywista rola i miejsce w procesie dostarczania oprogramowania, oraz jak je wdra\u017ca\u0107 poprawnie.<\/p>\n<p><img decoding=\"async\" alt=\"Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj za jej pomoc\u0105 b\u0142\u0119d\u00f3w.\" src=\"\/wp-content\/uploads\/2019\/05\/2a0339f10edcaed3310676ab6e2f975a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Wytrz\u0105sacz (\u017ar\u00f3d\u0142o: <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>Czego nigdy nie b\u0119d\u0105 mog\u0142y zrobi\u0107 statyczne analizatory<\/h2>\n<p>\nCo to jest, z praktycznego punktu widzenia, analiza kodu \u017ar\u00f3d\u0142owego? Podajemy pewne \u017ar\u00f3d\u0142a, a na wyj\u015bciu w kr\u00f3tkim czasie (zdecydowanie kr\u00f3tszym, ni\u017c przeprowadzenie test\u00f3w) uzyskujemy pewne informacje o naszym systemie. G\u0142\u00f3wnym i matematycznie nie do pokonania ograniczeniem jest to, \u017ce w ten spos\u00f3b mo\u017cemy uzyska\u0107 jedynie do\u015b\u0107 w\u0105sk\u0105 klas\u0119 informacji.<\/p>\n<p>Najbardziej znanym przyk\u0142adem problemu, kt\u00f3ry nie mo\u017ce by\u0107 rozwi\u0105zany za pomoc\u0105 analizy statycznej \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Halting_problem\">problem zatrzymania<\/a><\/noindex>: to twierdzenie, kt\u00f3re dowodzi, \u017ce nie jest mo\u017cliwe opracowanie og\u00f3lnego algorytmu, kt\u00f3ry na podstawie kodu \u017ar\u00f3d\u0142owego programu okre\u015bli, czy b\u0119dzie on si\u0119 zap\u0119tla\u0142, czy zako\u0144czy si\u0119 w sko\u0144czonym czasie. Rozszerzeniem tego twierdzenia jest <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Rice%27s_theorem\">twierdzenie Rice'a<\/a><\/noindex>, kt\u00f3re w ka\u017cdym nietrywialnym przypadku obliczalnych funkcji definiuj\u0105, czy dowolny program oblicza funkcj\u0119 o takim w\u0142a\u015bciwo\u015bci, jest problemem algorytmicznie nierozwi\u0105zywalnym. Na przyk\u0142ad, niemo\u017cliwe jest napisanie analizatora, kt\u00f3ry po dowolnym kodzie \u017ar\u00f3d\u0142owym okre\u015bli, czy analizowany program jest implementacj\u0105 algorytmu, kt\u00f3ry oblicza, powiedzmy, kwadrat liczby ca\u0142kowitej.<\/p>\n<p>W zwi\u0105zku z tym funkcjonalno\u015b\u0107 statycznych analizator\u00f3w ma nieprzezwyci\u0119\u017calne ograniczenia. Statyczny analizator nigdy nie b\u0119dzie w stanie we wszystkich przypadkach okre\u015bli\u0107 takich rzeczy, jak na przyk\u0142ad wyst\u0105pienie \u201enull pointer exception\u201d w j\u0119zykach dopuszczaj\u0105cych warto\u015b\u0107 null, ani we wszystkich przypadkach okre\u015bli\u0107 wyst\u0105pienia \u201eatrybut nie znaleziony\u201d w j\u0119zykach z dynamicznym typowaniem. Wszystko, co mo\u017ce osi\u0105gn\u0105\u0107 najdoskonalszy statyczny analizator, to wyodr\u0119bni\u0107 przypadki szczeg\u00f3lne, kt\u00f3rych liczba w\u015br\u00f3d wszystkich mo\u017cliwych problem\u00f3w z Twoim kodem \u017ar\u00f3d\u0142owym jest, nie b\u00f3jmy si\u0119 tego powiedzie\u0107, kropl\u0105 w morzu.<\/p>\n<h2>Analiza statyczna to nie poszukiwanie b\u0142\u0119d\u00f3w<\/h2>\n<p>\nZ powy\u017cszego wynika wniosek: analiza statyczna to nie \u015brodek do zmniejszenia liczby defekt\u00f3w w programie. O\u015bmiel\u0119 si\u0119 stwierdzi\u0107: stosuj\u0105c j\u0105 pierwszy raz w swoim projekcie, znajdzie w kodzie \u201eciekawostki\u201d, ale prawdopodobnie nie odkryje \u017cadnych defekt\u00f3w wp\u0142ywaj\u0105cych na jako\u015b\u0107 dzia\u0142ania Twojego programu.<\/p>\n<p>Przyk\u0142ady defekt\u00f3w, kt\u00f3re zosta\u0142y automatycznie wykryte przez analizatory, imponuj\u0105, ale nie nale\u017cy zapomina\u0107, \u017ce te przyk\u0142ady zosta\u0142y znalezione dzi\u0119ki skanowaniu du\u017cego zbioru rozbudowanych baz kodowych. Na tej samej zasadzie hakerzy, maj\u0105cy mo\u017cliwo\u015b\u0107 przetestowania kilku prostych hase\u0142 na wielu kontach, ostatecznie znajduj\u0105 te konta, na kt\u00f3rych jest proste has\u0142o.<\/p>\n<p>Czy to oznacza, \u017ce nie nale\u017cy stosowa\u0107 analizy statycznej? Oczywi\u015bcie, \u017ce nie! I z tej samej przyczyny, dla kt\u00f3rej warto sprawdza\u0107 ka\u017cde nowe has\u0142o pod k\u0105tem obecno\u015bci na li\u015bcie \u201eprosty\u201d hase\u0142.<\/p>\n<h2>Analiza statyczna to wi\u0119cej ni\u017c poszukiwanie b\u0142\u0119d\u00f3w<\/h2>\n<p>\nW rzeczywisto\u015bci kwestie, kt\u00f3re mo\u017cna rozwi\u0105za\u0107 za pomoc\u0105 analizy, s\u0105 znacznie szersze. W ko\u0144cu analiza statyczna to ka\u017cda kontrola kod\u00f3w \u017ar\u00f3d\u0142owych przeprowadzana przed ich uruchomieniem. Oto niekt\u00f3re rzeczy, kt\u00f3re mo\u017cna robi\u0107:<\/p>\n<ul>\n<li> Sprawdzenie stylu kodowania w szerokim tego s\u0142owa znaczeniu. Obejmuje to zar\u00f3wno kontrol\u0119 formatowania, jak i poszukiwanie u\u017cycia pustych lub zb\u0119dnych nawias\u00f3w, ustalanie prog\u00f3w dla metryk takich jak liczba linii lub z\u0142o\u017cono\u015b\u0107 cyklomatyczna metody itd. \u2014 wszystko, co potencjalnie utrudnia czytelno\u015b\u0107 i utrzymanie kodu. W Javie takim narz\u0119dziem jest Checkstyle, w Pythonie \u2014 flake8. Programy tego typu zazwyczaj nazywane s\u0105 \"linterami\".<\/li>\n<li>Analizie mo\u017ce podlega\u0107 nie tylko kod wykonywalny. Pliki zasob\u00f3w, takie jak JSON, YAML, XML, .properties mog\u0105 (i powinny!) by\u0107 automatycznie sprawdzane pod k\u0105tem poprawno\u015bci. Lepiej dowiedzie\u0107 si\u0119 o tym, \u017ce struktura JSON zosta\u0142a zaburzona przez jakie\u015b nieparzyste cudzys\u0142owy na wczesnym etapie automatycznej weryfikacji Pull Request, ni\u017c podczas wykonywania test\u00f3w lub w czasie wykonania? Odpowiednie narz\u0119dzia s\u0105 dost\u0119pne: na przyk\u0142ad, <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> Kompilacja (lub parsowanie dla dynamicznych j\u0119zyk\u00f3w programowania) to te\u017c rodzaj analizy statycznej. Zazwyczaj komputery s\u0105 w stanie generowa\u0107 ostrze\u017cenia sygnalizuj\u0105ce problemy z jako\u015bci\u0105 kodu \u017ar\u00f3d\u0142owego, kt\u00f3rych nie powinno si\u0119 ignorowa\u0107.<\/li>\n<li>Czasami kompilacja to nie tylko kompilacja kodu wykonywalnego. Na przyk\u0142ad, je\u015bli masz dokumentacj\u0119 w formacie <noindex><a rel=\"nofollow\" href=\"https:\/\/asciidoctor.org\/\">AsciiDoctor<\/a><\/noindex>, to w momencie jej przekszta\u0142cania w HTML\/PDF, przetwornik AsciiDoctor (<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/asciidoctor\/asciidoctor-maven-plugin\">wtyczki Maven<\/a><\/noindex>) mo\u017ce generowa\u0107 ostrze\u017cenia, na przyk\u0142ad o naruszonych linkach wewn\u0119trznych. I to jest istotny pow\u00f3d, aby nie zaakceptowa\u0107 Pull Request z zmianami w dokumentacji.<\/li>\n<li>Sprawdzanie pisowni to tak\u017ce forma analizy statycznej. Narz\u0119dzie <noindex><a rel=\"nofollow\" href=\"http:\/\/aspell.net\/\">aspell<\/a><\/noindex> jest w stanie sprawdza\u0107 pisowni\u0119 nie tylko w dokumentacji, ale tak\u017ce w kodzie \u017ar\u00f3d\u0142owym program\u00f3w (komentarzach i litera\u0142ach) w r\u00f3\u017cnych j\u0119zykach programowania, w tym C\/C++, Java i Python. B\u0142\u0105d ortograficzny w interfejsie u\u017cytkownika lub dokumentacji to te\u017c defekt!<\/li>\n<li>Testy konfiguracyjne (o tym, czym s\u0105, patrz <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=KaeEjsAjV6A&amp;index=30&amp;list=PLsVTVVvrKX9tuYyCtL8mASB6IOaa-kRCA&amp;t=0s\">ten<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=Tk_nmV-mWOA\">ten<\/a><\/noindex> prezentacje), chocia\u017c s\u0105 przeprowadzane w \u015brodowisku wykonywalnym test\u00f3w jednostkowych typu pytest, rzeczywi\u015bcie r\u00f3wnie\u017c s\u0105 rodzajem analizy statycznej, poniewa\u017c nie wykonuj\u0105 kod\u00f3w \u017ar\u00f3d\u0142owych w trakcie swojego dzia\u0142ania.<\/li>\n<\/ul>\n<p>\nJak widzimy, poszukiwanie b\u0142\u0119d\u00f3w w tej li\u015bcie zajmuje najmniej wa\u017cn\u0105 rol\u0119, a wszystko inne dost\u0119pne jest dzi\u0119ki u\u017cyciu bezp\u0142atnych narz\u0119dzi open source.<\/p>\n<p>Jakie z tych typ\u00f3w analizy statycznej nale\u017cy zastosowa\u0107 w Twoim projekcie? Oczywi\u015bcie, najlepiej wszystkie \u2014 im wi\u0119cej, tym lepiej! Najwa\u017cniejsze, aby wdro\u017cy\u0107 to poprawnie, o czym b\u0119dzie mowa dalej.<\/p>\n<h2>Proces dostarczania jako wieloetapowy filtr i analiza statyczna jako jego pierwszy kaskada<\/h2>\n<p>\nKlasyczn\u0105 metafor\u0105 ci\u0105g\u0142ej integracji jest rura (pipeline), przez kt\u00f3r\u0105 przep\u0142ywaj\u0105 zmiany \u2014 od zmiany kodu \u017ar\u00f3d\u0142owego do dostarczenia na produkcj\u0119. Standardowa kolejno\u015b\u0107 etap\u00f3w tego procesu wygl\u0105da nast\u0119puj\u0105co:<\/p>\n<ol>\n<li>analiza statyczna<\/li>\n<li>kompilacja<\/li>\n<li>testy jednostkowe<\/li>\n<li>testy integracyjne<\/li>\n<li>testy UI<\/li>\n<li>r\u0119czna weryfikacja<\/li>\n<\/ol>\n<p>\nZmiany odrzucone na N-tym etapie procesu nie s\u0105 przekazywane do etapu N+1.<\/p>\n<p>Dlaczego w\u0142a\u015bnie w ten spos\u00f3b, a nie inaczej? W tej cz\u0119\u015bci procesu, kt\u00f3ra dotyczy testowania, testerzy poznaj\u0105 szeroko znan\u0105 piramid\u0119 testowania.<\/p>\n<p><img decoding=\"async\" alt=\"Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj za jej pomoc\u0105 b\u0142\u0119d\u00f3w.\" src=\"\/wp-content\/uploads\/2019\/05\/f155307fd4c1663800843c394098ea6f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Piramida testowa. \u0179r\u00f3d\u0142o: <noindex><a rel=\"nofollow\" href=\"https:\/\/martinfowler.com\/bliki\/TestPyramid.html\">artyku\u0142<\/a><\/noindex> Martina Fowlera.<\/i><\/p>\n<p>Na dolnej cz\u0119\u015bci tej piramidy znajduj\u0105 si\u0119 testy, kt\u00f3re \u0142atwiej pisa\u0107, kt\u00f3re wykonuj\u0105 si\u0119 szybciej i rzadziej daj\u0105 fa\u0142szywe alarmy. Dlatego powinno ich by\u0107 wi\u0119cej, powinny obejmowa\u0107 wi\u0119cej kodu i by\u0107 wykonywane jako pierwsze. Na g\u00f3rze piramidy jest odwrotnie, przez co liczba test\u00f3w integracyjnych i UI powinna by\u0107 zredukowana do absolutnego minimum. Cz\u0142owiek w tym \u0142a\u0144cuchu jest najdro\u017cszym, najwolniejszym i najmniej niezawodnym zasobem, dlatego znajduje si\u0119 na samym ko\u0144cu i wykonuje swoje zadanie tylko wtedy, gdy wcze\u015bniejsze etapy nie wykry\u0142y \u017cadnych wad. Jednak na tych samych zasadach buduje si\u0119 procesy w cz\u0119\u015bciach, kt\u00f3re nie s\u0105 bezpo\u015brednio zwi\u0105zane z testowaniem!<\/p>\n<p>Chcia\u0142bym zaproponowa\u0107 analogi\u0119 w postaci wieloetapowego systemu filtracji wody. Na wej\u015bciu podawana jest brudna woda (zmiany z defektami), a na wyj\u015bciu powinni\u015bmy otrzyma\u0107 czyst\u0105 wod\u0119, woln\u0105 od wszelkich niepo\u017c\u0105danych zanieczyszcze\u0144.<\/p>\n<p><img decoding=\"async\" alt=\"Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj za jej pomoc\u0105 b\u0142\u0119d\u00f3w.\" src=\"\/wp-content\/uploads\/2019\/05\/76b5be8f13d55c16970d67e09767a045.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Wieloetapowy filtr. \u0179r\u00f3d\u0142o: <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>Jak wiadomo, filtry oczyszczaj\u0105ce s\u0105 projektowane w taki spos\u00f3b, aby ka\u017cdy kolejny kaskad m\u00f3g\u0142 oddziela\u0107 coraz drobniejsze frakcje zanieczyszcze\u0144. Przy tym kaskady o wi\u0119kszej grubo\u015bci oczyszczenia maj\u0105 wi\u0119ksz\u0105 przepustowo\u015b\u0107 i ni\u017csze koszty. W naszej analogii oznacza to, \u017ce wej\u015bciowe quality gates maj\u0105 wi\u0119ksz\u0105 wydajno\u015b\u0107, wymagaj\u0105 mniej wysi\u0142ku, aby je uruchomi\u0107 i same w sobie s\u0105 bardziej bezproblemowe w dzia\u0142aniu \u2014 i w\u0142a\u015bnie w takiej kolejno\u015bci s\u0105 one u\u0142o\u017cone. Rola analizy statycznej, kt\u00f3ra, jak teraz rozumiemy, jest w stanie wychwyci\u0107 jedynie najgrubsze wady \u2014 jest rol\u0105 siatki \u201ebrudnej\u201d na samym pocz\u0105tku kaskadu filtr\u00f3w.<\/p>\n<p>Analiza statyczna sama w sobie nie poprawia jako\u015bci ko\u0144cowego produktu, tak jak \u201ebrudnik\u201d nie czyni wody pitn\u0105. Niemniej jednak, w og\u00f3lnej kooperacji z innymi elementami linii produkcyjnej, jej wa\u017cno\u015b\u0107 jest oczywista. Cho\u0107 w wielokaskadowym filtrze wyj\u015bciowe kaskady mog\u0105 potencjalnie uchwyci\u0107 to samo, co kaskady wej\u015bciowe \u2014 oczywiste jest, do jakich konsekwencji doprowadzi pr\u00f3ba polegania tylko na kaskadach drobnego oczyszczania, bez kaskad wej\u015bciowych.<\/p>\n<p>Celem \u201ebrudnika\u201d jest odci\u0105\u017cenie kolejnych kaskad od \u0142apania naprawd\u0119 grubych wad. Na przyk\u0142ad, przynajmniej osoba przeprowadzaj\u0105ca przegl\u0105d kodu nie powinna by\u0107 rozpraszana przez niew\u0142a\u015bciwie sformatowany kod i naruszenia ustalonych norm kodowania (jak zb\u0119dne nawiasy czy zbyt g\u0142\u0119boko zagnie\u017cd\u017cone ga\u0142\u0119zie). B\u0142\u0119dy, takie jak NPE, powinny by\u0107 wykrywane przez testy jednostkowe, ale je\u015bli ju\u017c przed testem analizator wskazuje nam, \u017ce b\u0142\u0105d musi nast\u0105pi\u0107 \u2014 znacznie przyspieszy to jego napraw\u0119.<\/p>\n<p>My\u015bl\u0119, \u017ce teraz jasne jest, dlaczego analiza statyczna nie poprawia jako\u015bci produktu, je\u015bli jest stosowana epizodycznie, i powinna by\u0107 stosowana na sta\u0142e w celu oddzielania zmian z grubymi wadami. Pytanie, czy u\u017cycie analizy statycznej poprawi jako\u015b\u0107 Twojego produktu, jest w zasadzie r\u00f3wnowa\u017cne pytaniu \u201eczy jako\u015b\u0107 wody pitnej, wzi\u0119tej z brudnego zbiornika, poprawi si\u0119, je\u015bli przepu\u015bci si\u0119 j\u0105 przez sitko?\u201d<\/p>\n<h2>Wdro\u017cenie w projekt legacy<\/h2>\n<p>\nWa\u017cne praktyczne pytanie: jak wdro\u017cy\u0107 statyczn\u0105 analiz\u0119 w proces ci\u0105g\u0142ej integracji jako \"quality gate\"? W przypadku test\u00f3w automatycznych wszystko jest jasne: istnieje zestaw test\u00f3w, a niepowodzenie kt\u00f3regokolwiek z nich to wystarczaj\u0105cy pow\u00f3d, aby uzna\u0107, \u017ce budowa nie przesz\u0142a quality gate. Pr\u00f3ba ustalenia gate na podstawie wynik\u00f3w analizy statycznej ko\u0144czy si\u0119 niepowodzeniem: w kodzie legacy jest zbyt wiele ostrze\u017ce\u0144 analizy, nie chcemy ich ca\u0142kowicie ignorowa\u0107, ale tak\u017ce niemo\u017cliwe jest zatrzymanie dostarczania produktu tylko dlatego, \u017ce zawiera ostrze\u017cenia analizatora.<\/p>\n<p>B\u0119d\u0105c stosowana po raz pierwszy, na ka\u017cdym projekcie, analizator wydaje olbrzymi\u0105 ilo\u015b\u0107 ostrze\u017ce\u0144, przyt\u0142aczaj\u0105ca wi\u0119kszo\u015b\u0107 z nich nie ma zwi\u0105zku z prawid\u0142owym dzia\u0142aniem produktu. Niemo\u017cliwe jest od razu poprawienie wszystkich tych uwag, a wiele z nich nie wymaga poprawek. W ko\u0144cu wiemy, \u017ce nasz produkt og\u00f3lnie dzia\u0142a, i to przed wdro\u017ceniem analizy statycznej!<\/p>\n<p>W rezultacie wielu ogranicza si\u0119 do epizodycznego wykorzystania statycznej analizy, lub u\u017cywa jej tylko w trybie informacyjnym, gdy podczas budowy generowany jest po prostu raport analizatora. Jest to r\u00f3wnowa\u017cne braku jakiejkolwiek analizy, poniewa\u017c je\u015bli mamy ju\u017c wiele ostrze\u017ce\u0144, to pojawienie si\u0119 kolejnego (jak powa\u017cne by nie by\u0142o) przy zmianie kodu pozostaje niezauwa\u017cone.<\/p>\n<p>Znane s\u0105 nast\u0119puj\u0105ce sposoby wprowadzenia quality gates:<\/p>\n<ul>\n<li>Ustawienie limitu og\u00f3lnej liczby ostrze\u017ce\u0144 lub liczby ostrze\u017ce\u0144 podzielonej przez liczb\u0119 linii kodu. Dzia\u0142a to s\u0142abo, poniewa\u017c taki gate swobodnie przepuszcza zmiany z nowymi defektami, dop\u00f3ki ich limit nie zostanie przekroczony.<\/li>\n<li>Zbiorcze ignorowanie wszystkich starych ostrze\u017ce\u0144 w kodzie w pewnym momencie oraz odrzucenie budowy przy wyst\u0105pieniu nowych ostrze\u017ce\u0144. Tak\u0105 funkcjonalno\u015b\u0107 oferuje PVS-studio oraz niekt\u00f3re zasoby internetowe, takie jak Codacy. Nie mia\u0142em okazji pracowa\u0107 z PVS-studio, natomiast je\u015bli chodzi o moje do\u015bwiadczenie z Codacy, to ich g\u0142\u00f3wnym problemem jest z\u0142o\u017cono\u015b\u0107 ustalania, kt\u00f3re b\u0142\u0119dy s\u0105 \u201estare\u201d, a kt\u00f3re \u201enowe\u201d \u2014 to do\u015b\u0107 skomplikowany i nie zawsze skuteczny algorytm, zw\u0142aszcza je\u015bli pliki s\u0105 mocno zmieniane lub przemianowywane. Z tego co pami\u0119tam, Codacy m\u00f3g\u0142 pomija\u0107 nowe ostrze\u017cenia w pull requestach, a jednocze\u015bnie nie przepuszcza\u0107 pull request\u00f3w z powodu ostrze\u017ce\u0144, kt\u00f3re nie by\u0142y zwi\u0105zane ze zmianami w kodzie danego PR.<\/li>\n<li>Moim zdaniem, najskuteczniejszym rozwi\u0105zaniem jest opisane w ksi\u0105\u017cce <noindex><a rel=\"nofollow\" href=\"https:\/\/www.amazon.com\/Continuous-Delivery-Deployment-Automation-Addison-Wesley\/dp\/0321601912\">Continuous Delivery<\/a><\/noindex> \u201emetoda z\u0119batego ko\u0142a\u201d (\u201eratcheting\u201d). G\u0142\u00f3wna idea polega na tym, \u017ce w\u0142a\u015bciwo\u015bci\u0105 ka\u017cdej wersji jest liczba ostrze\u017ce\u0144 ze statycznej analizy, a dopuszczalne s\u0105 jedynie takie zmiany, kt\u00f3re nie zwi\u0119kszaj\u0105 og\u00f3lnej liczby ostrze\u017ce\u0144.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Z\u0119bate ko\u0142o<\/h2>\n<p>\nDzia\u0142a to w ten spos\u00f3b:<\/p>\n<ol>\n<li>Na pocz\u0105tkowym etapie realizowane jest zapisywanie w metadanych o wersji liczby ostrze\u017ce\u0144 w kodzie, wykrytych przez analizatory. W ten spos\u00f3b, podczas budowy g\u0142\u00f3wnej ga\u0142\u0119zi, do zarz\u0105dzaj\u0105cego repozytori\u00f3w zapisywana jest nie tylko \u201ewersja 7.0.2\u201d, ale \u201ewersja 7.0.2, zawieraj\u0105ca 100500 ostrze\u017ce\u0144 Checkstyle\u201d. Je\u015bli u\u017cywasz zaawansowanego mened\u017cera repozytori\u00f3w (takiego jak Artifactory), \u0142atwo jest zachowa\u0107 takie metadane o twojej wersji.<\/li>\n<li>Teraz ka\u017cdy pull request podczas budowy por\u00f3wnuje liczb\u0119 ostrze\u017ce\u0144 z tym, jakie liczby znajduj\u0105 si\u0119 w bie\u017c\u0105cej wersji. Je\u015bli PR prowadzi do zwi\u0119kszenia tej liczby, kod nie przechodzi przez wytyczne jako\u015bci w analizie statycznej. Je\u015bli liczba ostrze\u017ce\u0144 maleje lub nie zmienia si\u0119 \u2014 to przechodzi.<\/li>\n<li>Podczas nast\u0119pnej wersji ponownie obliczona liczba ostrze\u017ce\u0144 zostanie zapisana w metadanych wersji.<\/li>\n<\/ol>\n<p>\nTak powoli, ale nieub\u0142aganie (jak podczas pracy mechanizmu z\u0119batego), liczba ostrze\u017ce\u0144 b\u0119dzie d\u0105\u017cy\u0107 do zera. Oczywi\u015bcie, system mo\u017cna oszuka\u0107, wprowadzaj\u0105c nowe ostrze\u017cenie, ale poprawiaj\u0105c cudze. To jest w porz\u0105dku, poniewa\u017c w d\u0142u\u017cszym okresie przynosi efekty: ostrze\u017cenia zwykle s\u0105 poprawiane nie pojedynczo, lecz od razu grup\u0105 okre\u015blonego typu, a wszystkie \u0142atwe do usuni\u0119cia ostrze\u017cenia do\u015b\u0107 szybko zostaj\u0105 wyeliminowane.<\/p>\n<p>Na tym wykresie przedstawiono ca\u0142kowit\u0105 liczb\u0119 ostrze\u017ce\u0144 Checkstyle w ci\u0105gu p\u00f3\u0142 roku pracy takiego \u201emechanizmu z\u0119batego\u201d na <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\">jednym z naszych projekt\u00f3w Open Source<\/a><\/noindex>. Liczba ostrze\u017ce\u0144 zmniejszy\u0142a si\u0119 o rz\u0105d wielko\u015bci, i to w spos\u00f3b naturalny, r\u00f3wnolegle z rozwojem produktu!<\/p>\n<p><img decoding=\"async\" alt=\"Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj za jej pomoc\u0105 b\u0142\u0119d\u00f3w.\" src=\"\/wp-content\/uploads\/2019\/05\/9529bb2fb32187057088e8d2c4203333.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nStosuj\u0119 zmodyfikowan\u0105 wersj\u0119 tej metody, osobno zliczaj\u0105c ostrze\u017cenia w podziale na modu\u0142y projektu i narz\u0119dzia analityczne; generowany przy tym plik YAML z metadanymi o kompilacji wygl\u0105da mniej wi\u0119cej tak:<\/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>\nW ka\u017cdej zaawansowanej systemie CI \u201emechanizm z\u0119baty\u201d mo\u017cna zaimplementowa\u0107 dla dowolnych narz\u0119dzi analizy statycznej, nie polegaj\u0105c na wtyczkach i zewn\u0119trznych narz\u0119dziach. Ka\u017cdy z analityk\u00f3w generuje w\u0142asne raporty w prostym formacie tekstowym lub XML, \u0142atwym do analizy. Pozostaje tylko opisa\u0107 niezb\u0119dn\u0105 logik\u0119 w skrypcie CI. Mo\u017cna zobaczy\u0107, jak to jest zaimplementowane w naszych projektach open source na bazie Jenkins i Artifactory, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/2bass\/blob\/dev\/Jenkinsfile\">tutaj<\/a><\/noindex> lub <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/dev\/Jenkinsfile\">tutaj<\/a><\/noindex>. Oba przyk\u0142ady zale\u017c\u0105 od biblioteki <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/inponomarev\/ratchetlib\">ratchetlib<\/a><\/noindex>: metoda <code>countWarnings()<\/code> w zwyk\u0142y spos\u00f3b zlicza znaczniki xml w plikach generowanych przez Checkstyle i Spotbugs, a <code>compareWarningMaps()<\/code> implementuje ten w\u0142a\u015bnie mechanizm z\u0119baty, sygnalizuj\u0105c b\u0142\u0105d, gdy liczba ostrze\u017ce\u0144 w kt\u00f3rejkolwiek z kategorii wzrasta.<\/p>\n<p>Interesuj\u0105ca realizacja \u00abzawleczki\u00bb mo\u017ce by\u0107 u\u017cyta do analizy ortografii komentarzy, liter tekstowych i dokumentacji za pomoc\u0105 aspell. Jak wiadomo, podczas sprawdzania pisowni nie wszystkie s\u0142owa nieznane standardowemu s\u0142ownikowi s\u0105 b\u0142\u0119dne, mog\u0105 by\u0107 dodane do s\u0142ownika u\u017cytkownika. Je\u015bli uczynimy s\u0142ownik u\u017cytkownika cz\u0119\u015bci\u0105 kodu \u017ar\u00f3d\u0142owego projektu, to brama jako\u015bci w zakresie pisowni mo\u017ce by\u0107 sformu\u0142owana w nast\u0119puj\u0105cy spos\u00f3b: wykonywanie aspell z standardowym i u\u017cytkowniczym s\u0142ownikiem <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/CourseOrchestra\/celesta\/blob\/271dcfc8dc3ad65ac2d1dcaa39b7fd3ea8fb5891\/Jenkinsfile#L36\">nie powinno<\/a><\/noindex> znajdowa\u0107 \u017cadnych b\u0142\u0119d\u00f3w ortograficznych.<\/p>\n<h2>O znaczeniu ustalania wersji analizatora<\/h2>\n<p>\nNa koniec nale\u017cy podkre\u015bli\u0107, \u017ce niezale\u017cnie od sposobu, w jaki wprowadzisz analiz\u0119 do swojego procesu dostarczania, wersja analizatora powinna by\u0107 ustalona. Je\u015bli dopu\u015bcisz do samodzielnej aktualizacji analizatora, podczas budowania kolejnego pull requesta mog\u0105 \u201eujawni\u0107 si\u0119\u201d nowe defekty, kt\u00f3re nie s\u0105 zwi\u0105zane ze zmian\u0105 kodu, ale z tym, \u017ce nowy analizator po prostu potrafi znajdowa\u0107 wi\u0119cej defekt\u00f3w \u2014 a to popsu\u0107 ci proces akceptacji pull request\u00f3w. Aktualizacja analizatora powinna by\u0107 \u015bwiadomym dzia\u0142aniem. Zreszt\u0105, sztywne ustalenie wersji ka\u017cdej komponenty budowy to w og\u00f3le konieczny wym\u00f3g i temat na osobn\u0105 dyskusj\u0119.<\/p>\n<h2>Wnioski<\/h2>\n<p><\/p>\n<ul>\n<li>Analiza statyczna nie znajdzie bug\u00f3w i nie poprawi jako\u015bci twojego produktu w wyniku jednorazowego zastosowania. Pozytywny efekt dla jako\u015bci daje tylko jej sta\u0142e stosowanie w procesie dostarczania.<\/li>\n<li>Znajdowanie bug\u00f3w w og\u00f3le nie jest g\u0142\u00f3wnym zadaniem analizy, przyt\u0142aczaj\u0105ca wi\u0119kszo\u015b\u0107 przydatnych funkcji dost\u0119pna jest w narz\u0119dziach opensource.<\/li>\n<li>Wprowadzaj bramy jako\u015bci na podstawie wynik\u00f3w analizy statycznej ju\u017c na samym pocz\u0105tku procesu dostarczania, korzystaj\u0105c z \u00abzawleczki\u00bb dla kodu legacy.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Linki<\/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. Kudriavtsev: Analiza program\u00f3w: jak zrozumie\u0107, \u017ce jeste\u015b dobrym programist\u0105<\/a><\/noindex> referat o r\u00f3\u017cnych metodach analizy kodu (nie tylko statycznej!)<\/li>\n<\/ol>\n<p>\u0179r\u00f3d\u0142o: <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.1.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\/pl\/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.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\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\/pl\/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\udd47Wprowadzaj analiz\u0119 statyczn\u0105 w proces, a nie szukaj w niej bug\u00f3w | ProHoster","description":"Napisanie tego artyku\u0142u zainspirowa\u0142a mnie du\u017ca liczba materia\u0142\u00f3w na temat analizy statycznej, kt\u00f3re coraz cz\u0119\u015bciej wpada\u0142y mi w oczy.","canonical_url":"https:\/\/prohoster.info\/pl\/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":"pl_PL","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\/pl\/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\/pl\/wp-json\/wp\/v2\/posts\/32848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=32848"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/32848\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/24622"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=32848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=32848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=32848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}