Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3

Wir präsentieren Ihnen den dritten Teil der Materialübersetzung über den Weg, den Dropbox bei der Implementierung eines Typprüfungssystems für Python-Code eingeschlagen hat.

Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3

→ Vorherige Teile: erste и zweite

Erreichen von 4 Millionen Zeilen getipptem Code

Eine weitere große Herausforderung (und die zweithäufigste Sorge der intern Befragten) war die Erhöhung der Codemenge, die von Typprüfungen in Dropbox abgedeckt wird. Wir haben verschiedene Ansätze zur Lösung dieses Problems ausprobiert, von der natürlichen Vergrößerung der typisierten Codebasis bis hin zur Konzentration der Bemühungen des Mypy-Teams auf statische und dynamische automatisierte Typinferenz. Am Ende schien es, als gäbe es keine einfache Erfolgsstrategie, aber wir konnten durch die Kombination vieler Ansätze ein schnelles Wachstum des Volumens an annotierten Codes erreichen.

Infolgedessen verfügt unser größtes Python-Repository (mit Backend-Code) über fast 4 Millionen Zeilen annotierten Codes. Die Arbeiten zur statischen Codetypisierung wurden in etwa drei Jahren abgeschlossen. Mypy unterstützt jetzt verschiedene Arten von Codeabdeckungsberichten, die es einfacher machen, den Tippfortschritt zu überwachen. Insbesondere können wir Berichte über Code mit Unklarheiten in den Typen erstellen, wie zum Beispiel die explizite Verwendung eines Typs Any in Annotationen, die nicht verifiziert werden können, oder bei Dingen wie dem Importieren von Bibliotheken von Drittanbietern, die keine Typanmerkungen haben. Im Rahmen eines Projekts zur Verbesserung der Genauigkeit der Typprüfung in Dropbox haben wir dazu beigetragen, die Typdefinitionen (sogenannte Stub-Dateien) für einige beliebte Open-Source-Bibliotheken in einem zentralen Python-Repository zu verbessern Maschinenschuppen.

Wir haben neue Funktionen des Typsystems implementiert (und in nachfolgenden PEPs standardisiert), die präzisere Typen für einige spezifische Python-Muster ermöglichen. Ein bemerkenswertes Beispiel hierfür ist TypeDict, das Typen für JSON-ähnliche Wörterbücher bereitstellt, die über einen festen Satz von Zeichenfolgenschlüsseln verfügen, von denen jeder einen Wert seines eigenen Typs hat. Wir werden das Typensystem weiter ausbauen. Unser nächster Schritt wird wahrscheinlich darin bestehen, die Unterstützung für die numerischen Fähigkeiten von Python zu verbessern.

Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Anzahl der Zeilen mit annotiertem Code: Server

Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Anzahl der Zeilen mit annotiertem Code: Client

Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Gesamtzahl der Zeilen mit annotiertem Code

Hier ist ein Überblick über die Hauptfunktionen der Dinge, die wir unternommen haben, um die Menge an annotiertem Code in Dropbox zu erhöhen:

Genauigkeit der Anmerkungen. Wir haben die Anforderungen an die Genauigkeit der Kommentierung von neuem Code schrittweise erhöht. Wir begannen mit Linter-Tipps, die das Hinzufügen von Anmerkungen zu Dateien vorschlugen, die bereits einige Anmerkungen enthielten. Wir benötigen jetzt Typanmerkungen in neuen Python-Dateien und in den meisten vorhandenen Dateien.

Berichte schreiben. Wir senden den Teams wöchentlich Berichte über den Grad der Eingabe ihres Codes und geben Ratschläge, was zuerst annotiert werden sollte.

Popularisierung von Mypy. Wir sprechen bei Veranstaltungen über mypy und sprechen mit Teams, um ihnen den Einstieg in Typanmerkungen zu erleichtern.

Umfragen. Wir führen regelmäßig Benutzerbefragungen durch, um größere Probleme zu identifizieren. Wir sind bereit, bei der Lösung dieser Probleme ziemlich weit zu gehen (sogar die Entwicklung einer neuen Sprache, um mypy zu beschleunigen!).

Leistung. Wir haben die Leistung von mypy durch die Verwendung des Daemons und mypyc erheblich verbessert. Dies wurde durchgeführt, um die während des Annotationsprozesses auftretenden Unannehmlichkeiten auszugleichen und um mit großen Codemengen arbeiten zu können.

Integration mit Editoren. Wir haben Tools entwickelt, die die Ausführung von mypy in Editoren unterstützen, die bei Dropbox beliebt sind. Dazu gehören PyCharm, Vim und VS Code. Dies vereinfachte den Prozess der Kommentierung des Codes und der Überprüfung seiner Funktionalität erheblich. Diese Art von Aktionen kommt häufig vor, wenn vorhandener Code mit Anmerkungen versehen wird.

Statische Analyse. Wir haben ein Tool erstellt, um mithilfe statischer Analysetools Funktionssignaturen abzuleiten. Dieses Tool kann nur in relativ einfachen Situationen funktionieren, aber es hat uns dabei geholfen, die Abdeckung unserer Codetypen ohne großen Aufwand zu erweitern.

Unterstützung für Bibliotheken von Drittanbietern. Viele unserer Projekte verwenden das SQLAlchemy-Toolkit. Es nutzt die dynamischen Fähigkeiten von Python, die PEP 484-Typen nicht direkt modellieren können. Wir haben gemäß PEP 561 die entsprechende Stub-Datei erstellt und ein Plugin für mypy geschrieben (Open Source), was die SQLAlchemy-Unterstützung verbessert.

Schwierigkeiten, auf die wir gestoßen sind

Der Weg zu 4 Millionen Zeilen getipptem Code war für uns nicht immer einfach. Auf diesem Weg stießen wir auf viele Schlaglöcher und machten mehrere Fehler. Dies sind einige der Probleme, auf die wir gestoßen sind. Wir hoffen, dass das Erzählen davon anderen hilft, ähnliche Probleme zu vermeiden.

Fehlende Dateien. Wir begannen unsere Arbeit mit der Überprüfung nur einer kleinen Anzahl von Dateien. Alles, was nicht in diesen Dateien enthalten war, wurde nicht überprüft. Dateien wurden zur Scanliste hinzugefügt, als die ersten Anmerkungen darin erschienen. Wenn etwas aus einem Modul importiert wurde, das außerhalb des Überprüfungsbereichs liegt, dann sprachen wir über die Arbeit mit Werten wie Any, die überhaupt nicht getestet wurden. Dies führte insbesondere in den frühen Phasen der Migration zu einem erheblichen Verlust der Tippgenauigkeit. Dieser Ansatz hat bisher überraschend gut funktioniert, obwohl eine typische Situation darin besteht, dass das Hinzufügen von Dateien zum Prüfumfang Probleme in anderen Teilen der Codebasis aufdeckt. Im schlimmsten Fall stellte sich bei der Zusammenführung zweier isolierter Codebereiche, in denen unabhängig voneinander bereits Typen überprüft wurden, heraus, dass die Typen dieser Bereiche nicht miteinander kompatibel waren. Dies führte dazu, dass viele Änderungen an den Anmerkungen vorgenommen werden mussten. Wenn wir jetzt zurückblicken, wird uns klar, dass wir Kernbibliotheksmodule früher zum Typprüfungsbereich von mypy hätten hinzufügen sollen. Dies würde unsere Arbeit viel vorhersehbarer machen.

Kommentieren von altem Code. Als wir anfingen, verfügten wir über etwa 4 Millionen Zeilen vorhandenen Python-Codes. Es war klar, dass es keine leichte Aufgabe war, diesen gesamten Code mit Anmerkungen zu versehen. Wir haben ein Tool namens PyAnnotate erstellt, das während der Testausführung Typinformationen sammeln und basierend auf den gesammelten Informationen Typanmerkungen zu Ihrem Code hinzufügen kann. Allerdings konnten wir keine besonders weite Verbreitung dieses Tools feststellen. Das Sammeln von Typinformationen war langsam und automatisch generierte Anmerkungen erforderten oft viele manuelle Bearbeitungen. Wir dachten darüber nach, dieses Tool jedes Mal automatisch auszuführen, wenn wir den Code überprüfen, oder Typinformationen basierend auf der Analyse einer kleinen Menge tatsächlicher Netzwerkanfragen zu sammeln, haben uns aber dagegen entschieden, weil beide Ansätze zu riskant waren.

Als Ergebnis lässt sich feststellen, dass der Großteil des Codes von seinen Besitzern manuell mit Anmerkungen versehen wurde. Um diesen Prozess in die richtige Richtung zu lenken, erstellen wir Berichte zu besonders wichtigen Modulen und Funktionen, die kommentiert werden müssen. Beispielsweise ist es wichtig, Typanmerkungen für ein Bibliotheksmodul bereitzustellen, das an Hunderten von Stellen verwendet wird. Aber es ist nicht mehr so ​​wichtig, einen alten Dienst zu kommentieren, der durch einen neuen ersetzt wird. Wir experimentieren auch mit der statischen Analyse, um Typanmerkungen für Legacy-Code zu generieren.

Zyklische Importe. Oben habe ich über zyklische Importe (die „Abhängigkeitsgewirr“) gesprochen, deren Existenz es schwierig machte, mypy zu beschleunigen. Wir mussten auch hart daran arbeiten, dass mypy alle Arten von Redewendungen unterstützt, die durch diese zyklischen Importe verursacht werden. Wir haben kürzlich ein großes System-Redesign-Projekt abgeschlossen, das die meisten Probleme von mypy in Bezug auf zirkuläre Importe behoben hat. Diese Probleme rührten tatsächlich aus den frühen Tagen des Projekts, also aus Alore, der Bildungssprache, auf die sich das Mypy-Projekt ursprünglich konzentrierte. Die Alore-Syntax erleichtert die Lösung von Problemen mit zyklischen Importbefehlen. Das moderne Mypy hat einige Einschränkungen von seiner früheren, einfältigen Implementierung übernommen (die hervorragend zu Alore passte). Python erschwert die Arbeit mit zirkulären Importen, vor allem weil Ausdrücke mehrdeutig sind. Beispielsweise kann eine Zuweisungsoperation tatsächlich einen Typalias definieren. Mypy ist nicht immer in der Lage, solche Dinge zu erkennen, bis der Großteil der Importschleife verarbeitet wurde. In Alore gab es solche Unklarheiten nicht. Schlechte Entscheidungen, die in den frühen Phasen der Systementwicklung getroffen werden, können für den Programmierer viele Jahre später eine unangenehme Überraschung darstellen.

Ergebnisse: der Weg zu 5 Millionen Codezeilen und neuen Horizonten

Das mypy-Projekt hat einen langen Weg zurückgelegt – von frühen Prototypen bis hin zu einem System, das 4 Millionen Zeilen Produktionscodetypen steuert. Mit der Weiterentwicklung von mypy wurden die Typhinweise von Python standardisiert. Heutzutage hat sich rund um die Eingabe von Python-Code ein leistungsstarkes Ökosystem entwickelt. Es bietet Platz für Bibliotheksunterstützung, enthält Hilfstools für IDEs und Editoren und verfügt über mehrere Typkontrollsysteme, von denen jedes seine eigenen Vor- und Nachteile hat.

Auch wenn die Typprüfung bei Dropbox bereits selbstverständlich ist, glaube ich, dass wir uns noch in den Anfängen der Eingabe von Python-Code befinden. Ich denke, dass sich die Technologien zur Typprüfung weiterentwickeln und verbessern werden.

Wenn Sie die Typprüfung in Ihrem großen Python-Projekt noch nicht verwendet haben, wissen Sie, dass jetzt ein sehr guter Zeitpunkt ist, mit der statischen Typisierung zu beginnen. Ich habe mit denen gesprochen, die einen ähnlichen Übergang vollzogen haben. Keiner von ihnen hat es bereut. Durch die Typprüfung ist Python eine Sprache, die sich viel besser für die Entwicklung großer Projekte eignet als „normales Python“.

Liebe Leser! Verwenden Sie in Ihren Python-Projekten die Typprüfung?

Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3
Der Weg zur Typprüfung von 4 Millionen Zeilen Python-Code. Teil 3

Source: habr.com

Kommentar hinzufügen