Hari ini kami menyampaikan kepada Anda bagian pertama dari terjemahan materi tentang bagaimana Dropbox terlibat dalam kontrol tipe kode Python.

Dropbox banyak menulis dalam Python. Ini adalah bahasa yang kami gunakan sangat luas - baik untuk layanan backend dan aplikasi klien desktop. Kami juga menggunakan Go, TypeScript dan Rust dalam volume besar, tetapi Python adalah bahasa utama kami. Mengingat ruang lingkup kami, dan kami berbicara tentang jutaan baris kode Python, ternyata pengetikan dinamis kode semacam itu tidak perlu mempersulit pemahamannya dan mulai secara serius memengaruhi produktivitas. Untuk mengatasi masalah ini, kami mulai menerjemahkan kode kami secara bertahap ke pemeriksaan tipe statis menggunakan mypy. Ini mungkin adalah sistem pengecekan tipe mandiri yang paling populer untuk Python. Mypy adalah proyek sumber terbuka, pengembang utamanya bekerja di Dropbox.
Dropbox adalah salah satu perusahaan pertama yang menerapkan pemeriksaan tipe statis dalam kode Python pada skala yang sama. Saat ini, mypy digunakan dalam ribuan proyek. Alat ini berkali-kali, seperti yang mereka katakan, "diuji dalam pertempuran." Kita, untuk sampai ke tempat kita sekarang, harus menempuh jalan yang jauh. Di jalan ini ada banyak usaha yang gagal dan eksperimen yang gagal. Materi ini adalah tentang sejarah pengecekan tipe statis dengan Python - dari awal yang sangat sulit, yang merupakan bagian dari proyek penelitian ilmiah saya, hingga saat ini, ketika pengecekan tipe dan petunjuk tipe telah menjadi akrab bagi banyak pengembang yang menulis dengan Python. Mekanisme ini sekarang didukung oleh banyak alat - seperti IDE dan penganalisa kode.
→
Baca bagian keduaMengapa pemeriksaan jenis perlu dilakukan?
Jika Anda pernah menggunakan Python yang diketik secara dinamis, Anda mungkin bingung mengapa buzz semacam itu akhir-akhir ini ada di sekitar pengetikan statis dan mypy. Atau mungkin Anda menyukai Python karena ketikannya yang dinamis, dan apa yang terjadi hanya membuat Anda kesal. Kunci nilai pengetikan statis adalah skala keputusan: semakin besar proyek Anda, semakin Anda cenderung mengetik statis, dan, pada akhirnya, semakin Anda sangat membutuhkannya.
Misalkan sebuah proyek mencapai puluhan ribu baris, dan ternyata beberapa programmer sedang mengerjakannya. Mempertimbangkan proyek semacam itu, berdasarkan pengalaman kami, kami dapat mengatakan bahwa memahami kodenya akan menjadi kunci untuk mendukung produktivitas pengembang. Tanpa anotasi jenis, tidak mudah untuk mencari tahu, misalnya, argumen mana yang perlu Anda sampaikan ke fungsi, atau nilai-nilai dari tipe mana suatu fungsi dapat kembali. Berikut adalah pertanyaan umum yang seringkali sulit dijawab tanpa menggunakan anotasi jenis:
- Bisakah fungsi ini mengembalikan
None
? - Apa yang harus menjadi argumen
items
? - Apa itu
id
: tipe atribut int
, apakah itu str
, atau mungkin beberapa tipe khusus? - Haruskah argumen ini menjadi daftar? Apakah mungkin memasukkan tuple ke dalamnya?
Jika Anda melihat potongan kode berikut, dilengkapi dengan jenis anotasi, dan mencoba menjawab pertanyaan seperti itu, ternyata ini adalah tugas yang paling sederhana:
class Resource: id: bytes ... def read_metadata(self, items: Sequence[str]) -> Dict[str, MetadataItem]: ...
read_metadata
kembali None
, karena jenis kembali tidak Optional[…]
.- Argumen
items
adalah urutan string. Hal ini tidak dapat mengulangi dalam urutan acak. - Atribut
id
- ini adalah string byte.
Dalam dunia yang ideal, orang akan berharap bahwa semua seluk-beluk ini akan dijelaskan dalam dokumen internal (docstring). Tetapi pengalaman memberikan banyak contoh fakta bahwa dokumentasi seperti itu dalam kode yang harus Anda kerjakan seringkali tidak diperhatikan. Bahkan jika dokumentasi tersebut dalam kode dan sekarang, tidak bisa mengandalkan itu adalah mutlak benar. Dokumentasi ini mungkin tidak jelas, tidak akurat, meninggalkan banyak kemungkinan untuk kesalahpahamannya. Dalam tim besar atau dalam proyek besar, masalah ini bisa menjadi sangat akut.
Meskipun Python berkinerja baik di tahap awal atau menengah proyek, pada beberapa titik proyek yang sukses dan perusahaan yang menggunakan Python mungkin muncul dengan pertanyaan penting: "Apakah kita perlu menulis ulang semuanya dalam bahasa yang diketik secara statis?"
jenis sistem pemeriksaan seperti mypy mengatasi permasalahan di atas karena fakta yang memberikan pengembang bahasa formal untuk menggambarkan jenis dan fakta bahwa cek tersebut untuk menggambarkan jenis akan sesuai dengan pelaksanaan program (dan, opsional, memverifikasi keberadaan mereka). Secara umum, kita dapat mengatakan bahwa sistem ini memberi kita sesuatu seperti dokumentasi yang diperiksa dengan cermat.
Penggunaan sistem tersebut memiliki kelebihan lain, dan mereka sudah sepenuhnya non-pribadi:
- Sistem pemeriksaan tipe dapat mendeteksi beberapa kesalahan kecil (dan juga tidak terlalu kecil). Sebuah contoh khas - adalah ketika Anda lupa untuk mengurai nilai
None
atau beberapa kondisi khusus lainnya. - Refactoring kode sangat disederhanakan karena sistem pemeriksaan tipe sering sangat akurat melaporkan kode mana yang perlu diubah. Dalam hal ini, kita tidak perlu berharap untuk cakupan kode 100% dengan tes, yang, dalam hal apapun, biasanya tidak mungkin. Kami tidak perlu memeriksa kedalaman laporan pelacakan tumpukan untuk mengetahui penyebab masalahnya.
- Bahkan dalam proyek besar, mypy sering dapat melakukan pemeriksaan tipe penuh dalam sepersekian detik. Dan pelaksanaan tes biasanya memakan waktu puluhan detik atau bahkan menit. Sistem pengecekan tipe memberikan umpan balik instan kepada programmer dan memungkinkannya untuk melakukan pekerjaannya lebih cepat. Dia tidak lagi perlu menulis unit test yang rapuh dan berat yang menggantikan entitas nyata dengan mokas dan patch hanya untuk mendapatkan hasil tes kode lebih cepat.
IDE dan editor, seperti PyCharm atau Visual Studio Code, menggunakan kekuatan anotasi jenis untuk memberikan pengembang kemampuan untuk melengkapi kode secara otomatis, menyoroti kesalahan, dan mendukung konstruksi bahasa yang umum digunakan. Dan ini hanyalah beberapa keuntungan yang diberikan oleh mengetik. Untuk beberapa programmer, semua ini adalah argumen utama yang mendukung pengetikan. Inilah manfaatnya segera setelah implementasi. Kasing jenis penggunaan ini tidak memerlukan sistem pemeriksaan jenis yang terpisah, seperti mypy, walaupun harus dicatat bahwa mypy membantu menjaga konsistensi antara anotasi jenis dan kode.
latar belakang mypy
Kisah mypy dimulai di Inggris, di Cambridge, beberapa tahun sebelum saya bergabung dengan Dropbox. Sebagai bagian dari penelitian doktoral saya, saya berurusan dengan penyatuan bahasa yang diketik dan dinamis secara statis. Saya terinspirasi oleh sebuah artikel tentang pengetikan Jeremy Siek dan Walid Taha secara bertahap, serta proyek Typed Racket. Saya mencoba untuk menemukan cara untuk menggunakan bahasa pemrograman yang sama untuk berbagai proyek - dari script kecil untuk database kode yang terdiri dari jutaan baris. Pada saat yang sama, saya ingin proyek dalam skala berapa pun tidak perlu membuat kompromi terlalu besar. Bagian penting dari semua ini adalah gagasan tentang transisi bertahap dari proyek prototipe yang tidak diketik ke produk jadi yang diketik secara statis dan diuji secara komprehensif. Saat ini, ide-ide ini sebagian besar diterima begitu saja, tetapi pada tahun 2010 itu adalah masalah yang masih dieksplorasi secara aktif.
Pekerjaan awal saya di bidang pemeriksaan tipe tidak ditujukan untuk Python. Sebagai gantinya, saya menggunakan sedikit bahasa "buatan"
Alore . Berikut adalah contoh yang akan membuat Anda memahami apa yang dipertaruhkan (ketik anotasi adalah opsional di sini):
def Fib(n as Int) as Int if n <= 1 return n else return Fib(n - 1) + Fib(n - 2) end end
Menggunakan bahasa yang disederhanakan dari desain kami sendiri adalah pendekatan umum yang digunakan dalam penelitian ilmiah. Ini tidak lain karena fakta bahwa ini memungkinkan Anda untuk dengan cepat melakukan eksperimen, dan juga karena fakta bahwa penelitian itu tidak relevan, dapat diabaikan dengan bebas. Sebenarnya bahasa pemrograman yang digunakan biasanya fenomena skala besar dengan implementasi yang kompleks, dan ini memperlambat eksperimen. Namun, setiap hasil berdasarkan bahasa yang disederhanakan terlihat sedikit mencurigakan, karena ketika hasil itu diperoleh, peneliti mungkin telah mengorbankan pertimbangan yang penting untuk penggunaan praktis bahasa.
Alat pengecekan tipe saya untuk Alore terlihat sangat menjanjikan, tetapi saya ingin mengujinya dengan bereksperimen dengan kode asli, yang, bisa dikatakan, tidak ditulis di Alore. Untungnya, bahasa Alore sebagian besar didasarkan pada gagasan yang sama dengan Python. Itu cukup mudah untuk mengubah sarana untuk memverifikasi jenis sehingga bisa bekerja dengan sintaks Python dan semantik. Ini memungkinkan kami untuk mencoba mengetikkan centang pada kode Python open source. Selain itu, saya menulis transporter untuk mengonversi kode yang ditulis dengan Alore ke kode Python dan menggunakannya untuk menerjemahkan kode alat pengecekan tipe saya. Sekarang saya telah memiliki sistem untuk memverifikasi jenis ditulis dengan Python, yang didukung Python bagian, beberapa jenis bahasa! (Solusi arsitektur tertentu yang masuk akal untuk Alore tidak cocok untuk Python, yang masih terlihat di bagian basis kode mypy.)
Sebenarnya, bahasa yang didukung oleh sistem tipe saya pada saat itu tidak mungkin disebut Python: itu adalah varian Python karena beberapa batasan sintaksis penjelasan jenis Python 3.
Itu tampak seperti campuran Jawa dan Python:
int fib(int n): if n <= 1: return n else: return fib(n - 1) + fib(n - 2)
Salah satu ide saya pada saat itu adalah menggunakan anotasi jenis untuk meningkatkan kinerja dengan mengkompilasi jenis Python ini dalam C, atau mungkin dalam bytecode JVM. Saya maju ke tahap penulisan prototipe kompiler, tetapi saya meninggalkan usaha ini, karena pengecekan tipe itu sendiri terlihat cukup berguna.
Pada akhirnya, saya mempresentasikan proyek saya pada konferensi PyCon 2013 di Santa Clara. Saya juga membicarakan hal ini dengan Guido van Rossum, diktator Python yang murah hati. Dia meyakinkan saya untuk meninggalkan sintaks saya sendiri dan tetap menggunakan sintaks standar Python 3. Python 3 mendukung anotasi fungsi, sebagai hasilnya, contoh saya dapat ditulis ulang seperti yang ditunjukkan di bawah ini, mendapatkan program Python normal:
def fib(n: int) -> int: if n <= 1: return n else: return fib(n - 1) + fib(n - 2)
Saya perlu membuat beberapa kompromi (pertama-tama, saya ingin mencatat bahwa saya menemukan sintaks saya sendiri untuk alasan ini). Secara khusus, Python 3.3, versi bahasa terbaru saat itu, tidak mendukung anotasi variabel. Saya telah berdiskusi dengan Guido melalui email tentang berbagai kemungkinan untuk menyinkronkan anotasi tersebut. Kami memutuskan untuk menggunakan untuk komentar variabel yang menunjukkan jenis. Ini memungkinkan kami untuk mencapai tujuan kami, tetapi itu terlihat agak rumit (Python 3.6 memberi kami sintaks yang lebih menyenangkan):
products = []
Komentar untuk jenis juga berguna untuk mendukung Python 2, yang tidak memiliki dukungan asli untuk jenis anotasi:
f fib(n):
Ternyata kompromi ini (dan lainnya), pada kenyataannya, tidak memiliki banyak arti - keuntungan dari pengetikan statis menyebabkan fakta bahwa pengguna segera melupakan sintaks yang tidak cukup sempurna. Karena tidak ada konstruksi sintaks khusus yang digunakan dalam kode Python di mana jenis dikontrol, alat Python yang ada dan proses pemrosesan kode terus bekerja secara normal, yang sangat memudahkan pengembangan alat baru oleh pengembang.
Guido juga membujuk saya untuk bergabung Dropbox setelah saya membela tesis kelulusan saya. Di sinilah bagian yang menyenangkan dalam sejarah mypy dimulai.
Dilanjutkan ...
Pembaca yang budiman! Jika Anda menggunakan Python, beri tahu kami tentang skala proyek yang Anda kembangkan dalam bahasa ini.
