Səhvləri tapmaq üçün istifadə etməkdənsə, prosesə statik təhlili tətbiq edin

Bu yazını yazmağa məni getdikcə daha çox diqqətimi çəkən statik analizlə bağlı materialların çoxluğu vadar etdi. Birincisi, bu PVS-studio bloqu, açıq mənbəli layihələrdə alətləri tərəfindən tapılan səhvlərin nəzərdən keçirilməsinin köməyi ilə özünü Habré-də fəal şəkildə təbliğ edir. Bu yaxınlarda PVS-studio həyata keçirildi Java dəstəyi, və əlbəttə ki, daxili analizatoru bu gün Java üçün ən təkmil olan IntelliJ IDEA-nın tərtibatçıları, uzaq qala bilməzdi.

Bu cür rəyləri oxuyarkən, sehrli bir eliksirdən bəhs etdiyimizi hiss edirsiniz: düyməni basın və budur - gözünüzün qarşısında qüsurların siyahısı. Görünür ki, analizatorlar təkmilləşdikcə, getdikcə daha çox səhv avtomatik olaraq tapılacaq və bu robotlar tərəfindən skan edilən məhsullar bizim tərəfimizdən heç bir səy göstərmədən daha yaxşı və daha yaxşı olacaq.

Ancaq sehrli eliksirlər yoxdur. “Budur bizim robotumuzun tapa biləcəyi şeylər” kimi yazılarda ümumiyyətlə danışılmayan şeylər haqqında danışmaq istərdim: analizatorlar nəyi edə bilməz, proqram təminatının çatdırılma prosesində onların real rolu və yeri nədir və onları necə düzgün həyata keçirmək olar. .

Səhvləri tapmaq üçün istifadə etməkdənsə, prosesə statik təhlili tətbiq edin
Ratchet (mənbə: Vikipediya).

Statik analizatorların heç vaxt edə bilməyəcəyi şeylər

Praktiki baxımdan mənbə kodu təhlili nədir? Biz bəzi mənbə kodunu giriş kimi təqdim edirik və çıxış kimi qısa müddətdə (işləyən testlərdən daha qısa müddətdə) sistemimiz haqqında bəzi məlumatlar əldə edirik. Əsas və riyazi cəhətdən keçilməz məhdudiyyət ondan ibarətdir ki, biz bu yolla yalnız kifayət qədər dar bir məlumat sinfini əldə edə bilərik.

Statik analizdən istifadə etməklə həll edilə bilməyən problemin ən məşhur nümunəsidir bağlanma problemi: Bu, proqramın mənbə kodundan onun sonlu bir zamanda dövrələnməsini və ya sonlanacağını müəyyən edə bilən ümumi alqoritmin işlənib hazırlanmasının qeyri-mümkün olduğunu sübut edən bir teoremdir. Bu teoremin uzantısıdır Rays teoremi, hansı ki, hesablana bilən funksiyaların hər hansı qeyri-trivial xassələri üçün ixtiyari proqramın belə xassə ilə funksiyanı qiymətləndirib-qiymətləndirmədiyini müəyyən etmək alqoritmik cəhətdən həll edilə bilməyən bir problem olduğunu bildirir. Məsələn, hər hansı mənbə kodundan təhlil edilən proqramın, məsələn, tam ədədin kvadratını hesablayan alqoritmin icrası olub-olmadığını müəyyən edə bilən analizator yazmaq mümkün deyil.

Beləliklə, statik analizatorların funksionallığı keçilməz məhdudiyyətlərə malikdir. Statik analizator heç vaxt bütün hallarda, məsələn, null dəyərinə imkan verən dillərdə "null göstərici istisnasının" baş verməsi kimi şeyləri aşkar edə bilməyəcək və ya bütün hallarda " atribut tapılmadı" dinamik şəkildə yazılmış dillərdə. Ən qabaqcıl statik analizatorun edə biləcəyi yeganə şey, mənbə kodunuzla bağlı bütün mümkün problemlər arasında, mübaliğəsiz, okeanda bir damla olan xüsusi halları vurğulamaqdır.

Statik analiz səhvləri tapmaqdan ibarət deyil

Yuxarıda deyilənlərdən belə nəticə çıxır: statik analiz proqramdakı qüsurların sayını azaltmaq vasitəsi deyil. Mən deməyə cəsarət edərdim: layihənizə ilk dəfə müraciət etdikdə kodda “maraqlı” yerlər tapacaq, lakin çox güman ki, proqramınızın keyfiyyətinə təsir edən heç bir qüsur tapmayacaq.

Analizatorlar tərəfindən avtomatik aşkar edilən qüsurların nümunələri təsir edicidir, lakin unutmamalıyıq ki, bu nümunələr böyük kod bazalarının böyük dəstini skan etməklə tapılıb. Eyni prinsipə əsasən, çox sayda hesabda bir neçə sadə parolu sınamaq imkanı olan hakerlər sonda sadə parolu olan hesabları tapırlar.

Bu o deməkdirmi ki, statik analizdən istifadə etmək olmaz? Əlbəttə yox! Və eyni səbəbdən, hər bir yeni parolun "sadə" parolların dayanma siyahısına daxil olduğundan əmin olmaq üçün yoxlamağa dəyər.

Statik analiz səhvləri tapmaqdan daha çox şeydir

Əslində təhlillə praktiki olaraq həll edilən problemlər daha genişdir. Axı, ümumiyyətlə, statik təhlil mənbə kodlarının işə salınmazdan əvvəl həyata keçirilən hər hansı bir yoxlanmasıdır. Siz edə biləcəyiniz bəzi şeylər bunlardır:

  • Sözün geniş mənasında kodlaşdırma üslubunun yoxlanılması. Buraya həm formatlaşdırmanın yoxlanılması, həm boş/əlavə mötərizələrin istifadəsinin axtarılması, sətirlərin sayı/metodun siklomatik mürəkkəbliyi və s. kimi metriklər üzrə hədlərin təyin edilməsi daxildir - kodun oxunaqlılığına və davamlılığına potensial olaraq mane olan hər şey. Java-da belə bir alət Checkstyle, Python-da flake8-dir. Bu sinifin proqramları adətən “linters” adlanır.
  • Yalnız icra olunan kod təhlil edilə bilməz. JSON, YAML, XML, .properties kimi resurs faylları etibarlılıq üçün avtomatik olaraq yoxlana bilər (və olmalıdır!). Axı, JSON strukturunun bəzi qoşalaşdırılmamış kotirovkalara görə pozulduğunu öyrənmək daha yaxşıdır ki, testin icrası və ya iş vaxtı zamanı yox, avtomatik Pull Request yoxlanışının ilkin mərhələsində? Müvafiq alətlər mövcuddur: məs. YAMLlint, JSONLint.
  • Kompilyasiya (və ya dinamik proqramlaşdırma dilləri üçün təhlil) həm də statik analizin bir növüdür. Ümumiyyətlə, kompilyatorlar mənbə kodu keyfiyyəti ilə bağlı problemləri göstərən xəbərdarlıqlar yarada bilirlər və buna məhəl qoyulmamalıdır.
  • Bəzən kompilyasiya sadəcə icra edilə bilən kodu tərtib etməkdən daha çox şeydir. Məsələn, formatda sənədləriniz varsa AsciiDoktor, sonra onu HTML/PDF-yə çevirərkən AsciiDoctor işləyicisi (Maven plagini) xəbərdarlıqlar verə bilər, məsələn, pozulmuş daxili keçidlər haqqında. Və bu, sənəd dəyişiklikləri ilə Pull Sorğunu qəbul etməmək üçün yaxşı səbəbdir.
  • Orfoqrafiya yoxlaması da statik analizin bir növüdür. Utility yazmaq yalnız sənədlərdə deyil, həm də C/C++, Java və Python daxil olmaqla müxtəlif proqramlaşdırma dillərində proqramın mənbə kodlarında (şərhlər və hərflər) orfoqrafiyanı yoxlaya bilir. İstifadəçi interfeysində və ya sənədlərdə olan orfoqrafik xəta da qüsurdur!
  • Konfiqurasiya testləri (onların nə olduğu haqqında - baxın. bu и bu hesabatlar), pytest kimi vahid test iş vaxtında icra olunsa da, icrası zamanı mənbə kodlarını yerinə yetirmədiyi üçün əslində həm də statik analizin bir növüdür.

Gördüyünüz kimi, bu siyahıda səhvləri axtarmaq ən az vacib rol oynayır və qalan hər şey pulsuz açıq mənbə alətlərindən istifadə etməklə mümkündür.

Layihənizdə bu statik analiz növlərindən hansını istifadə etməlisiniz? Əlbəttə ki, nə qədər çox olsa, bir o qədər yaxşıdır! Əsas odur ki, onu düzgün həyata keçirək, bundan sonra da müzakirə olunacaq.

Çox mərhələli filtr kimi çatdırılma boru kəməri və ilk mərhələ kimi statik analiz

Davamlı inteqrasiya üçün klassik metafora mənbə kodunun dəyişməsindən tutmuş istehsala qədər dəyişikliklərin baş verdiyi boru kəməridir. Bu boru kəmərindəki standart mərhələlər ardıcıllığı belə görünür:

  1. statik analiz
  2. kompilyasiya
  3. vahid testləri
  4. inteqrasiya testləri
  5. UI testləri
  6. əllə yoxlama

Boru kəmərinin N-ci mərhələsində rədd edilən dəyişikliklər N+1 mərhələsinə keçirilmir.

Niyə məhz bu şəkildə, başqa cür deyil? Boru kəmərinin sınaq hissəsində sınaqçılar tanınmış sınaq piramidasını tanıyacaqlar.

Səhvləri tapmaq üçün istifadə etməkdənsə, prosesə statik təhlili tətbiq edin
Test piramidası. Mənbə: məqalə Martin Fowler.

Bu piramidanın aşağısında yazılması daha asan, yerinə yetirilməsi daha sürətli və uğursuzluğa meyilli olmayan testlər var. Buna görə də, onların sayı daha çox olmalıdır, daha çox kodu əhatə etməli və əvvəlcə icra edilməlidir. Piramidanın yuxarı hissəsində bunun əksi doğrudur, buna görə inteqrasiya və UI testlərinin sayı lazımi minimuma endirilməlidir. Bu zəncirdəki şəxs ən bahalı, yavaş və etibarsız resursdur, buna görə də o, ən sonundadır və yalnız əvvəlki mərhələlərdə heç bir qüsur tapmadıqda işi yerinə yetirir. Bununla belə, sınaq ilə birbaşa əlaqəli olmayan hissələrdə boru kəmərinin tikintisi üçün eyni prinsiplər istifadə olunur!

Çox mərhələli su filtrasiya sistemi şəklində bir bənzətmə təklif etmək istərdim. Çirkli su (qüsurlu dəyişikliklər) girişə verilir, çıxışda bütün arzuolunmaz çirkləndiricilərin aradan qaldırıldığı təmiz su almalıyıq.

Səhvləri tapmaq üçün istifadə etməkdənsə, prosesə statik təhlili tətbiq edin
Çox mərhələli filtr. Mənbə: Wikimedia Commons

Bildiyiniz kimi, təmizləyici filtrlər elə qurulmuşdur ki, hər bir sonrakı kaskad çirkləndiricilərin getdikcə daha incə bir hissəsini süzə bilsin. Eyni zamanda, daha qaba təmizləmə kaskadları daha yüksək məhsuldarlığa və aşağı qiymətə malikdir. Bizim bənzətməmizdə bu, giriş keyfiyyət qapılarının daha sürətli olması, işə başlamaq üçün daha az səy tələb etməsi və istismarda özləri daha iddiasız olması deməkdir - və bu, onların qurulduğu ardıcıllıqdır. İndi başa düşdüyümüz kimi, yalnız ən kobud qüsurları aradan qaldırmağa qadir olan statik analizin rolu filtr kaskadının ən başlanğıcında "palçıq" şəbəkəsinin roludur.

Statik analiz öz-özünə son məhsulun keyfiyyətini yaxşılaşdırmır, necə ki, “palçıq filtri” suyu içməli etmir. Bununla belə, kəmərin digər elementləri ilə birlikdə onun əhəmiyyəti göz qabağındadır. Çoxmərhələli filtrdə çıxış mərhələləri potensial olaraq giriş mərhələlərinin etdiyi hər şeyi ələ keçirməyə qadir olsa da, giriş mərhələləri olmadan yalnız incə təmizləmə mərhələləri ilə məşğul olmaq cəhdinin hansı nəticələrinin olacağı aydındır.

"Palçıq tələsinin" məqsədi sonrakı kaskadları çox kobud qüsurları tutmaqdan azad etməkdir. Məsələn, ən azı, kodu nəzərdən keçirən şəxs səhv formatlanmış kod və müəyyən edilmiş kodlaşdırma standartlarının pozulması (məsələn, əlavə mötərizələr və ya çox dərin daxili budaqlar) ilə diqqətini yayındırmamalıdır. NPE kimi səhvlər vahid testləri ilə tutulmalıdır, lakin testdən əvvəl analizator bizə bir səhvin baş verəcəyini bildirsə, bu, onun düzəldilməsini əhəmiyyətli dərəcədə sürətləndirəcək.

İnanıram ki, niyə statik analizin bəzən istifadə edildiyi təqdirdə məhsulun keyfiyyətini yaxşılaşdırmadığı və kobud qüsurlarla dəyişiklikləri süzgəcdən keçirmək üçün daim istifadə edilməli olduğu aydındır. Statik analizatordan istifadənin məhsulunuzun keyfiyyətini artırıb-yaxşılamaması sualı təqribən “Çirkli gölməçədən götürülən su süzgəcdən keçirilərsə, onun içməli keyfiyyəti yaxşılaşacaqmı?” sualına bərabərdir.

Köhnə bir layihəyə tətbiq

Vacib praktiki sual: “keyfiyyət qapısı” kimi davamlı inteqrasiya prosesinə statik təhlili necə tətbiq etmək olar? Avtomatik sınaqlar vəziyyətində hər şey göz qabağındadır: bir sıra testlər var, onlardan hər hansı birinin uğursuzluğu montajın keyfiyyət qapısından keçmədiyinə inanmaq üçün kifayət qədər səbəbdir. Statik təhlilin nəticələrinə əsasən eyni şəkildə qapını quraşdırmaq cəhdi uğursuzluqla nəticələnir: köhnə kodda çoxlu analiz xəbərdarlıqları var, siz onları tamamilə gözardı etmək istəmirsiniz, lakin məhsulun göndərilməsini dayandırmaq da mümkün deyil. sadəcə ona görə ki, onun tərkibində analizator xəbərdarlıqları var.

İlk dəfə istifadə edildikdə, analizator hər hansı bir layihədə çox sayda xəbərdarlıq istehsal edir, onların böyük əksəriyyəti məhsulun düzgün işləməsi ilə əlaqəli deyil. Bütün bu şərhləri bir anda düzəltmək mümkün deyil və çoxları lazım deyil. Axı biz bilirik ki, bütövlükdə məhsulumuz işləyir, hətta statik analiz tətbiq etməzdən əvvəl!

Nəticədə, bir çoxları statik analizin təsadüfi istifadəsi ilə məhdudlaşır və ya sadəcə montaj zamanı analizator hesabatı verildikdə onu yalnız məlumat rejimində istifadə edirlər. Bu, heç bir təhlilin olmamasına bərabərdir, çünki artıq bir çox xəbərdarlıqlarımız varsa, kodu dəyişdirərkən başqasının (nə qədər ciddi olmasından asılı olmayaraq) baş verməsi diqqətdən kənarda qalır.

Keyfiyyətli qapıların tətbiqi üçün aşağıdakı üsullar məlumdur:

  • Xəbərdarlıqların ümumi sayına və ya kod sətirlərinin sayına bölünən xəbərdarlıqların sayına məhdudiyyət qoyulması. Bu, zəif işləyir, çünki belə bir qapı yeni qüsurlarla dəyişikliklərin sərbəst şəkildə keçməsinə imkan verir, çünki onların həddi keçmir.
  • Müəyyən bir anda koddakı bütün köhnə xəbərdarlıqların nəzərə alınmadığını düzəltmək və yeni xəbərdarlıqlar baş verdikdə qurmaqdan imtina etmək. Bu funksionallıq PVS-studio və bəzi onlayn resurslar, məsələn, Codacy tərəfindən təmin edilir. PVS-studioda işləmək imkanım olmadı, Codacy ilə təcrübəmə gəldikdə, onların əsas problemi odur ki, "köhnə" və "yeni" xətanın nə olduğunu müəyyən etmək həmişə işləməyən olduqca mürəkkəb bir alqoritmdir. xüsusilə faylların ciddi şəkildə dəyişdirildiyi və ya adı dəyişdirildiyi təqdirdə. Təcrübəmə görə, Codacy pull sorğusunda yeni xəbərdarlıqlara məhəl qoymur, eyni zamanda verilmiş PR kodundakı dəyişikliklərlə əlaqəli olmayan xəbərdarlıqlara görə çəkmə sorğusunu keçirmir.
  • Məncə, ən təsirli həll kitabda təsvir olunandır Davamlı Çatdırılma “atlama üsulu”. Əsas ideya ondan ibarətdir ki, statik analiz xəbərdarlıqlarının sayı hər buraxılışın mülkiyyətidir və yalnız xəbərdarlıqların ümumi sayını artırmayan dəyişikliklərə icazə verilir.

Ratchet

Bu şəkildə işləyir:

  1. İlkin mərhələdə analizatorlar tərəfindən tapılan koddakı xəbərdarlıqların sayının buraxılması haqqında metaməlumatlarda qeyd aparılır. Beləliklə, siz yuxarıya doğru qurduğunuz zaman depo meneceriniz təkcə “7.0.2 buraxılışını” deyil, “7.0.2 yoxlama tərzi xəbərdarlığını ehtiva edən buraxılış 100500” yazır. Qabaqcıl depo menecerindən (məsələn, Artifactory) istifadə edirsinizsə, buraxılışınız haqqında bu cür metadata saxlamaq asandır.
  2. İndi hər çəkmə sorğusu qurulduqda yaranan xəbərdarlıqların sayını cari buraxılışda mövcud olan xəbərdarlıqların sayı ilə müqayisə edir. Əgər PR bu rəqəmin artmasına gətirib çıxarırsa, o zaman kod statik analiz üçün keyfiyyət qapısından keçmir. Xəbərdarlıqların sayı azalırsa və ya dəyişməzsə, o zaman keçir.
  3. Növbəti buraxılışda xəbərdarlıqların yenidən hesablanmış sayı buraxılış metadatasında yenidən qeyd olunacaq.

Beləliklə, yavaş-yavaş, lakin davamlı olaraq (məsələn, cırcır işlədiyi zaman), xəbərdarlıqların sayı sıfıra enəcək. Təbii ki, sistem yeni xəbərdarlıq təqdim etməklə, lakin başqasınınkini düzəltməklə aldadıla bilər. Bu normaldır, çünki uzun məsafədə nəticə verir: xəbərdarlıqlar, bir qayda olaraq, fərdi olaraq deyil, müəyyən bir növ qrupda dərhal düzəldilir və bütün asanlıqla çıxarıla bilən xəbərdarlıqlar olduqca tez aradan qaldırılır.

Bu qrafikdə belə bir “ratchet”in altı aylıq işləməsi üçün Checkstyle xəbərdarlıqlarının ümumi sayı göstərilir OpenSource layihələrimizdən biridir. Xəbərdarlıqların sayı böyük ölçüdə azaldı və bu, məhsulun inkişafı ilə paralel olaraq təbii olaraq baş verdi!

Səhvləri tapmaq üçün istifadə etməkdənsə, prosesə statik təhlili tətbiq edin

Mən layihə modulu və təhlil aləti ilə xəbərdarlıqları ayrıca hesablayaraq, bu metodun dəyişdirilmiş versiyasından istifadə edirəm, nəticədə bu kimi görünən metaməlumatları olan YAML faylı yaranır:

celesta-sql:
  checkstyle: 434
  spotbugs: 45
celesta-core:
  checkstyle: 206
  spotbugs: 13
celesta-maven-plugin:
  checkstyle: 19
  spotbugs: 0
celesta-unit:
  checkstyle: 0
  spotbugs: 0

İstənilən qabaqcıl CI sistemində plaginlərə və üçüncü tərəf alətlərinə etibar etmədən hər hansı statik analiz alətləri üçün ratchet tətbiq oluna bilər. Hər bir analizator öz hesabatını sadə mətndə və ya təhlil etmək asan olan XML formatında hazırlayır. Yalnız CI skriptində lazımi məntiqi yazmaq qalır. Bunun necə həyata keçirildiyini Jenkins və Artifactory əsasında açıq mənbə layihələrimizdə görə bilərsiniz burada və ya burada. Hər iki nümunə kitabxanadan asılıdır ratchetlib: üsul countWarnings() Checkstyle və Spotbugs tərəfindən adi şəkildə yaradılan fayllarda xml teqlərini hesablayır və compareWarningMaps() kateqoriyalardan hər hansı birində xəbərdarlıqların sayı artdıqda xəta atır, eyni ratchet tətbiq edir.

Aspell-dən istifadə edərək şərhlərin, mətn hərflərinin və sənədlərin orfoqrafiyasını təhlil etmək üçün "ratchet" in maraqlı tətbiqi mümkündür. Bildiyiniz kimi, orfoqrafiya yoxlanarkən standart lüğətə məlum olmayan bütün sözlər səhv deyil, onları istifadəçi lüğətinə əlavə etmək olar. Layihənin mənbə kodunun xüsusi lüğət hissəsini düzəltsəniz, orfoqrafiya keyfiyyət qapısı bu şəkildə tərtib edilə bilər: standart və xüsusi lüğət ilə aspell işlədir olmamalıdır heç bir orfoqrafik səhv tapma.

Analizator versiyasını düzəltməyin vacibliyi haqqında

Yekun olaraq qeyd etmək lazım olan məqam ondan ibarətdir ki, çatdırılma boru kəmərinizdə təhlili necə həyata keçirməyinizdən asılı olmayaraq, analizatorun versiyası düzəldilməlidir. Analizatorun kortəbii yeniləməsinə icazə versəniz, növbəti çəkmə sorğusunu yığarkən, kod dəyişiklikləri ilə əlaqəli olmayan, lakin yeni analizatorun sadəcə daha çox qüsur tapa bilməsi ilə əlaqəli yeni qüsurlar "açılacaq" - və bu, çəkmə sorğularını qəbul etmə prosesinizi pozacaq. Analizatorun təkmilləşdirilməsi şüurlu bir hərəkət olmalıdır. Bununla belə, hər bir montaj komponentinin versiyasının sərt şəkildə fiksasiyası ümumiyyətlə zəruri tələb və ayrıca müzakirə mövzusudur.

Tapıntılar

  • Statik analiz sizin üçün səhvlər tapmayacaq və bir tətbiq nəticəsində məhsulunuzun keyfiyyətini artırmayacaq. Keyfiyyətə müsbət təsir yalnız çatdırılma prosesində onun daimi istifadəsi ilə əldə edilə bilər.
  • Səhvləri tapmaq ümumiyyətlə təhlilin əsas vəzifəsi deyil; faydalı funksiyaların böyük əksəriyyəti açıq mənbə alətlərində mövcuddur.
  • Köhnə kod üçün "ratchet" istifadə edərək, çatdırılma boru kəmərinin ilk mərhələsində statik təhlilin nəticələrinə əsasən keyfiyyətli qapıları həyata keçirin.

References

  1. Davamlı Çatdırılma
  2. A. Kudryavtsev: Proqram təhlili: yaxşı bir proqramçı olduğunuzu necə başa düşmək olar kod analizinin müxtəlif üsulları haqqında hesabat (yalnız statik deyil!)

Mənbə: www.habr.com

Добавить комментарий