Die pad na tikkontrolering van 4 miljoen reëls Python-kode. Deel 1

Vandag bring ons die eerste deel van die vertaling van die materiaal onder u aandag oor hoe Dropbox met tipebeheer van Python-kode handel.

Die pad na tikkontrolering van 4 miljoen reëls Python-kode. Deel 1

Dropbox skryf baie in Python. Dit is 'n taal wat ons uiters wyd gebruik, beide vir back-end-dienste en rekenaarkliënttoepassings. Ons gebruik ook baie Go, TypeScript en Rust, maar Python is ons hooftaal. As ons ons skaal in ag neem, en ons praat van miljoene reëls Python-kode, het dit geblyk dat die dinamiese tik van sulke kode die begrip daarvan onnodig bemoeilik het en arbeidsproduktiwiteit ernstig begin beïnvloed het. Om hierdie probleem te versag, het ons begin om ons kode geleidelik oor te skakel na statiese tipe kontrolering met behulp van mypy. Dit is waarskynlik die gewildste selfstandige tipe kontrolestelsel vir Python. Mypy is 'n oopbronprojek, sy hoofontwikkelaars werk in Dropbox.

Dropbox was een van die eerste maatskappye wat statiese tipe kontrolering in Python-kode op hierdie skaal geïmplementeer het. Mypy word deesdae in duisende projekte gebruik. Hierdie instrument ontelbare kere, soos hulle sê, "getoets in die geveg." Ons het 'n lang pad gestap om te kom waar ons nou is. Langs die pad was daar baie onsuksesvolle ondernemings en mislukte eksperimente. Hierdie plasing dek die geskiedenis van statiese tipe nagaan in Python, vanaf die rotsagtige begin daarvan as deel van my navorsingsprojek, tot vandag toe, wanneer tipe kontrolering en tipe wenk alledaags geword het vir talle ontwikkelaars wat in Python skryf. Hierdie meganismes word nou ondersteun deur baie instrumente soos IDE's en kode-ontleders.

Lees die tweede gedeelte

Hoekom is tipe nagaan nodig?

As jy al ooit dinamies getikte Python gebruik het, kan jy dalk 'n mate van verwarring hê oor hoekom daar die afgelope tyd so 'n ophef rondom statiese tik en mypy was. Of dalk hou jy van Python juis vanweë sy dinamiese tik, en wat gebeur ontstel jou eenvoudig. Die sleutel tot die waarde van statiese tik is die skaal van die oplossings: hoe groter jou projek, hoe meer leun jy na statiese tik, en op die ou end, hoe meer het jy dit regtig nodig.

Gestel 'n sekere projek het die grootte van tienduisende reëls bereik, en dit het geblyk dat verskeie programmeerders daaraan werk. As ons na 'n soortgelyke projek kyk, gebaseer op ons ervaring, kan ons sê dat die begrip van die kode die sleutel sal wees om ontwikkelaars produktief te hou. Sonder tipe-aantekeninge kan dit moeilik wees om byvoorbeeld uit te vind watter argumente na 'n funksie oorgedra moet word, of watter tipes 'n funksie kan terugstuur. Hier is tipiese vrae wat dikwels moeilik is om te beantwoord sonder om tipe-aantekeninge te gebruik:

  • Kan hierdie funksie terugkeer None?
  • Wat moet hierdie argument wees? items?
  • Wat is die kenmerk tipe id: int is dit, str, of dalk 'n pasgemaakte tipe?
  • Moet hierdie argument 'n lys wees? Is dit moontlik om 'n tupel daaraan te slaag?

As jy na die volgende tipe-annoteerde kodebrokkie kyk en soortgelyke vrae probeer beantwoord, blyk dit dat dit die eenvoudigste taak is:

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

  • read_metadata keer nie terug nie None, aangesien die terugkeer tipe nie Optional[…].
  • argument items is 'n reeks lyne. Dit kan nie lukraak herhaal word nie.
  • Eienskap id is 'n string grepe.

In 'n ideale wêreld sou mens verwag dat al sulke subtiliteite in die ingeboude dokumentasie (dokstring) beskryf sou word. Maar ondervinding gee baie voorbeelde van die feit dat sulke dokumentasie dikwels nie waargeneem word in die kode waarmee jy moet werk nie. Selfs al is sulke dokumentasie in die kode teenwoordig, kan 'n mens nie op die absolute korrektheid daarvan staatmaak nie. Hierdie dokumentasie kan vaag, onakkuraat en oop vir misverstande wees. In groot spanne of groot projekte kan hierdie probleem uiters akuut word.

Terwyl Python uitblink in die vroeë of intermediêre stadiums van projekte, kan suksesvolle projekte en maatskappye wat Python gebruik op 'n sekere stadium voor die lewensbelangrike vraag te staan ​​kom: "Moet ons alles in 'n staties getikte taal herskryf?".

Tipe-kontroleringstelsels soos mypy los die bogenoemde probleem op deur die ontwikkelaar van 'n formele taal te voorsien vir die beskrywing van tipes, en deur te kontroleer dat tipe verklarings ooreenstem met die programimplementering (en, opsioneel, deur na te gaan vir hul bestaan). Oor die algemeen kan ons sê dat hierdie stelsels iets soos noukeurig gekontroleerde dokumentasie tot ons beskikking stel.

Die gebruik van sulke stelsels het ander voordele, en hulle is reeds heeltemal nie-triviaal:

  • Die tipe kontroleringstelsel kan 'n paar klein (en nie so klein) foute opspoor. 'n Tipiese voorbeeld is wanneer hulle vergeet om 'n waarde te verwerk None of 'n ander spesiale toestand.
  • Kode herfaktorering is baie vereenvoudig omdat die tipe kontroleringstelsel dikwels baie akkuraat is oor watter kode verander moet word. Terselfdertyd hoef ons nie te hoop op 100% kodedekking met toetse nie, wat in elk geval gewoonlik nie haalbaar is nie. Ons hoef nie in die dieptes van die stapelspoor te delf om die oorsaak van die probleem uit te vind nie.
  • Selfs op groot projekte kan mypy dikwels in 'n breukdeel van 'n sekonde volledige tipe kontrolering doen. En die uitvoering van toetse neem gewoonlik tien sekondes of selfs minute. Die tipe kontroleringstelsel gee die programmeerder onmiddellike terugvoer en laat hom toe om sy werk vinniger te doen. Hy hoef nie meer brose en moeilike eenheidstoetse te skryf wat werklike entiteite vervang met spotters en lappies net om kodetoetsresultate vinniger te kry nie.

IDE's en redigeerders soos PyCharm of Visual Studio Code gebruik die krag van tipe-aantekeninge om ontwikkelaars te voorsien van kodevoltooiing, foutuitlig en ondersteuning vir algemeen gebruikte taalkonstruksies. En dit is net 'n paar van die voordele van tik. Vir sommige programmeerders is dit alles die hoofargument ten gunste van tik. Dit is iets wat onmiddellik na implementering baat. Hierdie gebruiksgeval vir tipes vereis nie 'n aparte tipe kontroleringstelsel soos mypy nie, alhoewel daar kennis geneem moet word dat mypy help om tipe-aantekeninge in ooreenstemming met kode te hou.

Agtergrond van mypy

Die geskiedenis van mypy het begin in die Verenigde Koninkryk, in Cambridge, 'n paar jaar voordat ek by Dropbox aangesluit het. Ek was betrokke, as deel van my doktorale navorsing, by die eenwording van staties getikte en dinamiese tale. Ek is geïnspireer deur 'n artikel oor inkrementele tik deur Jeremy Siek en Walid Taha, en deur die Tiped Racket-projek. Ek het maniere probeer vind om dieselfde programmeertaal vir verskeie projekte te gebruik – van klein skrifte tot kodebasisse wat uit baie miljoene reëls bestaan. Terselfdertyd wou ek verseker dat in 'n projek van enige skaal, 'n mens nie te groot kompromieë hoef te maak nie. 'n Belangrike deel van dit alles was die idee om geleidelik van 'n ongetikte prototipeprojek na 'n omvattend getoetste staties getikte voltooide produk te beweeg. Hierdie idees word deesdae grootliks as vanselfsprekend aanvaar, maar in 2010 was dit ’n probleem wat steeds aktief ondersoek is.

My oorspronklike werk in tipe nagaan was nie gemik op Python nie. In plaas daarvan het ek 'n klein "tuisgemaakte" taal gebruik Alore. Hier is 'n voorbeeld wat jou sal laat verstaan ​​waaroor ons praat (tipe aantekeninge is hier opsioneel):

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

Die gebruik van 'n vereenvoudigde moedertaal is 'n algemene benadering wat in wetenskaplike navorsing gebruik word. Dit is so, nie die minste nie omdat dit jou toelaat om vinnig eksperimente uit te voer, en ook as gevolg van die feit dat wat niks met die studie te doen het nie maklik geïgnoreer kan word. Werklike programmeertale is geneig om grootskaalse verskynsels te wees met komplekse implementerings, en dit vertraag eksperimentering. Enige resultate gebaseer op 'n vereenvoudigde taal lyk egter 'n bietjie verdag, aangesien die navorser met die verkryging van hierdie resultate moontlike oorwegings wat belangrik is vir die praktiese gebruik van tale opgeoffer het.

My tipe kontroleerder vir Alore het baie belowend gelyk, maar ek wou dit uittoets deur met regte kode te eksperimenteer, wat, kan jy sê, nie in Alore geskryf is nie. Gelukkig vir my was die Alore-taal grootliks gebaseer op dieselfde idees as Python. Dit was maklik genoeg om die tiktoetser te hermaak sodat dit met Python se sintaksis en semantiek kon werk. Dit het ons in staat gestel om te probeer om die oopbron Python-kode in te tik. Daarbenewens het ek 'n transpiler geskryf om kode wat in Alore geskryf is, om te skakel na Python-kode en dit gebruik om my typechecker-kode te vertaal. Nou het ek 'n tipe kontroleringstelsel gehad wat in Python geskryf is wat 'n subset van Python ondersteun het, 'n soort van daardie taal! (Sekere argitektoniese besluite wat vir Alore sin gemaak het, was swak geskik vir Python, en dit is steeds opvallend in dele van die mypy-kodebasis.)

Trouens, die taal wat deur my tipe stelsel ondersteun word, kon op hierdie stadium nie heeltemal Python genoem word nie: dit was 'n variant van Python as gevolg van sekere beperkings van die Python 3 tipe annotasie sintaksis.

Dit het gelyk soos 'n mengsel van Java en Python:

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

Een van my idees destyds was om tipe-aantekeninge te gebruik om werkverrigting te verbeter deur hierdie soort Python saam te stel na C, of ​​dalk JVM-greepkode. Ek het op die stadium gekom om 'n samesteller-prototipe te skryf, maar ek het hierdie idee laat vaar, aangesien tipe-kontrolering self baie nuttig gelyk het.

Ek het uiteindelik my projek by PyCon 2013 in Santa Clara aangebied. Ek het ook hieroor gesels met Guido van Rossum, die welwillende Python-diktator lewenslank. Hy het my oortuig om my eie sintaksis te laat vaar en by die standaard Python 3-sintaksis te hou. Python 3 ondersteun funksie-aantekeninge, so my voorbeeld kan herskryf word soos hieronder getoon, wat 'n normale Python-program tot gevolg het:

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

Ek moes 'n paar kompromieë maak (eerste van alles, ek wil daarop let dat ek my eie sintaksis uitgevind het om hierdie rede). Python 3.3, die mees onlangse weergawe van die taal op daardie stadium, het veral nie veranderlike annotasies ondersteun nie. Ek het met Guido per e-pos verskeie moontlikhede vir sintaktiese ontwerp van sulke aantekeninge bespreek. Ons het besluit om tipe opmerkings vir veranderlikes te gebruik. Dit het die beoogde doel gedien, maar was ietwat omslagtig (Python 3.6 het vir ons 'n mooier sintaksis gegee):

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

Tipe opmerkings het ook handig te pas gekom om Python 2 te ondersteun, wat nie ingeboude ondersteuning vir tipe aantekeninge het nie:

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

Dit het geblyk dat hierdie (en ander) afwegings nie regtig saak maak nie – die voordele van statiese tik het veroorsaak dat gebruikers gou vergeet het van minder as ideale sintaksis. Aangesien geen spesiale sintaktiese konstrukte in die tipe-gekontroleerde Python-kode gebruik is nie, het bestaande Python-nutsmiddels en kodeverwerkingsprosesse normaal voortgegaan om dit vir ontwikkelaars baie makliker te maak om die nuwe instrument te leer.

Guido het my ook oortuig om by Dropbox aan te sluit nadat ek my nagraadse tesis voltooi het. Dit is waar die interessantste deel van die mypy-storie begin.

Vervolg…

Beste lesers! As jy Python gebruik, vertel ons asseblief van die omvang van projekte wat jy in hierdie taal ontwikkel.

Die pad na tikkontrolering van 4 miljoen reëls Python-kode. Deel 1
Die pad na tikkontrolering van 4 miljoen reëls Python-kode. Deel 1

Bron: will.com

Voeg 'n opmerking