Rruga për verifikimin e tipeve të 4 milion rreshtave të kodit Python. Pjesa 1

Sot tani po ju sjellim pjesën e parë të përkthimit të materialit mbi mënyrën se si Dropbox kontrollon tipet në kodin Python.

Rruga për verifikimin e tipeve të 4 milion rreshtave të kodit Python. Pjesa 1

NĂ« Dropbox shkrimi nĂ« Python Ă«shtĂ« shumĂ« i zakonshĂ«m. Ky Ă«shtĂ« njĂ« gjuhĂ« qĂ« e pĂ«rdorim jashtĂ«zakonisht gjerĂ« — si pĂ«r shĂ«rbimet e backend-it, ashtu edhe pĂ«r aplikacionet klientore nĂ« desktop. Gjithashtu, ne pĂ«rdorim shumĂ« Go, TypeScript dhe Rust, por Python Ă«shtĂ« gjuha jonĂ« kryesore. Duke marrĂ« parasysh pĂ«rmasat tona, qĂ« lidhen me miliona rreshta kodi Python, doli se tipizimi dinamik i kĂ«tij kodi e ka komplikuar pa nevojĂ« kuptimin e tij dhe filloi tĂ« ndikonte seriozisht nĂ« produktivitetin e punĂ«s. PĂ«r tĂ« lehtĂ«suar kĂ«tĂ« problem, ne filluam njĂ« proces tĂ« gradual tĂ« kalimit tĂ« kodit tonĂ« nĂ« kontrollin statik tĂ« tipeve duke pĂ«rdorur mypy. Ky Ă«shtĂ«, ndoshta, sistemi mĂ« i njohur i pavarur i verifikimit tĂ« tipeve pĂ«r Python. Mypy Ă«shtĂ« njĂ« projekt me kod tĂ« hapur, me zhvilluesit e saj kryesorĂ« qĂ« punojnĂ« nĂ« Dropbox.

Dropbox ishte njĂ« nga kompanitĂ« e para qĂ« implementoi kontrollin statik tĂ« tipeve nĂ« kodin Python nĂ« njĂ« shkallĂ« tĂ« tillĂ«. Sot, mypy pĂ«rdoret nĂ« mijĂ«ra projekte. Ky instrument Ă«shtĂ« provuar nĂ« mija raste, ose siç thuhet, "testuar nĂ« betejĂ«". Ne, pĂ«r tĂ« arritur aty ku jemi tani, kaluam njĂ« rrugĂ« tĂ« gjatĂ«. GjatĂ« kĂ«saj rruge pati jo pak pĂ«rpjekje tĂ« dĂ«shtuar dhe eksperimente tĂ« dĂ«shtuara. Ky material rrĂ«fen historinĂ« e kontrollit statik tĂ« tipeve nĂ« Python — nga fillimi i tij i vĂ«shtirĂ«, qĂ« ishte pjesĂ« e projektit tim kĂ«rkimor, deri nĂ« ditĂ«t e sotme, kur verifikimet e tipeve dhe sugjerimet pĂ«r tipe janĂ« bĂ«rĂ« normale pĂ«r njĂ« numĂ«r tĂ« pallogaritshĂ«m zhvilluesish qĂ« shkruajnĂ« nĂ« Python. KĂ«to mekanizma tani mbĂ«shteten nga shumĂ« mjete — si IDE dhe analizuesit e kodit.

→ Lexoni pjesĂ«n e dytĂ«

Përse nevojitet kontrolli i tipeve?

NĂ«se ndonjĂ«herĂ« keni pĂ«rdorur Python qĂ« ka tipe dinamike, mund tĂ« keni pak paqartĂ«si se pse ka kaq shumĂ« zhurmĂ« rreth tipeve statike dhe mypy kohĂ«t e fundit. Ndoshta ju pĂ«lqen Python pikĂ«risht pĂ«r shkak tĂ« tipizimit tĂ« tij dinamik, dhe kjo gjĂ« qĂ« po ndodh ju shqetĂ«son. ÇelĂ«si i vlerĂ«s sĂ« tipizimit statik Ă«shtĂ« shkalla e zgjidhjeve: sa mĂ« i madh tĂ« jetĂ« projekti juaj, aq mĂ« shumĂ« do tĂ« prireni drejt tipizimit statik dhe, pĂ«rfundimisht, aq mĂ« shumĂ« do ta keni nevojĂ« kĂ«tĂ« nĂ« tĂ« vĂ«rtetĂ«.

Supozoni se një projekt ka arritur në disa dhjetëra mijëra rreshta dhe doli se mbi të po punojnë disa programues. Ndërsa shqyrtojmë një projekt të tillë, bazuar në përvojën tonë, mund të themi se kuptimi i kodit të tij do të jetë çelësi për mbështetje produktiviteti të zhvilluesve. Pa anotime tipore, ndonjëherë është e vështirë të kuptohet, për shembull, se cilat argumente duhet t'i kaloni funksionit, ose se cilat tipe vlerash mund të kthejë një funksion. Këtu janë pyetje tipike, të cilave shpesh është e vështirë të përgjigjeni pa përdorur anotime tipore:

  • A mund tĂ« kthejĂ« ky funksion AsnjĂ«?
  • ÇfarĂ« duhet tĂ« jetĂ« ky argument artikuj?
  • Cili Ă«shtĂ« tipi i atributit id: int apo Ă«shtĂ«, str, ose ndoshta njĂ« tip personalizuar?
  • A duhet tĂ« jetĂ« ky argument njĂ« listĂ«? A mund tĂ« kalosh njĂ« tuple nĂ« tĂ«?

Nëse e shikoni fragmentin e mëposhtëm të kodit, i cili është i pajisur me annotime tipash, dhe përpiqeni të përgjigjeni në pyetje të tilla, do të mendoni se është një detyrë e thjeshtë:

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

  • read_metadata nuk kthen AsnjĂ«, pasi tipi i kthimit nuk Ă«shtĂ« Optional[
].
  • Argumenti artikuj Ă«shtĂ« njĂ« sekuencĂ« strings. Nuk mund tĂ« iterohet nĂ« rend tĂ« rastit.
  • Atributi id Ă«shtĂ« njĂ« varg bajtesh.

Në një botë ideale, do të pritej që të gjitha hollësitë e tilla të ishin të përshkruara në dokumentacionin e brendshëm (docstring). Por, përvoja ofron shumë shembuj që dokumentacioni i tillë shpesh mungon në kodin me të cilin punojmë. Edhe nëse një dokumentacion i tillë ekziston, nuk mund të presim që ai të jetë absolutisht i saktë. Ky dokumentacion mund të jetë i paqartë, i pasaktë dhe të lërë shumë mundësi për keqkuptime. Në ekipet e mëdha ose në projekte të mëdha, ky problem mund të bëhet jashtëzakonisht i ndjeshëm.

Ndërsa Python tregon performancë të shkëlqyer në fazat e hershme ose ndërmjet projekteve, në një moment të caktuar, projektet e suksesshme dhe kompanitë që përdorin Python mund të përballen me një pyetje jetësore: "Na nevojitet ta rishkruajmë gjithçka në një gjuhë me tipizim statik?"

Sistemet e verifikimit të tipeve simotike me mypy e zgjidhin këtë problem duke ofruar një gjuhë formale për zhvilluesit për të përshkruar llojet dhe duke verifikuar se përshkrimet e tipeve përputhen me realizimet e programeve (dhe, jo domosdoshmërisht, verifikojnë ekzistencën e tyre). Në përgjithësi, mund të thuhet se këto sisteme na japin diçka si një dokumentacion të kontrolluar me kujdes.

Përdorimi i këtyre sistemeve ka dhe avantazhe të tjera, dhe ato janë krejtësisht të rëndësishme:

  • Sistemi i verifikimit tĂ« tipeve mund tĂ« zbulojĂ« disa gabime tĂ« vogla (edhe jo aq tĂ« vogla). NjĂ« shembull tipik Ă«shtĂ« kur harrohet tĂ« trajtohet njĂ« vlerĂ« AsnjĂ« ose njĂ« kusht tjetĂ«r tĂ« veçantĂ«.
  • Refaktorizimi i kodit bĂ«het ndjeshĂ«m mĂ« i lehtĂ«, pasi sistemi i verifikimit tĂ« tipeve shpesh tregon shumĂ« saktĂ« se cili kod duhet tĂ« ndryshohet. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, nuk kemi nevojĂ« tĂ« mbĂ«shtetemi nĂ« njĂ« mbulim 100% tĂ« kodit me teste, gjĂ« qĂ«, nĂ« çdo rast, zakonisht Ă«shtĂ« e pamundur. Nuk kemi nevojĂ« tĂ« studiojmĂ« thellĂ«sitĂ« e raporteve tĂ« gjurmimit tĂ« stackut pĂ«r tĂ« zbuluar shkakun e defektit.
  • Edhe nĂ« projekte tĂ« mĂ«dha, mypy shpesh mund tĂ« kryejĂ« njĂ« kontroll tĂ« plotĂ« tĂ« tipeve nĂ« fraksione sekondash. NdĂ«rsa ekzekutimi i testeve zakonisht kĂ«rkon dhjetĂ«ra sekonda ose madje minuta. Sistemi i kontrollit tĂ« tipeve ofron programuesit reagim tĂ« menjĂ«hershĂ«m dhe i lejon atij tĂ« punojĂ« mĂ« shpejt. Nuk Ă«shtĂ« e nevojshme mĂ« tĂ« shkruajĂ« teste modulare tĂ« brishta dhe tĂ« vĂ«shtira pĂ«r t'u mbajtur, tĂ« cilat zĂ«vendĂ«sojnĂ« entitetet reale me mok-Ă«t dhe patch-Ă«t vetĂ«m pĂ«r tĂ« marrĂ« rezultatet e provave tĂ« kodit mĂ« shpejt.

IDE-të dhe redaktorët, si PyCharm ose Visual Studio Code, përdorin mundësitë e annotation e tipeve për të ofruar zhvilluesve mundësi për përfundimin automatik të kodit, për theksimin e gabimeve dhe për mbështetje të konstruksioneve të zakonshme gjuhësore. Dhe këto janë vetëm disa nga përfitimet që ofron tipizimi. Për disa programues, gjitha këto janë argumenti kryesor në favor të tipizimit. Kjo është diçka që sjell dobi menjëherë pas zbatimit në punë. Ky rast përdorimi i tipeve nuk kërkon përdorimin e një sistemi të veçantë të kontrollit të tipeve, si mypy, megjithatë duhet të theksohet se mypy ndihmon në ruajtjen e përputhshmërisë midis annotation e tipeve dhe kodit.

Historia e mypy

Historia e mypy filloi nĂ« BritaninĂ« e Madhe, nĂ« Kembrixh, disa vite para se tĂ« bashkohesha me Dropbox. GjatĂ« studimeve pĂ«r doktoraturĂ«, merresha me çështjen e unifikimit tĂ« gjuhĂ«ve tĂ« tipizuar statikisht dhe dinamikisht. MĂ« frymĂ«zoi njĂ« artikull mbi tipizimin gradual nga Jeremy Siek dhe Walid Taha, si dhe projekti Typed Racket. PĂ«rpiqesha tĂ« gjeja mĂ«nyra pĂ«r tĂ« pĂ«rdorur tĂ« njĂ«jtĂ«n gjuhĂ« programimi pĂ«r projekte tĂ« ndryshme – nga skriptet e vogla, deri te baza tĂ« kodit qĂ« pĂ«rbĂ«heshin nga miliona rreshta. Gjithashtu, doja qĂ« nĂ« projektin e çdo shkalle, tĂ« mos ishte e nevojshme tĂ« bĂ«ja kompromise shumĂ« tĂ« mĂ«dha. NjĂ« pjesĂ« e rĂ«ndĂ«sishme e kĂ«saj ishte ideja pĂ«r njĂ« kalim gradual nga njĂ« prototip pa tipizim nĂ« njĂ« produkt tĂ« gatshĂ«m, tĂ« testuar nĂ« mĂ«nyrĂ« tĂ« plotĂ« dhe me tipizim statik. Sot, kĂ«to ide priten si tĂ« natyrshme, por nĂ« vitin 2010, kjo ishte njĂ« çështje qĂ« ende po hulumtohej aktivisht.

Puna ime fillestare në verificimin e tipeve nuk ishte fokusuar në Python. Në vend të saj, përdorja një gjuhë të vogël 'të bërë vetë' Alore. Ky është një shembull që do t'ju ndihmojë të kuptoni për çfarë bëhet fjalë (annotimet e llojeve këtu nuk janë të detyrueshme):

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

Përdorimi i një gjuhe të thjeshtuar të zhvilluar në mënyrë të vetme është një qasje e zakonshme në kërkimin shkencor. Kjo është veçanërisht për shkak se kjo mundëson kryerjen e eksperimenteve më shpejt, si dhe që ajo që nuk ka të bëjë me kërkimin mund të injorohet lehtësisht. Gjuha të cilat përdoren në praktikë zakonisht janë fenomene masive me implementime komplekse, dhe kjo ngadalëson eksperimente. Megjithatë, çdo rezultat i bazuar në një gjuhë të thjeshtuar duket pak i dyshimtë, pasi kur arrijnë këto rezultate, mund të jetë se hulumtuesi ka sakrifikuar konsiderata të rëndësishme për përdorimin praktik të gjuhëve.

Mjeti im për verifikimin e tipeve për Alore dukej shumë premtues, por doja ta testoja atë duke kryer eksperimente me kodin real, të cilin, mund të thuhet, Alore nuk e kishte. Për fat të mirë, gjuha Alore ishte në masë të madhe e bazuar në idetë e njëjta si Python. Ishte mjaft e lehtë ta riformuloja mjetin për verifikimin e tipeve në mënyrë që të funksiononte me sintaksën dhe semantikën e Python. Kjo më lejoi të provoja të kryej verifikimin e tipeve në kodin open-source të Python. Për më tepër, shkrova një transpajler për të transformuar kodin e shkruar në Alore në kod Python dhe e përdora atë për të transmetuar kodin e mjetit tim për verifikimin e tipeve. Tani kisha një sistem për verifikimin e tipeve të shkruar në Python, i cili mbante një nëngrup të Python, një lloj të këtij gjuhe! (Disa vendime arkitektonike që kishin kuptim për Alore, nuk i përshtatnin mirë Python, kjo gjithashtu duket ende në disa pjesë të bazës së kodit mypy.)

Në të vërtetë, gjuha që mbështetet nga sistemi im i tipeve nuk mund të quhej Python në këtë moment: ishte një variant i Python për shkak të disa kufizimeve të sintaksës së tipave të Python 3.

Duhej të dukej si një përzierje e Java dhe Python:

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

Një nga idetë e mia në atë kohë ishte të përdorja anotimet e tipeve për të përmirësuar performancën duke kompiluar këtë variant të Python në C, ose ndoshta në kodin bajt të JVM. Arrita në fazën e hartimit të një prototipi të kompilerit, por e ndava këtë projekt, pasi kontrolli i tipeve vetë dukej mjaft i dobishëm.

Në fund, prezantova projektin tim në konferencën PyCon 2013 në Santa Clara. Po ashtu, bisedova për këtë me Guido van Rossum, diktatorin e përjetshëm dhe bujar të Python. Ai më bind të heq dorë nga sintaksa ime dhe të ndjek sintaksën standarde të Python 3. Python 3 mbështet anotimet e funksioneve, si rezultat, shembulli im mund të rishkruhej siç është treguar më poshtë, duke marrë një program normal Python:

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

Më duhej të bënja disa kompromise (dëshiroj të theksoj se unë shpika sintaksën time për këtë arsye). Në veçanti, Python 3.3, versioni më i ri i gjuhës në atë kohë, nuk mbështeste shënimet për variablat. Kam biseduar me Guido përmes emailit mbi mundësi të ndryshme për dizajnin sintaksor të këtyre shënimeve. Ne vendosëm të përdorim komente për variablat që tregonin llojet. Kjo lejonte të arrinim qëllimin, por duke e bërë pamjen paksa të ngarkuar (Python 3.6 na dha një sintaksë më të këndshme):

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

Komentet me lloje gjithashtu ishin të dobishme për mbështetje në Python 2, në të cilin nuk kishte mbështetje të integruar për shënimet e llojeve:

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

KĂ«to (dhe kompromise tĂ« tjera) nĂ« tĂ« vĂ«rtetĂ« nuk ishin tĂ« rĂ«ndĂ«sishme — pĂ«rfitimet e tipizimit statik çuan nĂ« atĂ« qĂ« pĂ«rdoruesit shpejt i harruan sintaksĂ«n e pakĂ«t tĂ« pĂ«rsosur. Duke qenĂ« se tani nĂ« kodin Python, ku kontrolloheshin tipet, nuk aplikohej ndonjĂ« konstrukcion sintaksor i veçantĂ«, mjetet dhe proceset ekzistuese tĂ« Python pĂ«r pĂ«rpunimin e kodit vazhduan tĂ« punonin normalisht, gjĂ« qĂ« e bĂ«ri shumĂ« mĂ« tĂ« lehtĂ« mĂ«simin e kĂ«tij instrumenti nga zhvilluesit.

Guido, përveç kësaj, më bindë të bashkohem me Dropbox pasi mbrojta punimin tim përfundimtar. Këtu fillon historia më interesante e mypy.

Vazhdon


TĂ« nderuar lexues! NĂ«se pĂ«rdorni Python — ju lutemi na tregoni pĂ«r projektet e çfarĂ« shkalle po zhvilloni nĂ« kĂ«tĂ« gjuhĂ«.

Rruga për verifikimin e tipeve të 4 milion rreshtave të kodit Python. Pjesa 1
Rruga për verifikimin e tipeve të 4 milion rreshtave të kodit Python. Pjesa 1

Burimi: habr.com

Bli njĂ« hosting tĂ« besueshĂ«m pĂ«r faqet me mbrojtje DDoS, VPS VDS serverĂ« đŸ”„ Bli njĂ« hosting tĂ« besueshĂ«m pĂ«r faqet me mbrojtje DDoS, VPS VDS serverĂ« | ProHoster