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 көбүнчө секунданын бир бөлүгүндө толук текшерүүнү жасай алат. Ал эми тесттердин аткарылышы, адатта, ондогон секунд, ал тургай, мүнөт талап кылынат. Типти текшерүү системасы программистке дароо пикир берип, анын ишин тезирээк аткарууга мүмкүндүк берет. Код тестинин натыйжаларын тезирээк алуу үчүн ал чыныгы объекттерди шылдың жана жамаачы менен алмаштырган морт жана сактоо үчүн кыйын тесттерди жазуунун кереги жок.

PyCharm же Visual Studio Code сыяктуу IDE жана редакторлор иштеп чыгуучуларга кодду бүтүрүү, каталарды бөлүп көрсөтүү жана көп колдонулган тил конструкцияларын колдоо үчүн типтеги аннотациялардын күчүн колдонушат. Булар терүүнүн кээ бир пайдасы гана. Кээ бир программисттер үчүн мунун баары терүүнүн пайдасына негизги аргумент болуп саналат. Бул ишке ашыруудан кийин дароо пайда алып келе турган нерсе. Типтер үчүн бул колдонуу учуру 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 компаниясына кошулууга ынандырды. mypy окуясынын эн кызыктуу жери мына ушул жерден башталат.

Уландысы бар…

Урматтуу окурмандар! Эгер сиз Pythonду колдонсоңуз, бул тилде иштеп жаткан долбоорлоруңуздун масштабы жөнүндө айтып бериңиз.

Python кодунун 4 миллион саптарын терүүнүн жолу. 1-бөлүк
Python кодунун 4 миллион саптарын терүүнүн жолу. 1-бөлүк

Source: www.habr.com

Комментарий кошуу