Jarayonda xato izlashdan ko'ra, statik tahlilni amalga oshiring

Meni ushbu maqolani yozishga tobora ko'proq duch kelayotgan statik tahlil bo'yicha ko'plab materiallar ilhomlantirdi. Birinchidan, bu PVS-studio blogi, u Habré-da ochiq kodli loyihalarda o'z vositalari tomonidan topilgan xatolarni ko'rib chiqish bilan faol ravishda o'zini targ'ib qiladi. PVS-studio yaqinda amalga oshirildi Java qo'llab-quvvatlash, va, albatta, IntelliJ IDEA ishlab chiquvchilari, uning o'rnatilgan analizatori bugungi kunda Java uchun eng ilg'or hisoblanadi. uzoqlasha olmadi.

Bunday sharhlarni o'qiyotganda, biz sehrli eliksir haqida gapirayotganimizni his qiladi: tugmani bosing va mana bu - ko'z oldingizda nuqsonlar ro'yxati. Ko'rinishidan, analizatorlar takomillashgani sari, avtomatik ravishda ko'proq xatolar paydo bo'ladi va bu robotlar tomonidan skanerlangan mahsulotlar bizning kuchimizsiz yaxshilanadi va yaxshilanadi.

Ammo sehrli eliksirlar yo'q. Men odatda "bu erda bizning robotimiz topa oladigan narsalar" kabi postlarda muhokama qilinmaydigan narsalar haqida gapirmoqchiman: analizatorlar nima qila olmaydi, dasturiy ta'minotni etkazib berish jarayonida ularning haqiqiy roli va o'rni qanday va ularni qanday qilib to'g'ri amalga oshirish kerak.

Jarayonda xato izlashdan ko'ra, statik tahlilni amalga oshiring
Ratchet (manba: Vikipediya).

Statik analizatorlar hech qachon qila olmaydigan narsa

Amaliy nuqtai nazardan, manba kodini tahlil qilish nima? Biz ba'zi manbalarda ovqatlanamiz va qisqa vaqt ichida (ishlayotgan testlardan ancha qisqaroq) tizimimiz haqida ba'zi ma'lumotlarni olamiz. Asosiy va matematik jihatdan engib bo'lmaydigan cheklov shundaki, biz faqat juda tor ma'lumot sinfini olishimiz mumkin.

Statik tahlil bilan hal qilib bo'lmaydigan muammoning eng mashhur misoli muammoni to'xtatish: bu dasturning dastlabki kodidan uning cheklangan vaqt ichida aylanishi yoki tugashini aniqlaydigan umumiy algoritmni ishlab chiqish mumkin emasligini isbotlovchi teorema. Bu teoremaning kengaytmasi Rays teoremasi, unda aytilishicha, hisoblash funktsiyalarining har qanday notrivial xususiyati uchun ixtiyoriy dasturning bunday xususiyatga ega funktsiyani baholashini aniqlash algoritmik hal etilmaydigan muammodir. Misol uchun, tahlil qilinayotgan dastur, aytaylik, butun sonni kvadratini hisoblaydigan algoritmning amalga oshirilishi yoki yo'qligini har qanday manba kodidan aniqlay oladigan analizator yozish mumkin emas.

Shunday qilib, statik analizatorlarning funksionalligi engib bo'lmaydigan cheklovlarga ega. Statik analizator hech qachon barcha holatlarda, masalan, null bo'ladigan tillarda "null ko'rsatkich istisnosi" paydo bo'lishini aniqlay olmaydi yoki barcha holatlarda "atribut topilmadi" bo'lgan tillarda paydo bo'lishini aniqlay olmaydi. dinamik yozish. Eng ilg'or statik analizator qila oladigan narsa - bu sizning manba kodingiz bilan bog'liq barcha mumkin bo'lgan muammolar orasida, mubolag'asiz, okeandagi tomchi bo'lgan maxsus holatlarni ajratib ko'rsatishdir.

Statik tahlil xatolarni qidirish emas

Yuqoridagilardan xulosa kelib chiqadi: statik tahlil dasturdagi nuqsonlar sonini kamaytirish vositasi emas. Men sizning loyihangizga birinchi marta murojaat qilganingizda, u kodda "qiziqarli" joylarni topadi, lekin, ehtimol, dasturingiz sifatiga ta'sir qiladigan kamchiliklarni topa olmasligini aytishga jur'at etaman.

Analizatorlar tomonidan avtomatik ravishda topilgan nuqsonlarning misollari ta'sirli, ammo unutmasligimiz kerakki, bu misollar katta kod bazalarining katta to'plamini skanerlash orqali topilgan. Xuddi shu printsipga ko'ra, ko'p sonli hisoblarda bir nechta oddiy parollarni sinab ko'rishga qodir bo'lgan krakerlar oxir-oqibat oddiy parolga ega bo'lgan hisoblarni topadilar.

Bu statik tahlildan foydalanmaslik kerakligini anglatadimi? Albatta yo'q! Xuddi shu sababga ko'ra, "oddiy" parollar ro'yxatiga kirish uchun har bir yangi parolni tekshirish kerak.

Statik tahlil xatolarni topishdan ko'ra ko'proq narsani anglatadi

Darhaqiqat, tahlil qilish orqali amaliy hal qilinadigan muammolar ancha kengroqdir. Umuman olganda, statik tahlil - bu ishga tushirilgunga qadar har qanday manba kodlarini tekshirish. Bu yerda siz qilishingiz mumkin bo'lgan ba'zi narsalar:

  • So'zning keng ma'nosida kodlash uslubini tekshirish. Bunga formatlashni tekshirish va boʻsh/qoʻshimcha qavslardan foydalanishni qidirish, qatorlar soni/ siklomatik usulning murakkabligi va boshqalar kabi koʻrsatkichlar boʻyicha chegaralarni oʻrnatish kiradi. Java-da bu vosita Checkstyle, Python-da flake8. Bu sinf dasturlari odatda "linters" deb ataladi.
  • Faqat bajariladigan kodni tahlil qilish mumkin emas. JSON, YAML, XML, .properties kabi resurs fayllari avtomatik ravishda haqiqiyligini tekshirishi mumkin (va kerak!). JSON tuzilmasi ba'zi birlashtirilmagan tirnoqlar tufayli avtomatik Pull Request tekshiruvining dastlabki bosqichida buzilganligini aniqlash testlarni bajarish yoki Run vaqtidan ko'ra yaxshiroq emasmi? Tegishli vositalar mavjud: masalan, YAMLlint, JSONLint.
  • Kompilyatsiya (yoki dinamik dasturlash tillari uchun tahlil qilish) ham statik tahlilning bir turidir. Qoida tariqasida, kompilyatorlar manba kodining sifati bilan bog'liq muammolarni ko'rsatadigan ogohlantirishlarni chiqarishga qodir va ularni e'tiborsiz qoldirmaslik kerak.
  • Ba'zan kompilyatsiya faqat bajariladigan kodni kompilyatsiya qilishdan iborat emas. Misol uchun, agar sizda formatdagi hujjatlar mavjud bo'lsa AsciiDoktor, so'ngra HTML/PDF ishlov beruvchisi AsciiDoctor ga aylantirilganda (Maven plaginlari) ogohlantirishlar berishi mumkin, masalan, buzilgan ichki havolalar haqida. Va bu hujjatlardagi o'zgarishlar bilan Pull so'rovini qabul qilmaslik uchun yaxshi sababdir.
  • Imloni tekshirish ham statik tahlilning bir turi hisoblanadi. Qulaylik yozmoq nafaqat hujjatlarda, balki turli dasturlash tillarida, jumladan C/C++, Java va Python tillarida dasturning manba kodlari (sharhlar va harflar)dagi imloni tekshirishga qodir. Foydalanuvchi interfeysi yoki hujjatlaridagi imlo xatosi ham nuqsondir!
  • Konfiguratsiya testlari (bu nima ekanligini ko'ring bu и bu hisobotlar), ular pytest kabi birlik sinovi ish vaqtida bajarilgan bo'lsa-da, ular aslida statik tahlilning bir turidir, chunki ular bajarilishi davomida manba kodlarini bajarmaydi.

Ko'rib turganingizdek, ushbu ro'yxatdagi xatolarni topish eng kam rol o'ynaydi va qolgan hamma narsa bepul ochiq manba vositalaridan foydalanish orqali mavjud.

Loyihangizda ushbu turdagi statik tahlillardan qaysi biri qo'llanilishi kerak? Albatta, qancha ko'p bo'lsa, shuncha yaxshi! Asosiysi, uni to'g'ri amalga oshirish, bu haqda keyinroq muhokama qilinadi.

Ko'p bosqichli filtr sifatida etkazib berish quvur liniyasi va birinchi kaskadi sifatida statik tahlil

Uzluksiz integratsiya uchun klassik metafora quvur liniyasi (quvur) bo'lib, u orqali o'zgarishlar - manba kodini o'zgartirishdan tortib ishlab chiqarishgacha bo'lgan davrda sodir bo'ladi. Ushbu quvur liniyasi bosqichlarining standart ketma-ketligi quyidagicha ko'rinadi:

  1. statik tahlil
  2. kompilyatsiya
  3. birlik sinovlari
  4. integratsiya testlari
  5. UI testlari
  6. qo'lda tekshirish

Quvurning N-bosqichida rad etilgan o'zgarishlar N+1 bosqichiga tarqalmaydi.

Nima uchun aynan shu tarzda, boshqacha emas? Quvurning sinov qismida sinovchilar taniqli sinov piramidasini taniydilar.

Jarayonda xato izlashdan ko'ra, statik tahlilni amalga oshiring
Sinov piramidasi. Manba: maqola Martin Fauler.

Ushbu piramidaning pastki qismida yozish osonroq, tezroq ishlaydi va noto'g'ri pozitivlikka moyil bo'lmagan testlar mavjud. Shuning uchun, ular ko'proq bo'lishi kerak, ular ko'proq kodni qamrab olishi va birinchi navbatda bajarilishi kerak. Piramidaning yuqori qismida buning aksi to'g'ri, shuning uchun integratsiya va UI testlari soni zaruriy minimal darajaga tushirilishi kerak. Ushbu zanjirdagi odam eng qimmat, eng sekin va ishonchsiz resursdir, shuning uchun u eng oxirida va faqat oldingi bosqichlarda hech qanday nuqson topilmasa, ishni bajaradi. Biroq, xuddi shu printsiplarga ko'ra, quvur liniyasi sinov bilan bevosita bog'liq bo'lmagan qismlarga qurilgan!

Men ko'p bosqichli suv filtrlash tizimi shaklida o'xshashlikni taklif qilmoqchiman. Kirga iflos suv etkazib beriladi (nuqsonlar bilan o'zgarishlar), chiqishda biz toza suvni olishimiz kerak, unda barcha kiruvchi ifloslantiruvchi moddalar yo'q qilinadi.

Jarayonda xato izlashdan ko'ra, statik tahlilni amalga oshiring
Ko'p bosqichli filtr. Manba: Wikimedia Commons

Ma'lumki, tozalash filtrlari har bir keyingi kaskad ifloslantiruvchi moddalarning tobora kichikroq qismini filtrlashi mumkin bo'lgan tarzda ishlab chiqilgan. Shu bilan birga, qo'pol tozalash kaskadlari yuqori o'tkazuvchanlik va arzonroq narxga ega. Bizning o'xshashligimiz bo'yicha, bu kirish sifati eshiklari tezroq, boshlash uchun kamroq kuch talab qiladi va ishlashda oddiyroq ekanligini anglatadi - va ular aynan shu ketma-ketlikda qurilgan. Statik tahlilning roli, biz hozir tushunganimizdek, faqat eng qo'pol nuqsonlarni yo'q qilishga qodir, filtr kaskadining eng boshida panjara - "loy" roli.

Statik tahlilning o'zi yakuniy mahsulot sifatini yaxshilamaydi, xuddi "loy qopqon" suvni ichishga yaroqli qilmaydi. Va shunga qaramay, konveyerning boshqa elementlari bilan birgalikda, uning ahamiyati aniq. Garchi ko'p bosqichli filtrda chiqish bosqichlari kirish bosqichlari kabi hamma narsani potentsial ravishda qamrab olishi mumkin bo'lsa-da, kirish bosqichlarisiz faqat nozik tozalash bosqichlari bilan o'tishga urinish qanday oqibatlarga olib kelishi aniq.

"Loy yig'uvchi" ning maqsadi keyingi kaskadlarni juda qo'pol nuqsonlarni ushlashdan tushirishdir. Misol uchun, hech bo'lmaganda, kodni ko'rib chiquvchini noto'g'ri formatlangan kod va belgilangan kodlash standartlarini buzish (masalan, qo'shimcha qavslar yoki juda chuqur joylashtirilgan novdalar) bilan chalg'itmasligi kerak. NPE kabi xatolar birlik testlari orqali aniqlanishi kerak, ammo agar testdan oldin analizator bizga xato muqarrar ravishda sodir bo'lishi kerakligini ko'rsatsa, bu uni tuzatishni sezilarli darajada tezlashtiradi.

O'ylaymanki, nima uchun statik tahlil mahsulot sifatini yaxshilamaydi, agar u vaqti-vaqti bilan qo'llanilsa va doimiy ravishda qo'pol nuqsonlar bilan o'zgarishlarni filtrlash uchun ishlatilishi kerak. Statik analizatordan foydalanish mahsulotingiz sifatini yaxshilaydimi degan savol taxminan “Agar iflos hovuzdan olingan suv filtrdan o‘tkazilsa, ichimlik sifati yaxshilanadimi?” degan savolga tengdir.

Eski loyihada amalga oshirish

Muhim amaliy savol: “sifat eshigi” sifatida uzluksiz integratsiya jarayoniga statik tahlilni qanday kiritish mumkin? Avtomatik sinovlar bo'lsa, hamma narsa aniq: sinovlar to'plami mavjud, ulardan birortasining muvaffaqiyatsizligi yig'ilish sifat eshigidan o'tmaganiga ishonish uchun etarli sababdir. Statik tahlil natijalariga ko'ra xuddi shu tarzda darvoza o'rnatishga urinish muvaffaqiyatsiz tugadi: eski kodda tahliliy ogohlantirishlar juda ko'p, siz ularni butunlay e'tiborsiz qoldirmoqchi emassiz, lekin etkazib berishni to'xtatish ham mumkin emas. mahsulot faqat analizator ogohlantirishlarini o'z ichiga olganligi uchun.

Birinchi marta foydalanilganda, analizator har qanday loyihada juda ko'p ogohlantirishlarni hosil qiladi, ularning aksariyati mahsulotning to'g'ri ishlashi bilan bog'liq emas. Bu sharhlarning barchasini birdaniga tuzatish mumkin emas va ularning ko'pchiligi kerak emas. Axir, biz bilamizki, mahsulotimiz umuman statik tahlilni joriy etishdan oldin ham ishlaydi!

Natijada, ko'p odamlar o'zlarini statik tahlildan epizodik foydalanish bilan cheklaydilar yoki faqat yig'ish paytida analizator hisoboti chiqarilganda uni faqat axborot rejimida ishlatishadi. Bu hech qanday tahlilning yo'qligiga teng, chunki agar bizda allaqachon juda ko'p ogohlantirishlar bo'lsa, kod o'zgarganda boshqasining paydo bo'lishi (qanchalik jiddiy bo'lmasin) e'tibordan chetda qoladi.

Sifatli eshiklarni joriy etishning quyidagi usullari ma'lum:

  • Ogohlantirishlarning umumiy soniga yoki ogohlantirishlar sonini kod satrlari soniga bo'lish chegarasini o'rnatadi. Bu yaxshi ishlamaydi, chunki bunday darvoza yangi nuqsonlar bilan o'zgarishlarni chegaradan oshib ketguncha erkin o'tkazib yuboradi.
  • Bir nuqtada koddagi barcha eski ogohlantirishlar e'tiborga olinmaganligini tuzatish va yangi ogohlantirishlar paydo bo'lganda tuzilmani bajarmaslik. Ushbu funksiya PVS-studio va ba'zi onlayn resurslar, masalan, Codacy tomonidan taqdim etiladi. Men PVS-studioda ishlash imkoniyatiga ega bo'lmadim, Codacy bilan bo'lgan tajribamga kelsak, ularning asosiy muammosi shundaki, "eski" va "yangi" xato nima ekanligini aniqlash juda murakkab algoritmdir. har doim to'g'ri ishlaydi, ayniqsa fayllar qattiq o'zgartirilgan yoki nomi o'zgartirilgan bo'lsa. Mening xotiramda Codacy tortishish so'rovida yangi ogohlantirishlarni o'tkazib yuborishi va shu bilan birga ushbu PR kodidagi o'zgarishlar bilan bog'liq bo'lmagan ogohlantirishlar tufayli tortib olish so'rovini o'tkazib yubormasligi mumkin.
  • Menimcha, eng samarali yechim kitobda tasvirlangan Har doim yetkazib berish "qo'zg'alish" usuli. Asosiy g'oya shundaki, har bir nashrning xususiyati statik tahlil ogohlantirishlari soni bo'lib, faqat ogohlantirishlarning umumiy sonini ko'paytirmaydigan o'zgarishlarga ruxsat beriladi.

Ratchet

Bu shunday ishlaydi:

  1. Dastlabki bosqichda, analizatorlar tomonidan topilgan koddagi ogohlantirishlar sonining reliz metama'lumotlarida yozuv amalga oshiriladi. Shunday qilib, siz yuqoriga yo'naltirilganingizda, sizning omboringiz menejeri nafaqat "reliz 7.0.2", balki "7.0.2 Checkstyle ogohlantirishlarini o'z ichiga olgan reliz 100500" deb yoziladi. Agar siz rivojlangan ombor boshqaruvchisidan (masalan, Artifactory) foydalanayotgan bo'lsangiz, relizingiz haqidagi bunday metama'lumotlarni saqlash oson.
  2. Endi har bir o'rnatish so'rovi qabul qilingan ogohlantirishlar sonini joriy versiyadagi raqam bilan taqqoslaydi. Agar PR bu raqamning oshishiga olib keladigan bo'lsa, u holda kod statik tahlilda sifat eshigidan o'tmaydi. Agar ogohlantirishlar soni kamaysa yoki o'zgarmasa, u o'tadi.
  3. Keyingi nashrda qayta hisoblangan ogohlantirishlar soni reliz metama'lumotlariga qayta yoziladi.

Shunday qilib, asta-sekin, lekin barqaror ravishda (ratchet kabi) ogohlantirishlar soni nolga tushadi. Albatta, tizimni yangi ogohlantirishni kiritish orqali aldash mumkin, ammo boshqa birovni tuzatish. Bu normal holat, chunki uzoq muddatda bu o'z natijasini beradi: ogohlantirishlar, qoida tariqasida, birma-bir emas, balki ma'lum bir turdagi guruh tomonidan darhol tuzatiladi va barcha osonlik bilan bartaraf etilgan ogohlantirishlar tezda yo'q qilinadi.

Ushbu grafikda bunday "ratchet" ning olti oylik ishlashi uchun Checkstyle ogohlantirishlarining umumiy soni ko'rsatilgan ochiq manba loyihalarimizdan biri. Ogohlantirishlar soni kattalik tartibida kamaydi va bu mahsulotning rivojlanishi bilan parallel ravishda tabiiy ravishda sodir bo'ldi!

Jarayonda xato izlashdan ko'ra, statik tahlilni amalga oshiring

Men ushbu usulning o'zgartirilgan versiyasidan foydalanaman, loyiha moduli va tahlil vositasi bo'yicha ogohlantirishlarni alohida hisoblayman, natijada yig'ish metama'lumotlariga ega YAML fayli paydo bo'ladi, bu quyidagicha ko'rinadi:

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

Har qanday ilg'or CI tizimida plaginlar va uchinchi tomon vositalariga tayanmasdan har qanday statik tahlil vositalari uchun ratchet amalga oshirilishi mumkin. Analizatorlarning har biri o'z hisobotini tahlil qilish oson bo'lgan oddiy matn yoki XML formatida ishlab chiqaradi. CI skriptida faqat kerakli mantiqni ro'yxatdan o'tkazish qoladi. Bu Jenkins va Artifactory asosidagi ochiq manba loyihalarimizda qanday amalga oshirilayotganini ko'rishingiz mumkin shu yerda yoki shu yerda. Ikkala misol ham kutubxonaga bog'liq ratchetlib: usul countWarnings() Checkstyle va Spotbugs tomonidan yaratilgan fayllardagi xml teglarini odatdagi tarzda hisoblaydi va compareWarningMaps() har qanday toifadagi ogohlantirishlar soni ko'tarilganda xatoga yo'l qo'yib, bir xil ratchetni amalga oshiradi.

Sharhlar, matn harflari va hujjatlarni aspell yordamida imlo tahlili uchun qiziqarli ratchet ilovasi mumkin. Ma'lumki, imloni tekshirishda standart lug'atga noma'lum bo'lgan barcha so'zlar noto'g'ri emas, ular foydalanuvchi lug'atiga qo'shilishi mumkin. Agar siz foydalanuvchi lug'atini loyiha manba kodining bir qismiga aylantirsangiz, imlo sifati eshigi quyidagicha shakllantirilishi mumkin: standart va foydalanuvchi lug'ati bilan aspell bajarilishi. bo'lmasligi kerak imlo xatolarini topmang.

Analizator versiyasini tuzatishning ahamiyati haqida

Xulosa qilib aytganda, quyidagilarni ta'kidlash kerak: tahlilni etkazib berish quvuriga qanday kiritganingizdan qat'i nazar, analizatorning versiyasi o'rnatilishi kerak. Agar siz analizatorning o'z-o'zidan yangilanishiga ruxsat bersangiz, keyingi tortishish so'rovini yaratishda kod o'zgarishi bilan bog'liq bo'lmagan yangi nuqsonlar "paydo bo'lishi" mumkin, lekin yangi analizator shunchaki ko'proq nuqsonlarni topishi mumkinligi bilan bog'liq - va bu tortishish so'rovlarini qabul qilish jarayonini buzadi. Analizatorni yangilash ongli harakat bo'lishi kerak. Biroq, har bir montaj komponentining versiyasini qattiq tuzatish umuman zaruriy talab va alohida muhokama uchun mavzudir.

topilmalar

  • Statik tahlil siz uchun xato topmaydi va bitta dastur natijasida mahsulotingiz sifatini yaxshilamaydi. Sifatga yagona ijobiy ta'sir - etkazib berish jarayonida doimiy foydalanish.
  • Xatolarni topish umuman tahlilning asosiy vazifasi emas, foydali funktsiyalarning katta qismi ochiq manba vositalarida mavjud.
  • Etkazib berish quvurining birinchi bosqichida statik tahlil natijalariga ko'ra, eski kod uchun ratchet yordamida sifatli eshiklarni amalga oshiring.

Manbalar

  1. Har doim yetkazib berish
  2. A. Kudryavtsev: Dastur tahlili: yaxshi dasturchi ekanligingizni qanday tushunish mumkin kodni tahlil qilishning turli usullari haqida hisobot (nafaqat statik!)

Manba: www.habr.com

a Izoh qo'shish