Python кодының 4 миллион жолын теруді тексеру жолы. 1 бөлім

Бүгін біз Dropbox Python кодының типті басқаруымен қалай айналысатыны туралы материалды аударудың бірінші бөлігін назарларыңызға ұсынамыз.

Python кодының 4 миллион жолын теруді тексеру жолы. 1 бөлім

Dropbox Python тілінде көп жазады. Бұл серверлік қызметтер үшін де, жұмыс үстелі клиенттік қолданбалары үшін де өте кең қолданатын тіл. Біз сондай-ақ Go, TypeScript және Rust-ті көп пайдаланамыз, бірақ Python – біздің негізгі тіліміз. Біздің масштабымызды ескере отырып, және біз Python кодының миллиондаған жолдары туралы айтып отырмыз, мұндай кодты динамикалық теру оны түсінуді қажетсіз қиындатып, еңбек өнімділігіне айтарлықтай әсер ете бастағаны анықталды. Бұл мәселені жеңілдету үшін біз mypy көмегімен кодты статикалық типті тексеруге біртіндеп көшіруді бастадық. Бұл Python үшін ең танымал оқшау типті тексеру жүйесі болуы мүмкін. Mypy - бұл ашық бастапқы жоба, оның негізгі әзірлеушілері Dropbox-та жұмыс істейді.

Dropbox осы масштабта Python кодында статикалық типті тексеруді енгізген алғашқы компаниялардың бірі болды. Mypy бүгінде мыңдаған жобаларда қолданылады. Бұл құрал сансыз рет, олар айтқандай, «шайқаста сыналған». Біз қазір тұрған жерге жету үшін ұзақ жолдан өттік. Бұл жолда көптеген сәтсіз бастамалар мен сәтсіз эксперименттер болды. Бұл постта Python-да статикалық типті тексерудің тарихы, оның менің зерттеу жобамның бір бөлігі ретіндегі қиын басынан бастап, Python-да жазатын сансыз әзірлеушілер үшін типті тексеру және типке нұсқау әдеттегідей болып кеткен бүгінгі күнге дейін қамтылған. Бұл механизмдерге қазір IDE және код анализаторлары сияқты көптеген құралдар қолдау көрсетеді.

Екінші бөлімді оқыңыз

Неліктен типті тексеру қажет?

Егер сіз динамикалық терілген Python тілін бұрын-соңды пайдаланған болсаңыз, соңғы кездері статикалық теру мен mypy төңірегінде неліктен әбігер болғаны туралы түсініксіз болуы мүмкін. Немесе сізге Python оның динамикалық теруіне байланысты ұнауы мүмкін және не болып жатқаны сізді ренжітеді. Статикалық теру құндылығының кілті шешімдердің ауқымы болып табылады: жобаңыз неғұрлым үлкен болса, соғұрлым сіз статикалық теруге көбірек бейім боласыз және соңында соғұрлым ол сізге қажет болады.

Белгілі бір жоба он мыңдаған жолдардың көлеміне жетті делік және онымен бірнеше программист жұмыс істеп жатқаны белгілі болды. Осыған ұқсас жобаны қарастыра отырып, тәжірибемізге сүйене отырып, оның кодын түсіну әзірлеушілерді өнімді ұстаудың кілті болады деп айта аламыз. Түр аннотациялары болмаса, мысалы, функцияға қандай аргументтерді беру керектігін немесе функцияның қай түрлерін қайтара алатынын анықтау қиын болуы мүмкін. Мұнда типтік аннотацияларды қолданбай жауап беру қиын болатын типтік сұрақтар берілген:

  • Бұл функция қайтара ала ма? None?
  • Бұл аргумент қандай болуы керек? items?
  • Атрибуттың түрі қандай id: int солай ма, str, немесе кейбір пайдаланушы түрі болуы мүмкін бе?
  • Бұл аргумент тізім болуы керек пе? Оған кортежді беруге болады ма?

Егер сіз келесі типтегі аннотацияланған код үзіндісін қарасаңыз және ұқсас сұрақтарға жауап беруге тырыссаңыз, бұл ең қарапайым тапсырма болып шығады:

class Resource:
    id: bytes
    ...
    def read_metadata(self, 
                      items: Sequence[str]) -> Dict[str, MetadataItem]:
        ...

  • read_metadata қайтып келмейді None, себебі қайтару түрі жоқ Optional[…].
  • дәлел items сызықтар тізбегі болып табылады. Оны кездейсоқ қайталауға болмайды.
  • Атрибут id байт тізбегі болып табылады.

Идеал әлемде мұндай нәзіктіктердің барлығы кірістірілген құжаттамада (docstring) сипатталады деп күтуге болады. Бірақ тәжірибе мұндай құжаттаманың жұмыс істеу керек кодта жиі байқалмайтындығына көптеген мысалдар келтіреді. Мұндай құжаттама кодта болса да, оның абсолютті дұрыстығына сенуге болмайды. Бұл құжаттама анық емес, дәл емес және түсінбеушіліктерге ашық болуы мүмкін. Үлкен командаларда немесе ірі жобаларда бұл мәселе өте өткір болуы мүмкін.

Python жобалардың бастапқы немесе аралық кезеңдерінде жоғары болса да, белгілі бір сәтте сәтті жобалар мен Python-ды қолданатын компаниялар өмірлік маңызды сұраққа тап болуы мүмкін: «Біз барлығын статикалық түрде терілген тілде қайта жазуымыз керек пе?».

Mypy сияқты типті тексеру жүйелері жоғарыда аталған мәселені әзірлеушіге типтерді сипаттау үшін ресми тілмен қамтамасыз ету және тип туралы мәлімдемелердің бағдарламаны іске асыруға сәйкестігін тексеру (және міндетті түрде олардың бар-жоғын тексеру) арқылы шешеді. Тұтастай алғанда, бұл жүйелер мұқият тексерілген құжаттама сияқты бірдеңе береді деп айта аламыз.

Мұндай жүйелерді пайдаланудың басқа артықшылықтары бар және олар қазірдің өзінде мүлдем тривиальды емес:

  • Түрді тексеру жүйесі кейбір кішігірім (және соншалықты кішкентай емес) қателерді анықтай алады. Әдеттегі мысал - олар мәнді өңдеуді ұмытып кеткен кезде None немесе басқа ерекше жағдай.
  • Кодты рефакторинг айтарлықтай жеңілдетілген, себебі типті тексеру жүйесі көбінесе қандай кодты өзгерту керектігі туралы өте дәл. Сонымен қатар, тесттермен кодты 100% қамтуға үміттенудің қажеті жоқ, бұл кез келген жағдайда әдетте мүмкін емес. Мәселенің себебін білу үшін бізге стек ізінің тереңдігіне барудың қажеті жоқ.
  • Тіпті үлкен жобаларда да mypy секундтың бір бөлігінде толық типті тексеруді жиі жасай алады. Ал сынақтарды орындау әдетте ондаған секундтарды немесе тіпті минуттарды алады. Түрді тексеру жүйесі бағдарламашыға лезде кері байланыс береді және оның жұмысын тезірек орындауға мүмкіндік береді. Тек кодты тексеру нәтижелерін тезірек алу үшін оған бұдан былай нақты нысандарды мысқылдар мен патчтармен алмастыратын сынғыш және техникалық қызмет көрсету қиын бірлік сынақтарын жазудың қажеті жоқ.

IDE және PyCharm немесе Visual Studio Code сияқты өңдегіштер әзірлеушілерге кодты аяқтауды, қателерді бөлектеуді және жиі қолданылатын тіл конструкцияларына қолдау көрсетуді қамтамасыз ету үшін түрдегі аннотациялардың күшін пайдаланады. Және бұл терудің кейбір артықшылықтары ғана. Кейбір бағдарламашылар үшін мұның бәрі терудің пайдасына негізгі дәлел. Бұл іске асырылғаннан кейін бірден пайда болатын нәрсе. Түрлерге арналған бұл пайдалану жағдайы mypy сияқты бөлек типті тексеру жүйесін қажет етпейді, дегенмен mypy түрі аннотацияларды кодпен сәйкес сақтауға көмектесетінін ескеру қажет.

Mypy фоны

Mypy тарихы Ұлыбританияда, Кембриджде, мен Dropbox-қа қосылғаннан бірнеше жыл бұрын басталды. Мен докторлық зерттеулерімнің бөлігі ретінде статикалық типтелген және динамикалық тілдерді біріктіруге қатыстым. Мені Джереми Сиек пен Валид Таханың қосымша теру туралы мақаласы және Typed Racket жобасы шабыттандырды. Мен әртүрлі жобалар үшін бірдей бағдарламалау тілін пайдалану жолдарын табуға тырыстым - шағын сценарийлерден миллиондаған жолдардан тұратын кодтық негіздерге дейін. Сонымен қатар, мен кез келген ауқымдағы жобада тым үлкен ымыраға келудің қажеті жоқ екеніне көз жеткізгім келді. Мұның бәрінің маңызды бөлігі типтелмеген прототиптік жобадан кешенді түрде сыналған статикалық терілген дайын өнімге біртіндеп көшу идеясы болды. Бұл күндері бұл идеялар негізінен кәдімгідей қабылданады, бірақ 2010 жылы бұл әлі де белсенді түрде зерттеліп жатқан мәселе болды.

Менің типті тексерудегі бастапқы жұмысым Python-ға бағытталған емес. Оның орнына мен кішкентай «үйдегі» тілді қолдандым Alore. Міне, не туралы айтып жатқанымызды түсінуге мүмкіндік беретін мысал (түр аннотациялары мұнда міндетті емес):

def Fib(n as Int) as Int
  if n <= 1
    return n
  else
    return Fib(n - 1) + Fib(n - 2)
  end
end

Жеңілдетілген ана тілін пайдалану ғылыми зерттеулерде жиі қолданылатын әдіс болып табылады. Бұл эксперименттерді жылдам жүргізуге мүмкіндік беретіндіктен, сонымен қатар зерттеуге ешқандай қатысы жоқ нәрсені оңай елемеу мүмкін болғандықтан. Нақты әлемдегі бағдарламалау тілдері күрделі іске асырулары бар ауқымды құбылыстар болып табылады және бұл экспериментті баяулатады. Дегенмен, жеңілдетілген тілге негізделген кез келген нәтиже аздап күдікті болып көрінеді, өйткені бұл нәтижелерді алу кезінде зерттеуші тілдерді практикалық қолдану үшін маңызды ойларды құрбан еткен болуы мүмкін.

Менің Alore үшін типті тексеру құралы өте перспективалы болып көрінді, бірақ мен оны Alore тілінде жазылмаған нақты кодпен тәжірибе жасау арқылы сынап көргім келді. Бақытымызға орай, алоре тілі негізінен Python сияқты идеяларға негізделген. Python синтаксисі мен семантикасымен жұмыс істей алатындай теру тексеру құралын өзгерту оңай болды. Бұл бізге ашық бастапқы Python кодында теруді тексеруге мүмкіндік берді. Сонымен қатар, мен Alore тілінде жазылған кодты Python кодына түрлендіру үшін транспилер жаздым және оны теру кодымды аудару үшін пайдаландым. Енді менде Python тілінде жазылған типті тексеру жүйесі болды, ол Python-ның ішкі жиынын, сол тілдің бір түрін қолдады! (Alore үшін мағынасы бар кейбір архитектуралық шешімдер Python үшін нашар сәйкес келді және бұл mypy кодтық базасының бөліктерінде әлі де байқалады.)

Шындығында, менің типтік жүйем қолдайтын тілді бұл кезде Python деп атауға болмайды: бұл Python 3 типті аннотация синтаксисінің кейбір шектеулеріне байланысты Python нұсқасы болды.

Бұл Java және Python қоспасы сияқты көрінді:

int fib(int n):
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Сол кездегі идеяларымның бірі Python-ның осы түрін C-ге немесе мүмкін JVM байт кодына құрастыру арқылы өнімділікті жақсарту үшін типтік аннотацияларды пайдалану болды. Мен компилятор прототипін жазу кезеңіне жеттім, бірақ мен бұл идеядан бас тарттым, өйткені типті тексерудің өзі өте пайдалы болып көрінді.

Мен өз жобамды Санта-Кларадағы PyCon 2013 көрмесінде таныстырдым. Мен бұл туралы өмір бойы мейірімді Python диктаторы Гидо ван Россуммен де сөйлестім. Ол мені өз синтаксисімді тастап, стандартты Python 3 синтаксисін ұстануға көндірді. Python 3 функция аннотацияларын қолдайды, сондықтан менің мысалды төменде көрсетілгендей қайта жазуға болады, нәтижесінде қалыпты Python бағдарламасы пайда болды:

def fib(n: int) -> int:
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Мен кейбір ымыраға келуге тура келді (ең алдымен, мен өзімнің синтаксисімді осы себепті ойлап тапқанымды атап өткім келеді). Атап айтқанда, сол кездегі тілдің ең соңғы нұсқасы болған Python 3.3 айнымалы аннотацияларды қолдамады. Мен Гвидомен электрондық пошта арқылы мұндай аннотацияларды синтаксистік жобалаудың әртүрлі мүмкіндіктерін талқыладым. Біз айнымалылар үшін типтік түсініктемелерді пайдалануды шештік. Бұл мақсатқа сай болды, бірақ біршама қиын болды (Python 3.6 бізге жақсырақ синтаксис берді):

products = []  # type: List[str]  # Eww

Түрдегі түсініктемелер Python 2-ге қолдау көрсету үшін де пайдалы болды, ол түрдегі аннотацияларды қолдауы жоқ:

f fib(n):
    # type: (int) -> int
    if n <= 1:
        return n
    else:
        return fib(n - 1) + fib(n - 2)

Бұл (және басқа да) келіссөздер маңызды емес екені белгілі болды - статикалық терудің артықшылықтары пайдаланушылар мінсіз емес синтаксисті көп ұзамай ұмытып кетті. Түрі тексерілген Python кодында арнайы синтаксистік құрылымдар пайдаланылмағандықтан, қолданыстағы Python құралдары мен кодты өңдеу процестері қалыпты жұмыс істеуін жалғастырды, бұл әзірлеушілерге жаңа құралды үйренуді жеңілдетеді.

Гвидо сонымен қатар дипломдық жұмысымды аяқтағаннан кейін мені Dropbox-қа қосылуға көндірді. Мипи оқиғасының ең қызық жері осы жерден басталады.

Жалғасы бар…

Құрметті оқырмандар! Егер сіз Python тілін қолдансаңыз, осы тілде әзірлейтін жобаларыңыздың ауқымы туралы айтып беріңізші.

Python кодының 4 миллион жолын теруді тексеру жолы. 1 бөлім
Python кодының 4 миллион жолын теруді тексеру жолы. 1 бөлім

Ақпарат көзі: www.habr.com

пікір қалдыру