Å odien mÄs publicÄjam otro daļu materiÄla tulkojumam par to, kÄ Dropbox organizÄja tipa kontroli vairÄkiem miljoniem Python koda rindu.
OficiÄlais tipa atbalsts (PEP 484)
Pirmos nopietnos eksperimentus ar mypy veicÄm vietnÄ Dropbox 2014. gada Hack Week laikÄ. Hack Week ir vienas nedÄļas pasÄkums, ko rÄ«ko Dropbox. Å ajÄ laikÄ darbinieki var strÄdÄt pie tÄ, ko vÄlas! Daži no Dropbox slavenÄkajiem tehnoloÄ£iju projektiem sÄkÄs tÄdos pasÄkumos kÄ Å”ie. Å Ä« eksperimenta rezultÄtÄ mÄs secinÄjÄm, ka mypy izskatÄs daudzsoloÅ”i, lai gan projekts vÄl nav gatavs plaÅ”ai lietoÅ”anai.
Toreiz gaisÄ virmoja ideja standartizÄt Python tipa mÄjienu sistÄmas. KÄ jau teicu, kopÅ” Python 3.0 funkcijÄm bija iespÄjams izmantot tipa anotÄcijas, taÄu tÄs bija tikai patvaļīgas izteiksmes bez noteiktas sintakses un semantikas. Programmas izpildes laikÄ Å”Ä«s anotÄcijas lielÄkoties tika vienkÄrÅ”i ignorÄtas. PÄc Hack Week mÄs sÄkÄm strÄdÄt pie semantikas standartizÄcijas. Å is darbs noveda pie raÅ”anÄs
MÅ«su motÄ«vus varÄja aplÅ«kot no divÄm pusÄm. PirmkÄrt, mÄs cerÄjÄm, ka visa Python ekosistÄma varÄtu pieÅemt kopÄju pieeju tipa mÄjienu izmantoÅ”anai (termins, ko Python lieto kÄ "tipa anotÄciju" ekvivalentu). Tas, Åemot vÄrÄ iespÄjamos riskus, bÅ«tu labÄk nekÄ daudzu savstarpÄji nesaderÄ«gu pieeju izmantoÅ”ana. OtrkÄrt, mÄs vÄlÄjÄmies atklÄti apspriest tipa anotÄcijas mehÄnismus ar daudziem Python kopienas locekļiem. Å o vÄlmi daļÄji noteica tas, ka mÄs plaÅ”o Python programmÄtÄju acÄ«s negribÄtu izskatÄ«ties kÄ āatkritÄjiā no valodas pamatidejÄm. TÄ ir dinamiski drukÄta valoda, kas pazÄ«stama kÄ "pÄ«les rakstÄ«Å”ana". SabiedrÄ«bÄ paÅ”Ä sÄkumÄ nedaudz aizdomÄ«ga attieksme pret statiskÄs maŔīnrakstÄ«Å”anas ideju nevarÄja palÄ«dzÄt, bet radÄs. TaÄu Å”is noskaÅojums galu galÄ mazinÄjÄs pÄc tam, kad kļuva skaidrs, ka statiskÄ rakstÄ«Å”ana nebÅ«s obligÄta (un pÄc tam, kad cilvÄki saprata, ka tÄ patieÅ”Äm ir noderÄ«ga).
Tipa mÄjienu sintakse, kas galu galÄ tika pieÅemta, bija ļoti lÄ«dzÄ«ga tai, ko mypy tajÄ laikÄ atbalstÄ«ja. PEP 484 tika izlaists kopÄ ar Python 3.5 2015. gadÄ. Python vairs nebija dinamiski drukÄta valoda. Man patÄ«k domÄt par Å”o notikumu kÄ nozÄ«mÄ«gu pagrieziena punktu Python vÄsturÄ.
MigrÄcijas sÄkums
2015. gada beigÄs Dropbox izveidoja trÄ«s cilvÄku komandu, lai strÄdÄtu pie mypy. ViÅu vidÅ« bija Gvido van Rosums, Gregs Praiss un Deivids FiÅ”ers. KopÅ” Ŕī brīža situÄcija sÄka attÄ«stÄ«ties ÄrkÄrtÄ«gi Ätri. Pirmais ŔķÄrslis mypy izaugsmei bija veiktspÄja. KÄ jau minÄju iepriekÅ”, projekta sÄkumÄ es domÄju par mypy implementÄcijas tulkoÅ”anu C valodÄ, taÄu Ŕī ideja pagaidÄm tika svÄ«trota no saraksta. MÄs bijÄm iestrÄguÅ”i ar sistÄmas palaiÅ”anu, izmantojot CPython tulku, kas nav pietiekami Ätrs tÄdiem rÄ«kiem kÄ mypy. (Mums nepalÄ«dzÄja arÄ« PyPy projekts, alternatÄ«va Python ievieÅ”ana ar JIT kompilatoru.)
Par laimi, Å”eit mums ir palÄ«dzÄjuÅ”i daži algoritmu uzlabojumi. Pirmais spÄcÄ«gais āpaÄtrinÄtÄjsā bija pakÄpeniskas pÄrbaudes ievieÅ”ana. Å Ä« uzlabojuma ideja bija vienkÄrÅ”a: ja visas moduļa atkarÄ«bas nav mainÄ«juÅ”Äs kopÅ” iepriekÅ”ÄjÄs mypy palaiÅ”anas, mÄs varam izmantot iepriekÅ”ÄjÄs palaiÅ”anas laikÄ keÅ”atmiÅÄ saglabÄtos datus, strÄdÄjot ar atkarÄ«bÄm. Mums bija jÄveic tikai modificÄto failu un no tiem atkarÄ«go failu tipa pÄrbaude. Mypy pat devÄs nedaudz tÄlÄk: ja moduļa ÄrÄjais interfeiss nemainÄ«jÄs, mypy pieÅÄma, ka citi moduļi, kas importÄja Å”o moduli, nav jÄpÄrbauda vÄlreiz.
PakÄpeniska pÄrbaude mums ir ļoti palÄ«dzÄjusi, anotÄjot lielu daudzumu esoÅ”Ä koda. Lieta tÄda, ka Å”is process parasti ietver daudzas iteratÄ«vas mypy darbÄ«bas, jo kodam pakÄpeniski tiek pievienotas anotÄcijas un pakÄpeniski uzlabotas. Mypy pirmÄ palaiÅ”ana joprojÄm bija ļoti lÄna, jo tajÄ bija jÄpÄrbauda daudz atkarÄ«bu. PÄc tam, lai uzlabotu situÄciju, mÄs ieviesÄm attÄlÄs keÅ”atmiÅas mehÄnismu. Ja mypy konstatÄ, ka vietÄjÄ keÅ”atmiÅa, visticamÄk, ir novecojusi, tÄ lejupielÄdÄ paÅ”reizÄjo keÅ”atmiÅas momentuzÅÄmumu visai kodu bÄzei no centralizÄtÄs krÄtuves. PÄc tam tÄ veic pakÄpenisku pÄrbaudi, izmantojot Å”o momentuzÅÄmumu. Tas ir spÄris vÄl vienu lielu soli, lai palielinÄtu mypy veiktspÄju.
Å is bija periods, kad Dropbox tika Ätri un dabiski ieviesta tipa pÄrbaude. 2016. gada beigÄs mums jau bija aptuveni 420000 XNUMX Python koda rindu ar tipa anotÄcijÄm. Daudzi lietotÄji bija entuziastiski par tipa pÄrbaudi. Arvien vairÄk izstrÄdes komandu izmantoja Dropbox mypy.
Toreiz viss izskatÄ«jÄs labi, bet mums vÄl bija daudz darÄmÄ. SÄkÄm veikt periodiskas iekÅ”ÄjÄs lietotÄju aptaujas, lai apzinÄtu projekta problÄmzonas un saprastu, kÄdi jautÄjumi vispirms ir jÄatrisina (Å”Äda prakse uzÅÄmumÄ tiek izmantota arÄ« Å”odien). SvarÄ«gÄkie, kÄ kļuva skaidrs, bija divi uzdevumi. PirmkÄrt, mums bija nepiecieÅ”ams plaÅ”Äks koda pÄrklÄjums, otrkÄrt, lai mypy strÄdÄtu ÄtrÄk. Bija pilnÄ«gi skaidrs, ka mÅ«su darbs, lai paÄtrinÄtu mypy un ieviestu to uzÅÄmuma projektos, vÄl nebija pabeigts. MÄs, pilnÄ«bÄ apzinoties Å”o divu uzdevumu svarÄ«gumu, Ä·ÄrÄmies pie to risinÄÅ”anas.
VairÄk produktivitÄtes!
PakÄpeniskas pÄrbaudes padarÄ«ja mypy ÄtrÄku, taÄu rÄ«ks joprojÄm nebija pietiekami Ätrs. Daudzas pakÄpeniskas pÄrbaudes ilga apmÄram minÅ«ti. Iemesls tam bija cikliskais imports. Tas, iespÄjams, nepÄrsteigs nevienu, kurÅ” ir strÄdÄjis ar lielÄm Python rakstÄ«tÄm kodu bÄzÄm. Mums bija simtiem moduļu komplekti, no kuriem katrs netieÅ”i importÄja visus pÄrÄjos. Ja tika mainÄ«ts kÄds importÄÅ”anas cilpas fails, mypy bija jÄapstrÄdÄ visi Ŕīs cilpas faili un bieži vien visi moduļi, kas importÄja moduļus no Ŕīs cilpas. Viens no Å”Ädiem cikliem bija bÄdÄ«gi slavenais āatkarÄ«bas juceklisā, kas Dropbox radÄ«ja daudz nepatikÅ”anas. KÄdreiz Å”ajÄ struktÅ«rÄ bija vairÄki simti moduļu, kamÄr tÄ tika tieÅ”i vai netieÅ”i importÄta, daudzi testi, tÄ tika izmantota arÄ« ražoÅ”anas kodÄ.
MÄs apsvÄrÄm iespÄju "atŔķetinÄt" cirkulÄrÄs atkarÄ«bas, taÄu mums nebija resursu, lai to izdarÄ«tu. Bija pÄrÄk daudz koda, ar kuru mÄs nebijÄm pazÄ«stami. RezultÄtÄ mÄs nonÄcÄm pie alternatÄ«vas pieejas. MÄs nolÄmÄm, ka mypy darbojas Ätri, pat ja ir āatkarÄ«bas juceklisā. MÄs sasniedzÄm Å”o mÄrÄ·i, izmantojot mypy dÄmonu. DÄmons ir servera process, kas ievieÅ” divas interesantas funkcijas. PirmkÄrt, tÄ atmiÅÄ saglabÄ informÄciju par visu kodu bÄzi. Tas nozÄ«mÄ, ka katru reizi, kad palaižat mypy, jums nav jÄielÄdÄ keÅ”atmiÅÄ saglabÄtie dati, kas saistÄ«ti ar tÅ«kstoÅ”iem importÄtu atkarÄ«bu. OtrkÄrt, viÅÅ” rÅ«pÄ«gi, mazo struktÅ«rvienÄ«bu lÄ«menÄ«, analizÄ atkarÄ«bas starp funkcijÄm un citÄm vienÄ«bÄm. PiemÄram, ja funkcija foo
izsauc funkciju bar
, tad ir atkarība foo
no bar
. Kad fails mainÄs, dÄmons vispirms atseviŔķi apstrÄdÄ tikai mainÄ«to failu. PÄc tam tiek aplÅ«kotas Ŕī faila ÄrÄji redzamÄs izmaiÅas, piemÄram, mainÄ«tie funkciju paraksti. DÄmons izmanto detalizÄtu informÄciju par importÄÅ”anu tikai, lai vÄlreiz pÄrbaudÄ«tu tÄs funkcijas, kuras faktiski izmanto modificÄto funkciju. Parasti, izmantojot Å”o pieeju, jums ir jÄpÄrbauda ļoti maz funkciju.
To visu ieviest nebija viegli, jo sÄkotnÄjÄ mypy ievieÅ”ana lielÄ mÄrÄ bija vÄrsta uz viena faila apstrÄdi vienlaikus. NÄcÄs saskarties ar daudzÄm robežsituÄcijÄm, kuru raÅ”anÄs prasÄ«ja atkÄrtotas pÄrbaudes gadÄ«jumos, kad kodÄ kaut kas mainÄ«jÄs. PiemÄram, tas notiek, ja klasei tiek pieŔķirta jauna bÄzes klase. Kad mÄs izdarÄ«jÄm to, ko gribÄjÄm, mÄs varÄjÄm samazinÄt lielÄko daļu papildu pÄrbaužu izpildes laiku lÄ«dz dažÄm sekundÄm. Å Ä« mums Ŕķita liela uzvara.
VÄl lielÄka produktivitÄte!
KopÄ ar attÄlo keÅ”atmiÅu, par kuru es runÄju iepriekÅ”, mypy dÄmons gandrÄ«z pilnÄ«bÄ atrisinÄja problÄmas, kas rodas, programmÄtÄjam bieži veicot tipa pÄrbaudi, veicot izmaiÅas nelielÄ skaitÄ failu. TomÄr sistÄmas veiktspÄja visnelabvÄlÄ«gÄkajÄ lietoÅ”anas gadÄ«jumÄ joprojÄm bija tÄlu no optimÄlÄs. TÄ«ra mypy palaiÅ”ana var ilgt vairÄk nekÄ 15 minÅ«tes. Un tas bija daudz vairÄk, nekÄ mÄs bÅ«tu bijuÅ”i apmierinÄti. Katru nedÄļu situÄcija pasliktinÄjÄs, jo programmÄtÄji turpinÄja rakstÄ«t jaunu kodu un pievienot anotÄcijas esoÅ”ajam kodam. MÅ«su lietotÄji joprojÄm bija izsalkuÅ”i pÄc lielÄkas veiktspÄjas, taÄu mÄs priecÄjÄmies viÅus satikt pusceļÄ.
MÄs nolÄmÄm atgriezties pie vienas no iepriekÅ”ÄjÄm idejÄm par mypy. Proti, pÄrvÄrst Python kodu C kodÄ. EksperimentÄÅ”ana ar Cython (sistÄmu, kas ļauj tulkot Python rakstÄ«to kodu C kodÄ) mums nedeva nekÄdu redzamu paÄtrinÄjumu, tÄpÄc mÄs nolÄmÄm atdzÄ«vinÄt ideju par sava kompilatora rakstÄ«Å”anu. TÄ kÄ mypy kodu bÄzÄ (rakstÄ«ta Python) jau bija visas nepiecieÅ”amÄs tipa anotÄcijas, mÄs uzskatÄ«jÄm, ka bÅ«tu vÄrts mÄÄ£inÄt izmantot Ŕīs anotÄcijas, lai paÄtrinÄtu sistÄmu. Es Ätri izveidoju prototipu, lai pÄrbaudÄ«tu Å”o ideju. Tas uzrÄdÄ«ja vairÄk nekÄ 10 reižu veiktspÄjas pieaugumu dažÄdos mikro etalonos. MÅ«su ideja bija apkopot Python moduļus C moduļos, izmantojot Cython, un pÄrvÄrst tipa anotÄcijas izpildlaika tipa pÄrbaudÄs (parasti tipa anotÄcijas izpildes laikÄ tiek ignorÄtas un tiek izmantotas tikai tipa pÄrbaudes sistÄmÄs). MÄs faktiski plÄnojÄm tulkot mypy ievieÅ”anu no Python valodÄ, kas bija paredzÄta statiskai ievadÄ«Å”anai un kas izskatÄ«tos (un lielÄkoties darbotos) tieÅ”i tÄpat kÄ Python. (Å Äda veida starpvalodu migrÄcija ir kļuvusi par mypy projekta tradÄ«ciju. SÄkotnÄjÄ mypy ievieÅ”ana tika uzrakstÄ«ta Alore, pÄc tam bija Java un Python sintaktiskais hibrÄ«ds).
KoncentrÄÅ”anÄs uz CPython paplaÅ”inÄjuma API bija galvenais, lai nezaudÄtu projektu pÄrvaldÄ«bas iespÄjas. Mums nebija jÄievieÅ” virtuÄlÄ maŔīna vai bibliotÄkas, kas bija vajadzÄ«gas mypy. TurklÄt mums joprojÄm bÅ«tu piekļuve visai Python ekosistÄmai un visiem rÄ«kiem (piemÄram, pytest). Tas nozÄ«mÄja, ka izstrÄdes laikÄ varÄjÄm turpinÄt izmantot interpretÄtu Python kodu, ļaujot mums turpinÄt strÄdÄt ar ļoti Ätru koda izmaiÅu un tÄ testÄÅ”anas modeli, nevis gaidÄ«t, kamÄr kods tiks kompilÄts. IzskatÄ«jÄs, ka mÄs, tÄ teikt, paveicam lielisku darbu, sÄdÄdami uz diviem krÄsliem, un mums tas patika.
Kompilators, ko mÄs nosaucÄm par mypyc (jo tas izmanto mypy kÄ priekÅ”galu tipu analÄ«zei), izrÄdÄ«jÄs ļoti veiksmÄ«gs projekts. KopumÄ mÄs panÄcÄm aptuveni 4 reizes paÄtrinÄjumu biežai mypy palaiÅ”anai bez keÅ”atmiÅas. Lai izstrÄdÄtu mypyc projekta kodolu, nelielai komandai Maikls Salivans, Ivans Levkivskis, HjÅ« HÄns un es aizÅÄma aptuveni 4 kalendÄros mÄneÅ”us. Å is darba apjoms bija daudz mazÄks nekÄ tas, kas bÅ«tu bijis nepiecieÅ”ams, lai pÄrrakstÄ«tu mypy, piemÄram, C++ vai Go. Un mums projektÄ bija jÄveic daudz mazÄk izmaiÅu, nekÄ bÅ«tu bijis jÄveic, pÄrrakstot to citÄ valodÄ. MÄs arÄ« cerÄjÄm, ka varÄsim panÄkt mypyc lÄ«dz tÄdam lÄ«menim, lai citi Dropbox programmÄtÄji to varÄtu izmantot sava koda apkopoÅ”anai un paÄtrinÄÅ”anai.
Lai sasniegtu Å”o veiktspÄjas lÄ«meni, mums bija jÄpiemÄro daži interesanti inženiertehniskie risinÄjumi. TÄdÄjÄdi kompilators var paÄtrinÄt daudzas darbÄ«bas, izmantojot Ätras, zema lÄ«meÅa C konstrukcijas. PiemÄram, kompilÄts funkcijas izsaukums tiek pÄrtulkots C funkcijas izsaukumÄ. Un Å”Äds izsaukums ir daudz ÄtrÄks nekÄ interpretÄtas funkcijas izsaukÅ”ana. DažÄs operÄcijÄs, piemÄram, vÄrdnÄ«cÄs meklÄÅ”anÄ, joprojÄm tika izmantoti regulÄri C-API izsaukumi no CPython, kas kompilÄÅ”anas laikÄ bija tikai nedaudz ÄtrÄki. VarÄjÄm novÄrst papildu slodzi sistÄmai, ko radÄ«ja interpretÄcija, taÄu tas Å”ajÄ gadÄ«jumÄ deva tikai nelielu ieguvumu veiktspÄjas ziÅÄ.
Lai identificÄtu visizplatÄ«tÄkÄs ālÄnÄsā darbÄ«bas, mÄs veicÄm koda profilÄÅ”anu. ApbruÅojoties ar Å”iem datiem, mÄs mÄÄ£inÄjÄm vai nu pielÄgot mypyc, lai tas Å”ÄdÄm darbÄ«bÄm Ä£enerÄtu ÄtrÄku C kodu, vai arÄ« pÄrrakstÄ«t atbilstoÅ”o Python kodu, izmantojot ÄtrÄkas darbÄ«bas (un dažreiz mums vienkÄrÅ”i nebija pietiekami vienkÄrÅ”a risinÄjuma Å”ai vai citai problÄmai). . Python koda pÄrrakstÄ«Å”ana bieži bija vienkÄrÅ”Äks problÄmas risinÄjums nekÄ kompilatora automÄtiska pÄrveidoÅ”ana. IlgtermiÅÄ mÄs vÄlÄjÄmies automatizÄt daudzas no Ŕīm transformÄcijÄm, taÄu tajÄ laikÄ mÄs koncentrÄjÄmies uz mypy paÄtrinÄÅ”anu ar minimÄlu piepÅ«li. Un virzoties uz Å”o mÄrÄ·i, mÄs nogriezÄm vairÄkus stÅ«rus.
Lai varÄtu turpinÄt ...
CienÄ«jamie lasÄ«tÄji! KÄdi bija jÅ«su iespaidi par mypy projektu, kad uzzinÄjÄt par tÄ esamÄ«bu?
Avots: www.habr.com