Rruga për të kontrolluar 4 milion rreshta të kodit Python. Pjesa 1

Sot paraqesim pjesën e parë të një përkthimi të materialit rreth mënyrës se si Dropbox trajton kontrollin e tipit për kodin Python.

Rruga për të kontrolluar 4 milion rreshta të kodit Python. Pjesa 1

NĂ« Dropbox, ne shkruajmĂ« shumĂ« Python. ËshtĂ« njĂ« gjuhĂ« qĂ« e pĂ«rdorim gjerĂ«sisht, si pĂ«r shĂ«rbimet backend ashtu edhe pĂ«r aplikacionet klientĂ« desktop. Ne gjithashtu pĂ«rdorim gjerĂ«sisht Go, TypeScript dhe Rust, por Python Ă«shtĂ« gjuha jonĂ« kryesore. Duke pasur parasysh shkallĂ«n tonĂ« - po flasim pĂ«r miliona rreshta kodi Python - doli qĂ« shtypja dinamike nĂ« njĂ« kod tĂ« tillĂ« ishte panevojshĂ«m e vĂ«shtirĂ« pĂ«r t'u kuptuar dhe po fillonte tĂ« ndikonte seriozisht nĂ« produktivitet. PĂ«r tĂ« zbutur kĂ«tĂ« problem, filluam gradualisht tĂ« migrojmĂ« kodin tonĂ« nĂ« kontrollin statik tĂ« tipit duke pĂ«rdorur mypy. ËshtĂ« padyshim kontrolluesi i tipit mĂ« i popullarizuar i pavarur pĂ«r Python. Mypy Ă«shtĂ« njĂ« projekt me burim tĂ« hapur dhe zhvilluesit e tij kryesorĂ« punojnĂ« nĂ« Dropbox.

Dropbox ishte njĂ« nga kompanitĂ« e para qĂ« zbatoi kontrollin statik tĂ« tipit nĂ« kodin Python nĂ« njĂ« shkallĂ« tĂ« tillĂ«. Sot, mypy pĂ«rdoret nĂ« mijĂ«ra projekte. ËshtĂ« njĂ« mjet i testuar nĂ« beteja, shumĂ« herĂ«. Ka qenĂ« njĂ« rrugĂ« e gjatĂ« pĂ«r tĂ« arritur aty ku jemi sot, me shumĂ« pĂ«rpjekje dhe eksperimente tĂ« dĂ«shtuara. Ky artikull kronikon historinĂ« e kontrollit statik tĂ« tipit nĂ« Python - qĂ« nga fillimet e tij sfiduese si pjesĂ« e projektit tim kĂ«rkimor akademik deri mĂ« sot, kur kontrolli i tipit dhe aludimi i tipit janĂ« bĂ«rĂ« tĂ« zakonshme pĂ«r zhvillues tĂ« panumĂ«rt tĂ« Python. KĂ«to mekanizma tani mbĂ«shteten nga njĂ« gamĂ« e gjerĂ« mjetesh, tĂ« tilla si IDE dhe analizues kodi.

→ Lexoni pjesĂ«n e dytĂ«

Pse është i nevojshëm kontrolli i tipit?

NĂ«se keni pĂ«rdorur ndonjĂ«herĂ« Python tĂ« tipizuar dinamikisht, mund tĂ« jeni pak tĂ« hutuar se pse kohĂ«t e fundit ka pasur kaq shumĂ« bujĂ« rreth tipizimit statik dhe mypy. Ose ndoshta ju pĂ«lqen Python posaçërisht pĂ«r shkak tĂ« tipizimit dinamik, dhe thjesht jeni tĂ« frustruar nga gjendja aktuale. ÇelĂ«si i vlerĂ«s sĂ« tipizimit statik Ă«shtĂ« shkalla e zgjidhjes: sa mĂ« i madh tĂ« jetĂ« projekti juaj, aq mĂ« shumĂ« anoni nga tipizimi statik dhe nĂ« fund tĂ« fundit, aq mĂ« shumĂ« keni nevojĂ« pĂ«r tĂ«.

Le të themi se një projekt është rritur në dhjetëra mijëra rreshta kodi dhe përfshin disa programues. Bazuar në përvojën tonë, të kuptuarit e kodit për një projekt të tillë është çelësi për të ruajtur produktivitetin e zhvilluesit. Pa shënime të tipit, mund të jetë e vështirë të kuptosh, për shembull, se cilat argumente duhet t'i kalosh një funksioni ose çfarë lloje vlerash mund të kthejë një funksion. Ja pyetje tipike që shpesh janë të vështira për t'u përgjigjur pa përdorur shënime të tipit:

  • A mund tĂ« kthehet ky funksion None?
  • Cili duhet tĂ« jetĂ« ky argument? items?
  • Cili Ă«shtĂ« lloji i atributit? id: int Ă«shtĂ« kjo, str, apo ndoshta ndonjĂ« lloj i personalizuar?
  • A duhet qĂ« ky argument tĂ« jetĂ« patjetĂ«r njĂ« listĂ«? A mund t'i kaloj njĂ« tuple?

Nëse shikoni fragmentin e mëposhtëm të kodit, të shoqëruar me shënime tipi, dhe përpiqeni t'u përgjigjeni pyetjeve si këto, rezulton se është një detyrë shumë e thjeshtë:

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

  • read_metadata nuk kthehet None, meqenĂ«se lloji i kthimit nuk Ă«shtĂ« Optional[
].
  • Argument items — Ă«shtĂ« njĂ« sekuencĂ« vargjesh. Nuk mund tĂ« iterohet nĂ« asnjĂ« renditje.
  • Atribut id — Ă«shtĂ« njĂ« varg bajtesh.

Në një botë ideale, do të pritej që të gjitha hollësitë e tilla të përshkruheshin në dokumentacionin e brendshëm (docstring). Megjithatë, përvoja tregon se një dokumentacion i tillë shpesh mungon në kodin me të cilin punohet. Edhe nëse një dokumentacion i tillë është i pranishëm në kod, nuk mund të mbështetemi në saktësinë e tij absolute. Ky dokumentacion mund të jetë i paqartë, i pasaktë dhe të lërë mundësi të shumta për keqkuptime. Në ekipe ose projekte të mëdha, ky problem mund të bëhet jashtëzakonisht akut.

Ndërsa Python funksionon shkëlqyeshëm në projekte në fazat e hershme ose të ndërmjetme, në një moment të caktuar, projektet e suksesshme dhe kompanitë që përdorin Python mund të përballen me një pyetje jetësore: "A duhet të rishkruajmë gjithçka në një gjuhë të tipizuar statikisht?"

Sistemet e kontrollit të tipeve si mypy e zgjidhin këtë problem duke u ofruar zhvilluesve një gjuhë formale për përshkrimin e tipeve dhe duke verifikuar që këto përshkrime të tipeve përputhen me zbatimin e programit (dhe, opsionalisht, duke verifikuar ekzistencën e tyre). Shkurt, këto sisteme na ofrojnë një lloj dokumentacioni të verifikuar me kujdes.

Ka edhe avantazhe të tjera në përdorimin e sistemeve të tilla, dhe ato janë mjaft të thjeshta:

  • Sistemi i kontrollit tĂ« tipit mund tĂ« zbulojĂ« disa gabime tĂ« vogla (dhe jo aq tĂ« vogla). NjĂ« shembull tipik Ă«shtĂ« harresa e trajtimit tĂ« njĂ« vlere. None ose ndonjĂ« kusht tjetĂ«r i veçantĂ«.
  • Rifaktorizimi i kodit thjeshtohet ndjeshĂ«m, pasi sistemi i kontrollit tĂ« tipit shpesh tregon me shumĂ« saktĂ«si se cili kod duhet tĂ« ndryshohet. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, nuk kemi pse tĂ« mbĂ«shtetemi nĂ« mbulimin 100% tĂ« testimit, gjĂ« qĂ« zakonisht Ă«shtĂ« e pamundur gjithsesi. Nuk kemi pse tĂ« gĂ«rmojmĂ« nĂ« gjurmĂ«t e pirgut pĂ«r tĂ« pĂ«rcaktuar shkakun e njĂ« problemi.
  • Edhe nĂ« projekte tĂ« mĂ«dha, mypy shpesh mund tĂ« kryejĂ« kontroll tĂ« plotĂ« tĂ« tipit nĂ« njĂ« pjesĂ« tĂ« sekondĂ«s. Ekzekutimi i testit zakonisht zgjat dhjetĂ«ra sekonda ose edhe minuta. Sistemi i kontrollit tĂ« tipit u ofron programuesve reagime tĂ« menjĂ«hershme dhe u lejon atyre tĂ« punojnĂ« mĂ« shpejt. Ata nuk kanĂ« mĂ« nevojĂ« tĂ« shkruajnĂ« teste njĂ«sie tĂ« brishta dhe tĂ« vĂ«shtira pĂ«r t'u mirĂ«mbajtur qĂ« zĂ«vendĂ«sojnĂ« entitetet reale me modele dhe patch-e vetĂ«m pĂ«r tĂ« marrĂ« rezultate mĂ« tĂ« shpejta tĂ« testimit tĂ« kodit.

IDE-tĂ« dhe redaktorĂ«t si PyCharm ose Visual Studio Code shfrytĂ«zojnĂ« shĂ«nimet e tipit pĂ«r t'u ofruar zhvilluesve plotĂ«sim automatik tĂ« kodit, nxjerrje nĂ« pah tĂ« gabimeve dhe mbĂ«shtetje pĂ«r konstruktet gjuhĂ«sore tĂ« pĂ«rdorura zakonisht. KĂ«to janĂ« vetĂ«m disa nga pĂ«rfitimet e shkrimit me dorĂ«. PĂ«r disa programues, kjo Ă«shtĂ« arsyeja kryesore pĂ«r pĂ«rdorimin e shĂ«nimeve tĂ« tipit. ËshtĂ« diçka qĂ« u sjell dobi zhvilluesve menjĂ«herĂ« pas implementimit. Ky pĂ«rdorim i tipit nuk kĂ«rkon njĂ« kontrollues tĂ« veçantĂ« tĂ« tipit si mypy, megjithĂ«se ia vlen tĂ« pĂ«rmendet se mypy ndihmon nĂ« ruajtjen e qĂ«ndrueshmĂ«risĂ« midis shĂ«nimeve tĂ« tipit dhe kodit.

Historia e Mypy-t

Historia e mypy filloi në Kembrixh, Mbretëria e Bashkuar, disa vite para se të bashkohesha me Dropbox. Hulumtimi im i doktoraturës u përqendrua në unifikimin e gjuhëve të tipizuara statikisht dhe dinamike. U frymëzova nga punimi i Jeremy Siek dhe Walid Taha mbi tipizimin gradual, si dhe nga projekti Typed Racket. Po përpiqesha të gjeja mënyra për të përdorur të njëjtën gjuhë programimi për një sërë projektesh - nga skripte të vogla te bazat e kodit që përbëhen nga miliona rreshta. Gjithashtu doja të shmangja bërjen e shumë kompromiseve në projekte të çdo madhësie. Një pjesë kyçe e kësaj ishte ideja e kalimit gradual nga një prototip i pa tipizuar në një produkt të testuar plotësisht dhe të tipizuar statikisht. Këto ditë, këto ide merren kryesisht si të mirëqena, por në vitin 2010, ky ishte një problem që ende po eksplorohej në mënyrë aktive.

Puna ime fillestare në kontrollin e tipit nuk ishte e përqendruar në Python. Në vend të kësaj, përdora një gjuhë të vogël dhe të përgatitur në shtëpi. AloreJa një shembull për t'ju ndihmuar të kuptoni se për çfarë po flasim (shënimet e tipit janë opsionale):

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 dhe të brendshme është një qasje e zakonshme në kërkimin shkencor. Kjo jo vetëm sepse lejon eksperimentim të shpejtë dhe gjithashtu sepse të dhënat e parëndësishme mund të injorohen në mënyrë të sigurt. Gjuhët e programimit të botës reale zakonisht përfaqësojnë fenomene në shkallë të gjerë me zbatime komplekse, të cilat ngadalësojnë eksperimentet. Megjithatë, çdo rezultat i bazuar në një gjuhë të thjeshtuar është disi i dyshimtë, pasi studiuesi mund të ketë sakrifikuar konsiderata të rëndësishme për përdorimin praktik të gjuhëve për të arritur në këto rezultate.

Kontrolluesi im i tipit për Alore dukej premtues, por doja ta testoja duke kryer eksperimente në kod të vërtetë, diçka që në të vërtetë nuk ishte shkruar në Alore. Për fat të mirë, gjuha Alore bazohej kryesisht në të njëjtat ide si Python. Ishte mjaft e thjeshtë të rifaktorizohej kontrolluesi i tipit për të punuar me sintaksën dhe semantikën e Python. Kjo më lejoi të provoja kontrollin e tipit në kodin Python me burim të hapur. Gjithashtu shkrova një transpiler për të kthyer kodin e shkruar në Alore në Python dhe e përdora atë për të përkthyer kodin e kontrolluesit tim të tipit. Tani kisha një kontrollues tipi të shkruar në Python që mbështeste një nëngrup të Python, një lloj të gjuhës! (Disa vendime dizajni që kishin kuptim për Alore nuk u përkthyen mirë në Python, një fakt që është ende i dukshëm në pjesë të bazës së kodit mypy.)

Në fakt, gjuha e mbështetur nga sistemi im i tipeve në këtë pikë nuk mund të quhej realisht Python: ishte një variant i Python për shkak të disa kufizimeve të sintaksës së shënimeve të tipeve të Python 3.

Duket 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 shënime të tipit për të përmirësuar performancën duke kompiluar këtë variant të Python në C, ose ndoshta në kod bajtesh JVM. Arrita deri në shkrimin e një prototipi kompajleri, por e braktisa këtë ide sepse kontrolli i tipit më dukej mjaft i dobishëm më vete.

Përfundimisht e prezantova projektin tim në PyCon 2013 në Santa Clara. E diskutova edhe me Guido van Rossum, diktatorin dashamirës të Python për gjithë jetën. Ai më bindi të braktisja sintaksën time dhe të qëndroja te sintaksa standarde e Python 3. Python 3 mbështet shënimet e funksioneve, kështu që shembulli im mund të rishkruhet siç tregohet më poshtë, duke dhënë një program të vlefshëm Python:

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

Më është dashur të bëj disa kompromise (para së gjithash, dua të theksoj se pikërisht për këtë arsye shpika sintaksën time). Konkretisht, Python 3.3, versioni më i fundit i gjuhës në atë kohë, nuk mbështeste shënimet e variablave. Diskutova opsione të ndryshme sintaksore për shënime të tilla me Guidon përmes email-it. Vendosëm të përdornim komente të shtypura për variablat. Kjo arriti qëllimin e synuar, por ishte disi e vështirë (Python 3.6 na dha një sintaksë më të këndshme):

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

Komentet e tipit janë gjithashtu të dobishme për të mbështetur Python 2, i cili nuk ka mbështetje të integruar për shënimet e tipit:

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

Doli që këto (dhe të tjera) kompromise nuk kishin shumë rëndësi - përfitimet e shtypjes statike nënkuptonin që përdoruesit e harruan shpejt sintaksën jo ideale. Meqenëse kodi Python i kontrolluar nga lloji nuk përdorte më konstruksione të veçanta sintaksore, mjetet ekzistuese Python dhe proceset e përpunimit të kodit vazhduan të funksiononin normalisht, duke lehtësuar ndjeshëm miratimin e mjetit të ri për zhvilluesit.

Guido më bindi gjithashtu të bashkohesha me Dropbox pasi mbrojta tezën time. Këtu fillon pjesa më interesante e historisë së mypy-t.

Vazhdon


Të nderuar lexues! Nëse përdorni Python, ju lutemi na tregoni për shkallën e projekteve që zhvilloni në këtë gjuhë.

Rruga për të kontrolluar 4 milion rreshta të kodit Python. Pjesa 1
Rruga për të kontrolluar 4 milion rreshta të kodit Python. Pjesa 1

Burimi: www.habr.com

Bleni njĂ« host tĂ« besueshĂ«m pĂ«r faqet me mbrojtje DDoS, serverĂ« VPS VDS đŸ”„ Bleni hosting tĂ« besueshĂ«m tĂ« faqeve tĂ« internetit me mbrojtje DDoS, servera VPS VDS | ProHoster