4 сая мөр Python кодын шивж шалгах зам. 2-р хэсэг

Өнөөдөр бид Dropbox хэдэн сая мөр Python кодын төрлийн хяналтыг хэрхэн зохион байгуулсан тухай материалын орчуулгын хоёрдугаар хэсгийг нийтэлж байна.

4 сая мөр Python кодын шивж шалгах зам. 2-р хэсэг

Нэгдүгээр хэсгийг уншина уу

Албан ёсны төрлийн дэмжлэг (PEP 484)

Бид 2014 оны Hack Week-ийн үеэр Dropbox дээр mypy-тэй анхны ноцтой туршилтуудаа хийсэн. Hack Week бол Dropbox-оос зохион байгуулдаг нэг долоо хоногийн арга хэмжээ юм. Энэ хугацаанд ажилчид хүссэн зүйл дээрээ ажиллах боломжтой! Dropbox-ын хамгийн алдартай технологийн төслүүдийн зарим нь иймэрхүү арга хэмжээнүүдээс эхэлдэг. Энэхүү туршилтын үр дүнд төсөл өргөн хэрэглээнд хараахан бэлэн болоогүй байгаа хэдий ч mypy ирээдүйтэй харагдаж байна гэж бид дүгнэсэн.

Тухайн үед Python төрлийн дохиоллын системийг стандартчилах санаа агаарт байсан. Миний хэлсэнчлэн, Python 3.0-аас хойш функцүүдэд төрлийн тэмдэглэгээг ашиглах боломжтой байсан ч эдгээр нь тодорхой синтакс, семантикгүйгээр дурын илэрхийллүүд байсан. Хөтөлбөрийг хэрэгжүүлэх явцад эдгээр тэмдэглэгээг ихэвчлэн үл тоомсорлодог. Hack Week-ийн дараа бид семантикийг стандартчилахаар ажиллаж эхэлсэн. Энэ ажил нь гарч ирэхэд хүргэсэн PEP 484 (Гуидо ван Россум, Лукаш Ланга бид хоёр энэ баримт бичигт хамтран ажилласан).

Бидний сэдлийг хоёр талаас нь харж болно. Нэгдүгээрт, бид Python-ын экосистем бүхэлдээ төрлийн зөвлөмжийг ашиглах нийтлэг арга барилыг хэрэгжүүлж чадна гэж найдаж байсан (Python-д "төрлийн тайлбар"-тай дүйцэхүйц нэр томъёог ашигладаг). Энэ нь болзошгүй эрсдэлийг харгалзан үзэхэд бие биедээ үл нийцэх олон арга хэрэглэхээс илүү дээр байх болно. Хоёрдугаарт, бид Python нийгэмлэгийн олон гишүүдтэй төрлийн тэмдэглэгээний механизмын талаар нээлттэй ярилцахыг хүссэн. Энэхүү хүсэл нь Python програмистуудын өргөн хүрээний нүдэн дээр бид хэлний үндсэн санаанаасаа "урвагчид" шиг харагдахыг хүсэхгүй байгаатай холбоотой юм. Энэ нь "нугас бичих" гэж нэрлэгддэг динамикаар бичигдсэн хэл юм. Нийгэмд хамгийн эхэнд статик бичих санааны талаархи зарим сэжигтэй хандлага гарч ирж чадахгүй байв. Гэвч статик бичих нь заавал байх албагүй нь тодорхой болсны дараа (мөн хүмүүс энэ нь үнэхээр хэрэгтэй гэдгийг ойлгосны дараа) энэ мэдрэмж аажмаар буурчээ.

Эцэст нь батлагдсан төрлийн зөвлөмжийн синтакс нь тухайн үед mypy-ийн дэмждэг байсантай маш төстэй байв. PEP 484 нь Python 3.5-тай 2015 онд гарсан. Python нь динамикаар бичдэг хэл байхаа больсон. Би энэ үйл явдлыг Python-ийн түүхэн дэх чухал үйл явдал гэж үзэх дуртай.

Шилжилтийн эхлэл

2015 оны сүүлээр Dropbox mypy дээр ажиллах гурван хүний ​​бүрэлдэхүүнтэй багийг байгуулсан. Тэдэнд Гуидо ван Россум, Грег Прайс, Дэвид Фишер нар багтсан. Энэ мөчөөс эхлэн нөхцөл байдал маш хурдан хөгжиж эхлэв. Mypy-ийн өсөлтөд саад болж буй хамгийн эхний зүйл бол гүйцэтгэл юм. Би дээр дурдсанчлан, төслийн эхний өдрүүдэд mypy-ийн хэрэгжилтийг Си хэл рүү хөрвүүлэх талаар бодож байсан ч энэ санаа одоохондоо жагсаалтаас тасарчээ. Бид CPython орчуулагч ашиглан системийг ажиллуулахад гацсан бөгөөд энэ нь mypy гэх мэт хэрэгслүүдэд хангалттай хурдан биш юм. (PyPy төсөл, JIT хөрвүүлэгчтэй Python-ийн өөр хувилбар нь бидэнд тусалсангүй.)

Аз болоход, алгоритмын зарим сайжруулалт энд бидэнд тусалсан. Эхний хүчирхэг "хурдасгуур" нь шаталсан шалгалтыг хэрэгжүүлэх явдал байв. Энэхүү сайжруулалтын цаад санаа нь энгийн байсан: хэрэв mypy-ийн өмнөх ажиллуулснаас хойш модулийн бүх хамаарал өөрчлөгдөөгүй бол бид хамааралтай ажиллахдаа өмнөх ажиллуулах явцад хадгалсан өгөгдлийг ашиглаж болно. Бид зөвхөн өөрчилсөн файлууд болон тэдгээрээс хамааралтай файлууд дээр төрлийн шалгалт хийх шаардлагатай болсон. Mypy бүр цаашлаад: хэрэв модулийн гадаад интерфейс өөрчлөгдөөгүй бол mypy энэ модулийг импортолсон бусад модулиудыг дахин шалгах шаардлагагүй гэж үзсэн.

Өсөн нэмэгдэж буй шалгах нь одоо байгаа кодыг их хэмжээгээр тэмдэглэхэд бидэнд маш их тусалсан. Гол нь энэ процесс нь ихэвчлэн mypy-ийн олон давталттай гүйлтүүдийг агуулж байдаг тул тэмдэглэгээг кодод аажмаар нэмж, аажмаар сайжруулдаг. mypy-ийн эхний гүйлт нь маш удаан байсан, учир нь үүнийг шалгах шаардлагатай олон хамааралтай байсан. Дараа нь нөхцөл байдлыг сайжруулахын тулд бид алсаас кэш хийх механизмыг хэрэгжүүлсэн. Хэрэв mypy нь локал кэш хуучирсан болохыг илрүүлбэл төвлөрсөн агуулахаас бүх кодын сангийн одоогийн кэшийн агшин зургийг татаж авдаг. Дараа нь энэ хормын хувилбарыг ашиглан шаталсан шалгалтыг хийнэ. Энэ нь биднийг mypy-ийн гүйцэтгэлийг нэмэгдүүлэх нэг том алхам хийлээ.

Энэ бол Dropbox-т төрөл шалгах хурдан бөгөөд жам ёсны хэрэгжсэн үе байсан. 2016 оны эцэс гэхэд бид 420000 орчим мөрийн Python кодтой болсон бөгөөд төрлийн тайлбартай. Олон хэрэглэгчид төрөл шалгах талаар урам зоригтой байсан. Илүү олон хөгжүүлэлтийн багууд Dropbox mypy ашигладаг болсон.

Тэр үед бүх зүйл сайхан харагдаж байсан ч бидэнд хийх зүйл их байсан. Төслийн тулгамдсан асуудлуудыг тодорхойлох, хамгийн түрүүнд ямар асуудлыг шийдвэрлэх шаардлагатайг ойлгохын тулд бид хэрэглэгчийн дотоод судалгааг үе үе хийж эхэлсэн (энэ практикийг өнөөдрийг хүртэл компанид ашигладаг). Хамгийн чухал нь тодорхой болсон тул хоёр даалгавар байв. Нэгдүгээрт, бидэнд кодын илүү төрлийн хамрах хүрээ, хоёрдугаарт, илүү хурдан ажиллахын тулд mypy хэрэгтэй байсан. Бидний mypy-ийг хурдасгах, компанийн төслүүдэд хэрэгжүүлэх ажил бүрэн дуусаагүй байгаа нь тодорхой байлаа. Бид эдгээр хоёр ажлын ач холбогдлыг бүрэн ухамсарлаж, тэдгээрийг шийдвэрлэхээр шийдсэн.

Илүү бүтээмжтэй!

Өсөн нэмэгдэж буй шалгалтууд нь mypy-г илүү хурдан болгосон боловч хэрэгсэл нь хангалттай хурдан биш байсан. Олон тооны нэмэлт шалгалтууд нэг минут орчим үргэлжилсэн. Үүний шалтгаан нь мөчлөгийн импорт байсан. Энэ нь Python дээр бичигдсэн том кодын сантай ажиллаж байсан хэнийг ч гайхшруулахгүй байх. Бидэнд олон зуун модулиуд байсан бөгөөд тус бүр нь бусад бүх модулийг шууд бусаар импортолсон. Хэрэв импортын гогцоонд ямар нэгэн файл өөрчлөгдсөн бол mypy нь тухайн давталт дахь бүх файлыг боловсруулах шаардлагатай болдог ба ихэнхдээ тухайн циклээс модулийг импортолсон модулиудыг боловсруулах шаардлагатай болдог. Ийм мөчлөгийн нэг нь Dropbox-т маш их асуудал үүсгэсэн гутамшигт "хамааралтай орооцолдох" явдал байв. Нэгэнт энэ бүтэц нь хэдэн зуун модулийг агуулж байсан бол шууд болон шууд бусаар олон туршилтуудыг импортоор оруулж ирсэн боловч үйлдвэрлэлийн кодонд бас ашиглагдаж байсан.

Бид дугуй хэлбэрийн хамаарлыг “тайлах” боломжийг авч үзсэн ч үүнийг хийх нөөц бололцоо байгаагүй. Бидний мэддэггүй хэтэрхий олон код байсан. Үүний үр дүнд бид өөр арга барилтай болсон. Бид "хамааралтай орооцолдох" үед ч mypy-г хурдан ажиллуулахаар шийдсэн. Бид mypy демоныг ашиглан энэ зорилгодоо хүрсэн. Демон нь хоёр сонирхолтой функцийг хэрэгжүүлдэг серверийн процесс юм. Нэгдүгээрт, энэ нь санах ойд бүх кодын сангийн мэдээллийг хадгалдаг. Энэ нь та mypy-г ажиллуулах бүртээ олон мянган импортын хамааралтай холбоотой кэш өгөгдлийг ачаалах шаардлагагүй гэсэн үг юм. Хоёрдугаарт, тэрээр жижиг бүтцийн нэгжүүдийн түвшинд чиг үүрэг болон бусад нэгжүүдийн хоорондын хамаарлыг сайтар судалж үздэг. Жишээлбэл, хэрэв функц бол foo функцийг дууддаг bar, тэгвэл хараат байдал бий болно foo нь bar. Файл өөрчлөгдөхөд демон эхлээд зөвхөн өөрчилсөн файлыг тусад нь боловсруулдаг. Дараа нь өөрчлөгдсөн функцийн гарын үсэг гэх мэт тухайн файлын гаднаас харагдах өөрчлөлтүүдийг харна. Демон нь импортын талаарх дэлгэрэнгүй мэдээллийг зөвхөн өөрчилсөн функцийг ашиглаж байгаа функцүүдийг давхар шалгахын тулд ашигладаг. Ерөнхийдөө энэ аргын тусламжтайгаар та маш цөөн тооны функцийг шалгах хэрэгтэй.

Анхны mypy хэрэглүүр нь нэг файлыг боловсруулахад ихээхэн төвлөрч байсан тул энэ бүгдийг хэрэгжүүлэх амаргүй байсан. Бид хилийн олон нөхцөл байдалтай тулгарсан бөгөөд энэ нь кодонд ямар нэг зүйл өөрчлөгдсөн тохиолдолд давтан шалгах шаардлагатай байв. Жишээлбэл, энэ нь ангид шинэ үндсэн анги оноогдсон үед тохиолддог. Бид хүссэн зүйлээ хийснийхээ дараа ихэнх нэмэлт шалгалтын гүйцэтгэлийн хугацааг хэдхэн секунд болгон бууруулж чадсан. Энэ нь бидний хувьд том ялалт юм шиг санагдлаа.

Илүү бүтээмжтэй!

Миний дээр дурдсан алсын зайн кэшийн хамт mypy демон нь программист цөөн тооны файлд өөрчлөлт оруулан төрөл шалгах ажиллагааг байнга ажиллуулж байх үед үүсдэг асуудлуудыг бараг бүрэн шийдсэн. Гэсэн хэдий ч хамгийн бага ашиг тустай тохиолдолд системийн гүйцэтгэл оновчтой биш хэвээр байна. Mypy-г цэвэрхэн эхлүүлэхэд 15 минут зарцуулагдана. Энэ нь бидний баярлахаас хамаагүй илүү байсан. Долоо хоног бүр программистууд шинэ код бичиж, одоо байгаа кодод тайлбар нэмж оруулснаар байдал улам дордов. Манай хэрэглэгчид илүү их гүйцэтгэлийг хүсэн тэсэн ядан хүлээж байсан ч бид тэдэнтэй хагас замд уулзсандаа баяртай байсан.

Бид mypy-ийн талаархи өмнөх санаануудын нэг рүү буцахаар шийдсэн. Тухайлбал, Python кодыг C код болгон хөрвүүлэх. Cython (Python дээр бичсэн кодыг C код руу хөрвүүлэх боломжийг олгодог систем) дээр туршилт хийх нь бидэнд харагдахуйц хурдыг өгөөгүй тул бид өөрсдийн хөрвүүлэгчийг бичих санааг сэргээхээр шийдсэн. Mypy кодын сан (Python хэл дээр бичигдсэн) нь шаардлагатай бүх төрлийн тэмдэглэгээг аль хэдийн агуулсан байсан тул системийг хурдасгахын тулд эдгээр тэмдэглэгээг ашиглахыг оролдох нь зүйтэй гэж бид бодсон. Энэ санааг шалгахын тулд би маш хурдан прототип бүтээсэн. Энэ нь янз бүрийн микро шалгуур үзүүлэлтүүдийн гүйцэтгэлийн 10 дахин нэмэгдсэнийг харуулсан. Бидний санаа бол Python модулиудыг C модулиудыг Cython ашиглан эмхэтгэх, мөн төрлийн тэмдэглэгээг ажиллах цагийн төрлийн шалгалт болгон хувиргах явдал байв (ихэвчлэн төрлийн тэмдэглэгээг ажиллуулах үед үл тоомсорлодог бөгөөд зөвхөн төрөл шалгах систем ашигладаг). Бид үнэндээ mypy программыг Python-оос статик байдлаар бичихэд зориулагдсан хэл рүү орчуулахаар төлөвлөж байсан бөгөөд энэ нь яг Python шиг харагдах (мөн ихэнх тохиолдолд ажиллах болно). (Ийм төрлийн хэл хоорондын шилжилт нь mypy төслийн уламжлал болсон. Анхны mypy хэрэгжилт нь Alore хэл дээр бичигдсэн, дараа нь Java болон Python-ийн синтакс эрлийз байсан).

CPython өргөтгөлийн API дээр анхаарлаа төвлөрүүлэх нь төслийн менежментийн чадавхийг алдахгүй байх гол түлхүүр байсан. Бид виртуал машин эсвэл mypy-д хэрэгтэй номын сангуудыг хэрэгжүүлэх шаардлагагүй байсан. Нэмж дурдахад, бид Python-ийн бүх экосистем болон бүх хэрэгслүүдэд (жишээлбэл, pytest) хандах боломжтой хэвээр байх болно. Энэ нь бид хөгжүүлэлтийн явцад тайлбарласан Python кодыг үргэлжлүүлэн ашиглах боломжтой гэсэн үг бөгөөд энэ нь кодыг эмхэтгэхийг хүлээхээс илүүтэйгээр кодын өөрчлөлтийг маш хурдан хийж, туршиж үзэх боломжийг бидэнд олгосон юм. Бид хоёр сандал дээр сууж байхдаа маш сайн ажиллаж байгаа юм шиг харагдаж байсан бөгөөд энэ нь бидэнд таалагдсан.

Бидний mypyc гэж нэрлэсэн хөрвүүлэгч (энэ нь mypy-г төрлүүдэд дүн шинжилгээ хийхэд ашигладаг тул) маш амжилттай төсөл болсон. Ерөнхийдөө бид кэш хийхгүйгээр байнга mypy ажиллуулахын тулд ойролцоогоор 4 дахин хурдасгасан. Mypyc төслийн гол цөмийг боловсруулахад Майкл Салливан, Иван Левкивский, Хью Хан болон миний бие багтсан жижиг баг хуанлийн 4 сар зарцуулсан. Энэ хэмжээний ажил нь жишээлбэл, C++ эсвэл Go дээр mypy-г дахин бичихэд шаардагдах хэмжээнээс хамаагүй бага байсан. Мөн бид төслийг өөр хэлээр дахин бичихэд хийхээс хамаагүй бага өөрчлөлт хийх шаардлагатай болсон. Мөн бид mypyc-ийг бусад Dropbox програмистууд үүнийг ашиглан кодоо эмхэтгэж, хурдасгах түвшинд хүргэж чадна гэж найдаж байсан.

Ийм түвшинд хүрэхийн тулд бид инженерийн сонирхолтой шийдлүүдийг ашиглах шаардлагатай болсон. Иймд хөрвүүлэгч нь хурдан, доод түвшний С бүтцийг ашиглан олон үйлдлийг хурдасгаж чадна.Жишээ нь, хөрвүүлсэн функцийн дуудлагыг C функцийн дуудлага руу хөрвүүлдэг. Ийм дуудлага нь тайлбарласан функцийг дуудахаас хамаагүй хурдан юм. Зарим үйлдлүүд, тухайлбал толь бичиг хайх нь CPython-ын ердийн C-API дуудлагуудыг ашигласан хэвээр байгаа бөгөөд тэдгээрийг эмхэтгэх үед арай хурдан байсан. Тайлбараар бий болсон систем дээрх нэмэлт ачааллыг бид арилгаж чадсан боловч энэ тохиолдолд энэ нь гүйцэтгэлийн хувьд бага зэрэг ашиг өгсөн.

Хамгийн түгээмэл "удаан" үйлдлүүдийг тодорхойлохын тулд бид кодын профайлыг хийсэн. Энэ өгөгдлийн тусламжтайгаар бид mypyc-ийг өөрчлөхийг оролдсон бөгөөд ингэснээр ийм үйлдлүүдэд илүү хурдан C код үүсгэх эсвэл илүү хурдан үйлдлүүдийг ашиглан харгалзах Python кодыг дахин бичихийг оролдсон (мөн заримдаа бидэнд энэ болон бусад асуудлыг шийдэх хангалттай энгийн шийдэл байдаггүй). . Python кодыг дахин бичих нь хөрвүүлэгч автоматаар ижил хувиргалт хийхээс илүүтэйгээр асуудлыг шийдвэрлэхэд хялбар байдаг. Урт хугацаанд бид эдгээр өөрчлөлтүүдийн ихэнхийг автоматжуулахыг хүссэн ч тухайн үед бид mypy-ийг хамгийн бага хүчин чармайлтаар хурдасгахад анхаарч байсан. Мөн энэ зорилгодоо хүрэхийн тулд бид хэд хэдэн булангуудыг таслав.

Үргэлжлэл бий…

Эрхэм уншигчид! Mypy төслийн оршин тогтнохыг мэдээд танд ямар сэтгэгдэл төрсөн бэ?

4 сая мөр Python кодын шивж шалгах зам. 2-р хэсэг
4 сая мөр Python кодын шивж шалгах зам. 2-р хэсэг

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх