Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3

Прадстаўляем вашай увазе трэцюю частку перакладу матэрыялу аб шляху, які прайшла кампанія Dropbox, укараняючы ў сябе сістэму праверкі тыпаў Python-кода.

Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3

→ Папярэднія часткі: першая и другая

Дасягненне 4 мільёнаў радкоў тыпізаванага кода

Яшчэ адной важнай задачай (гэта была другая па папулярнасці праблема, якая хвалявала тых, хто ўдзельнічаў ва ўнутраных апытаннях) было павелічэнне аб'ёму кода ў Dropbox, пакрытага праверкамі тыпаў. Мы выпрабавалі некалькі падыходаў для рашэння гэтай задачы – ад натуральнага росту аб'ёму тыпізаванай кодавай базы да засяроджвання намаганняў чальцоў каманды mypy на статычнай і дынамічнай аўтаматызаванай выснове тыпаў. У выніку стварылася такое ўражанне, што тут няма простай выйгрышнай стратэгіі, але мы змаглі дасягнуць хуткага росту аб'ёму анатаванага кода, скамбінаваўшы мноства падыходаў.

У выніку ў нашым самым вялікім Python-рэпазітары (з бэкэнд-кодам) колькасць радкоў анатаванага кода дасягнула амаль 4 мільёнаў. Праца па статычнай тыпізацыі кода была праведзена прыкладна за тры гады. Mypy зараз падтрымлівае розныя віды справаздач аб пакрыцці кода тыпамі, якія спрашчаюць назіранне за ходам тыпізацыі. У прыватнасці, мы можам фармаваць справаздачы па кодзе з нявызначанасцямі ў тыпах, з такімі, напрыклад, як відавочнае выкарыстанне тыпу Any у анатацыях, якія немагчыма праверыць, ці з такімі, як імпарт іншых бібліятэк, у якіх няма анатацыяў тыпаў. Мы, у рамках праекту па падвышэнні дакладнасці праверкі тыпаў у Dropbox, унеслі фундуш у паляпшэнні азначэнняў тыпаў (так званых stub-файлаў) для некаторых папулярных апенсорсных бібліятэк у цэнтралізаваным Python-рэпазітары. typeshed.

Мы рэалізавалі (і стандартызавалі ў наступных PEP) новыя магчымасці сістэмы тыпаў, якія дазваляюць выкарыстоўваць больш дакладныя тыпы для некаторых спецыфічных Python-патэрнаў. Прыкметным прыкладам гэтага з'яўляецца TypeDict, які дае тыпы для JSON-падобных слоўнікаў, якія маюць фіксаваны набор радковых ключоў, кожны з якіх мае значэнне ўласнага тыпу. Мы працягнем пашыраць сістэму тыпаў. Верагодна, нашым наступным крокам стане паляпшэнне падтрымкі магчымасцяў Python па працы з лікамі.

Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3
Колькасць радкоў анатаванага кода: сервер

Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3
Колькасць радкоў анатаванага кода: кліент

Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3
Агульная колькасць радкоў анатаванага кода

Вось агляд асноўных асаблівасцяў тых дзеянняў, якія мы выканалі дзеля падвышэння аб'ёму анатаванага кода ў Dropbox:

Строгасць анатавання. Мы паступова падвышалі патрабаванні па строгасці анатавання новага кода. Мы пачалі з парад лінтара, у якіх прапаноўвалася дадаваць анатацыі ў файлы, у якіх ужо ёсць некаторыя анатацыі. Цяпер мы патрабуем наяўнасці анатацый тыпаў у новых Python-файлах і ў большасці існуючых файлаў.

Справаздачы аб тыпізацыі. Мы штотыдзень рассылаем камандам справаздачы аб узроўні тыпізацыі іх кода і даем парады, датычныя таго, што менавіта варта анатаваць у першую чаргу.

Папулярызацыя mypy. Мы расказваем пра mypy на розных мерапрыемствах і маем зносіны з камандамі, дапамагаючы ім пачаць карыстацца анатацыямі тыпаў.

Апытанні. Мы праводзім перыядычныя апытанні карыстальнікаў для выяўлення галоўных праблем. Мы гатовы зайсці дастаткова далёка ў справе вырашэння гэтых праблем (аж да стварэння новай мовы дзеля паскарэння mypy!).

Прадукцыйнасць. Мы значна палепшылі прадукцыйнасць mypy дзякуючы выкарыстанню дэмана і mypyc. Зроблена гэта дзеля згладжванні нязручнасцяў, якія ўзнікаюць падчас анатаванняў, і дзеля таго, каб атрымаць магчымасць працаваць з вялікімі аб'ёмамі кода.

Інтэграцыя з рэдактарамі. Мы стварылі сродкі для падтрымкі запуску mypy у рэдактарах, якія карыстаюцца папулярнасцю ў Dropbox. Сюды ўваходзяць PyCharm, Vim і VS Code. Гэта значна спрасціла працэс выканання работ па анатаванні кода і па праверцы яго працаздольнасці. Падобныя дзеянні звычайна характэрны пры анатаванні існуючага кода.

Статычны аналіз. Мы стварылі інструмент для вываду сігнатур функцый з выкарыстаннем сродкаў статычнага аналізу. Гэты інструмент можа працаваць толькі ў параўнальна простых сітуацыях, але ён дапамог нам без асаблівых намаганняў павялічыць пакрыццё кода тыпамі.

Падтрымка іншых бібліятэк. У шматлікіх нашых праектах выкарыстоўваецца набор прылад SQLAlchemy. У ім ужываюцца дынамічныя магчымасці Python, якія тыпы PEP 484 няздольныя змадэляваць напроста. Мы, у адпаведнасці з PEP 561, стварылі адпаведны stub-файл і напісалі плягін для mypy (апенсорны), які паляпшае падтрымку SQLAlchemy.

Цяжкасці, з якімі мы сустрэліся

Шлях да 4 мільёнаў радкоў тыпізаванага кода не заўсёды даваўся нам лёгка. На гэтым шляху мы сустрэлі нямала ям і зрабілі некалькі памылак. Вось некаторыя з праблем, з якімі мы сутыкнуліся. Спадзяемся, аповяд аб іх дапаможа іншым падобных праблем пазбегнуць.

Прапушчаныя файлы. Мы пачыналі працу з праверкі толькі невялікага аб'ёму файлаў. Усё, якое не ўваходзіць у лік гэтых файлаў, не правяралася. Файлы ў спіс праверкі дадаваліся тады, калі ў іх з'яўляліся першыя анатацыі. Калі нешта імпартавалася з модуля, размешчанага за межамі вобласці праверкі, то гаворка ішла аб працы са значэннямі тыпу Any, якія ўвогуле не правяраліся. Гэта прывяло да значнай страты дакладнасці тыпізацыі, асабліва - на ранніх стадыях міграцыі. Такі падыход да гэтага часу працаваў на здзіўленне добра, хоць тыповай была сітуацыя, калі даданне файлаў у вобласць праверкі выяўляла праблемы ў іншых частках кодавай базы. У самым горшым выпадку, калі аб'ядноўваліся дзве ізаляваных вобласці кода, у якіх, незалежна сябар ад сябра, тыпы былі ўжо правераныя, апынялася, што тыпы гэтых абласцей несумяшчальныя адзін з адным. Гэта прыводзіла да неабходнасці занясення ў анатацыі мноства змен. Цяпер, азіраючыся назад, мы разумеем, што нам варта было б як мага раней дадаць у вобласць праверкі тыпаў mypy базавыя бібліятэчныя модулі. Гэта зрабіла б нашую працу значна больш прадказальнай.

Анатаванне старога кода. Калі мы пачыналі працу, у нас было каля 4 мільёнаў радкоў ужо існуючага Python-кода. Было ясна, што анатаванне ўсяго гэтага кода - задача не з лёгкіх. Мы стварылі інструмент, названы PyAnnotate, які можа збіраць звесткі аб тыпах падчас выканання тэстаў і ўмее дадаваць у код анатацыі тыпаў, грунтуючыся на сабраных звестках. Аднак асабліва шырокага ўкаранення гэтай прылады мы не заўважылі. Збор звестак аб тыпах быў павольным, аўтаматычна згенераваныя анатацыі часта патрабавалі мноства ручных правак. Мы думалі аб аўтаматычным запуску гэтага сродку пры кожнай праверцы кода, ці аб тым, каб збіраць звесткі аб тыпах, засноўваючыся на аналізе нейкага невялікага аб'ёму рэальных сеткавых запытаў, але вырашылі гэтага не рабіць, бо любы з гэтых падыходаў занадта рызыкоўны.

У выніку можна адзначыць, што большая частка кода была ўручную анатаваная яго ўладальнікамі. Мы, для таго, каб накіроўваць гэты працэс у правільнае рэчышча, рыхтуем справаздачы па асабліва важных модулях і функцый, якія трэба анатаваць. Напрыклад, важна забяспечыць анатацыямі тыпаў бібліятэчны модуль, які выкарыстоўваецца ў сотнях месцаў. А вось стары сэрвіс, які замяняюць новым, анатаваць ужо не так важна. Мы, акрамя таго, эксперыментуем з выкарыстаннем статычнага аналізу для генеравання анатацый тыпаў для старога кода.

Цыклічныя імпарты. Вышэй я казаў пра цыклічныя імпарты (пра «клубкі залежнасцяў»), існаванне якіх ускладніла паскарэнне mypy. Нам, акрамя таго, прыйшлося сур'ёзна папрацаваць над тым, каб забяспечыць mypy падтрымкай усіх відаў ідыём, прычынай узнікнення якіх з'яўляюцца гэтыя вось цыклічныя імпарты. Нядаўна мы завяршылі буйны праект па рэдызайне сістэмы, які выправіў большасць праблем mypy, якія тычацца цыклічных імпартаў. Гэтыя праблемы, насамрэч, раслі з вельмі ранніх дзён праекту, яшчэ з Alore, навучальнай мовы, на які быў першапачаткова арыентаваны праект mypy. Сінтаксіс Alore дазваляе лёгка вырашаць праблемы цыклічных каманд імпарту. Сучасны mypy атрымаў у спадчыну некаторыя абмежаванні ад сваёй ранняй няхітрай рэалізацыі (якая выдатна падыходзіла для Alore). Python ускладняе працу з цыклічнымі імпартамі ў асноўным з-за неадназначнасці выразаў. Напрыклад, падчас аперацый прысвойвання значэння можа, насамрэч, вызначацца псеўданім тыпу. Mypy не заўсёды здольны выяўляць падобныя рэчы да таго часу, пакуль большая частка цыклу імпарту не будзе апрацавана. У Alore такіх неадназначнасцяў не было. Няўдалыя рашэнні, прынятыя на ранніх этапах распрацоўкі сістэмы, могуць паднесці праграмісту непрыемную неспадзеўку праз шмат гадоў.

Вынікі: шлях да 5 мільёнаў радкоў кода і да новых гарызонтаў

Праект mypy прайшоў доўгі шлях - ад ранніх прататыпаў, да сістэмы, сродкамі якой кантралююцца тыпы прадакшн-кода аб'ёмам у 4 мільёны радкоў. Па ходзе развіцця mypy была ажыццёўлена стандартызацыя падказак па тыпах у Python. У нашы дні вакол тыпізацыі Python-кода развілася магутная экасістэма. У ёй знайшлося месца падтрымцы бібліятэк, у ёй прысутнічаюць дапаможныя сродкі для IDE і рэдактараў, у ёй ёсць некалькі сістэм кантролю тыпаў, у кожнай з якіх ёсць свае плюсы і мінусы.

Нягледзячы на ​​тое, што праверка тыпаў ужо ўспрымаецца ў Dropbox як нешта само сабой якое разумеецца, я ўпэўнены ў тым, што мы ўсё яшчэ жывем на світанку тыпізацыі Python-кода. Я думаю, што тэхналогіі праверкі тыпаў будуць працягваць разьвівацца і ўдасканальвацца.

Калі вы яшчэ не карысталіся праверкамі тыпаў у сваім буйнамаштабным Python-праекце, то ведайце, што цяпер - вельмі зручны час для таго, каб пачаць пераход на статычную тыпізацыю. Я гутарыў з тымі, хто здзейсніў падобны пераход. Ніхто з іх аб гэтым не пашкадаваў. Кантроль тыпаў ператварае Python у мову, якая значна лепш, чым "звычайны Python", падыходзіць для распрацоўкі вялікіх праектаў.

Паважаныя чытачы! Ці карыстаецеся вы кантролем тыпаў у сваіх Python-праектах?

Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3
Шлях да праверкі тыпаў 4 радкоў Python-кода. Частка 3

Крыніца: habr.com

Дадаць каментар