Pembaruan arsitektur DevTools: memigrasikan DevTools ke TypeScript

Tim van der Lippe
Tim van der Lippe

Postingan ini adalah bagian dari serangkaian postingan blog yang menjelaskan perubahan yang kami lakukan pada arsitektur DevTools dan cara pembuatannya.

Menindaklanjuti migrasi ke modul JavaScript dan migrasi ke Komponen Web, hari ini kami melanjutkan rangkaian postingan blog tentang perubahan yang kami lakukan pada arsitektur Devtools dan cara pembuatannya. (Jika Anda belum melihatnya, kami memposting video tentang pekerjaan kami tentang Mengupgrade arsitektur DevTools ke web modern, yang berisi 14 tips tentang cara meningkatkan project web Anda.)

Dalam postingan ini, kami akan menjelaskan perjalanan 13 bulan kami beralih dari pemeriksa jenis Closure Compiler ke TypeScript.

Pengantar

Mengingat ukuran codebase DevTools dan kebutuhan untuk memberikan kepercayaan diri kepada para engineer yang mengerjakannya, penggunaan pemeriksa jenis adalah suatu keharusan. Untuk itu, DevTools menggunakan Closure Compiler pada tahun 2013. Dengan mengadopsi Closure, para engineer DevTools dapat membuat perubahan dengan percaya diri; compiler Closure akan melakukan pemeriksaan jenis untuk memastikan bahwa semua integrasi sistem diketik dengan baik.

Namun, seiring berjalannya waktu, pemeriksa jenis alternatif menjadi populer dalam pengembangan web modern. Dua contoh utamanya adalah TypeScript dan Flow. Selain itu, TypeScript menjadi bahasa pemrograman resmi di Google. Meskipun pemeriksa jenis baru ini makin populer, kami juga memperhatikan bahwa kami mengirimkan regresi yang seharusnya terdeteksi oleh pemeriksa jenis. Oleh karena itu, kami memutuskan untuk mengevaluasi kembali pilihan pemeriksa jenis kami dan mencari tahu langkah selanjutnya untuk pengembangan di DevTools.

Mengevaluasi pemeriksa jenis

Karena DevTools sudah menggunakan pemeriksa jenis, pertanyaan yang harus kami jawab adalah:

Apakah kami akan terus menggunakan Closure Compiler atau bermigrasi ke pemeriksa jenis baru?

Untuk menjawab pertanyaan ini, kita harus mengevaluasi pemeriksa jenis berdasarkan beberapa karakteristik. Karena penggunaan pemeriksa jenis kami berfokus pada keyakinan engineer, aspek terpenting bagi kami adalah ketepatan jenis. Dengan kata lain: Seberapa andal pemeriksa jenis dalam menemukan masalah nyata?

Evaluasi kami berfokus pada regresi yang telah kami hasilkan dan menentukan apa yang menjadi akar penyebabnya. Asumsinya adalah, karena kita sudah menggunakan Closure Compiler, Closure tidak akan dapat mendeteksi masalah ini. Oleh karena itu, kami harus menentukan apakah pemeriksa jenis lainnya bisa melakukannya.

Ketepatan ketik di TypeScript

Karena TypeScript adalah bahasa pemrograman yang didukung secara resmi di Google dan makin populer dengan cepat, kami memutuskan untuk mengevaluasi TypeScript terlebih dahulu. TypeScript adalah pilihan yang menarik, karena tim TypeScript sendiri menggunakan DevTools sebagai salah satu project pengujian mereka untuk melacak kompatibilitasnya dengan pemeriksaan jenis JavaScript. Output pengujian referensi dasar pengukuran mereka menunjukkan bahwa TypeScript mengalami banyak masalah jenis - masalah yang tidak selalu terdeteksi oleh compiler Closure. Banyak dari masalah ini kemungkinan besar menjadi akar penyebab regresi yang kami kirimkan; ini, pada akhirnya, membuat kami percaya bahwa TypeScript bisa menjadi opsi yang tepat untuk DevTools.

Selama migrasi ke modul JavaScript, kami mendapati bahwa Closure Compiler menemukan lebih banyak masalah daripada sebelumnya. Peralihan ke format modul standar telah meningkatkan kemampuan Closure untuk memahami codebase kami, sehingga meningkatkan efektivitas pemeriksa jenis. Namun, tim TypeScript menggunakan versi dasar DevTools sebelum migrasi modul JavaScript. Oleh karena itu, kami harus mencari tahu apakah migrasi ke modul JavaScript juga telah mengurangi jumlah error yang akan ditangkap compiler TypeScript.

Mengevaluasi TypeScript

DevTools telah ada selama lebih dari satu dekade, tempatnya telah berkembang menjadi aplikasi web yang berukuran cukup besar dan kaya fitur. Pada saat penulisan postingan blog ini, DevTools berisi sekitar 150.000 baris kode JavaScript pihak pertama. Saat kami menjalankan compiler TypeScript pada kode sumber, volume error yang besar membuat kewalahan. Kami dapat mengetahui bahwa meskipun compiler TypeScript memunculkan lebih sedikit kesalahan terkait dengan resolusi kode (~ 2.000 kesalahan), masih ada 6.000 kesalahan lebih lanjut dalam codebase kami yang terkait dengan kompatibilitas jenis.

Hal ini menunjukkan bahwa meskipun TypeScript dapat memahami cara me-resolve jenis, ini menemukan sejumlah besar inkompatibilitas jenis dalam codebase kami. Analisis manual atas error ini menunjukkan bahwa TypeScript (sering kali) sudah benar. Alasan TypeScript dapat mendeteksi ini dan Closure bukan karena compiler Closure sering kali menyimpulkan jenis sebagai Any, sedangkan TypeScript akan melakukan inferensi jenis berdasarkan penetapan dan menyimpulkan jenis yang lebih akurat. Dengan demikian, TypeScript memang lebih baik dalam memahami struktur objek dan menemukan penggunaan yang bermasalah.

Salah satu tangkapan penting untuk hal ini adalah penggunaan compiler Closure di DevTools menyertakan penggunaan @unrestricted yang sering. Menganotasi class dengan @unrestricted secara efektif menonaktifkan pemeriksaan properti yang ketat pada compiler Closure untuk class tertentu, yang berarti bahwa developer dapat menambah definisi class sesuai keinginan tanpa keamanan jenis. Kami tidak dapat menemukan konteks historis terkait alasan penggunaan @unrestricted lazim digunakan dalam codebase DevTools, tetapi hal ini mengakibatkan compiler Closure menjalankan compiler Closure dalam mode operasi yang kurang aman untuk sebagian besar codebase.

Analisis silang regresi kami dengan kesalahan jenis yang ditemukan TypeScript juga menunjukkan tumpang tindih, yang membuat kami yakin TypeScript dapat mencegah masalah ini (asalkan jenis itu sendiri sudah benar).

Melakukan any panggilan

Di titik ini, kami harus memutuskan antara meningkatkan penggunaan Closure Compiler atau bermigrasi ke TypeScript. (Karena Flow tidak didukung di Google atau di Chromium, kami harus mengabaikan opsi tersebut.) Berdasarkan diskusi dengan, dan rekomendasi dari, engineer Google yang mengerjakan alat JavaScript/TypeScript, kami memutuskan untuk memilih compiler TypeScript. (Kami baru-baru ini juga memublikasikan postingan blog tentang memigrasikan Puppeteer ke TypeScript.)

Alasan utama compiler TypeScript adalah peningkatan ketepatan jenis, sementara keuntungan lainnya menyertakan dukungan dari tim TypeScript secara internal di Google dan fitur bahasa TypeScript, seperti interfaces (bukan typedefs di JSDoc).

Memilih compiler TypeScript berarti kami harus berinvestasi secara signifikan dalam codebase DevTools dan arsitektur internalnya. Dengan demikian, kami memperkirakan bahwa kami membutuhkan setidaknya satu tahun untuk bermigrasi ke TypeScript (ditargetkan pada Q3 2020).

Melakukan migrasi

Pertanyaan terbesar yang masih ada: bagaimana kita akan bermigrasi ke TypeScript? Kami memiliki 150.000 baris kode dan kami tidak dapat memigrasikannya sekaligus. Kami juga tahu bahwa menjalankan TypeScript pada codebase akan menemukan ribuan error.

Kami mengevaluasi beberapa opsi:

  1. Dapatkan semua error TypeScript dan bandingkan dengan output "emas". Pendekatan ini akan mirip dengan yang dimiliki tim TypeScript. Kelemahan terbesar dari pendekatan ini adalah tingginya terjadinya konflik penggabungan, karena puluhan engineer bekerja dalam codebase yang sama.
  2. Tetapkan semua jenis masalah ke any. Hal ini pada dasarnya akan membuat TypeScript menyembunyikan error. Kami tidak memilih opsi ini, karena tujuan kami untuk migrasi adalah ketepatan jenis yang akan diganggu.
  3. Perbaiki semua error TypeScript secara manual. Cara ini akan melibatkan perbaikan ribuan {i>error<i}, yang memakan waktu.

Meskipun harus melakukan upaya yang besar, kami memilih opsi 3. Ada alasan tambahan mengapa kami memilih opsi ini: misalnya, opsi ini memungkinkan kami mengaudit semua kode dan melakukan peninjauan sekali dalam satu dekade terhadap semua fungsi, termasuk penerapannya. Dari perspektif bisnis, kami tidak memberikan nilai baru, melainkan mempertahankan status quo. Hal ini mempersulit proses untuk membenarkan opsi 3 sebagai pilihan yang benar.

Namun, dengan mengadopsi TypeScript, kami sangat yakin dapat mencegah masalah di masa mendatang, terutama terkait regresi. Dengan demikian, argumennya kurang "kami menambahkan nilai bisnis baru", dan lebih banyak "kami memastikan bahwa kami tidak kehilangan nilai bisnis yang diperoleh".

Dukungan JavaScript compiler TypeScript

Setelah mendapatkan dukungan dan mengembangkan rencana untuk menjalankan compiler Closure dan TypeScript pada kode JavaScript yang sama, kami memulai dengan beberapa file kecil. Pendekatan kami sebagian besar dari bawah ke atas: dimulai dengan kode inti dan melanjutkan arsitektur ke atas hingga mencapai panel tingkat tinggi.

Kami dapat memparalelkan pekerjaan kami dengan menambahkan @ts-nocheck terlebih dahulu ke setiap file di DevTools. Proses "memperbaiki TypeScript" adalah menghapus anotasi @ts-nocheck dan menyelesaikan error yang ditemukan TypeScript. Ini berarti kami yakin bahwa setiap file telah diperiksa dan sebanyak mungkin masalah telah diatasi.

Secara umum, pendekatan ini dapat mengatasi beberapa masalah. Kami mengalami beberapa bug di compiler TypeScript, tetapi sebagian besarnya tidak jelas:

  1. Parameter opsional dengan jenis fungsi yang menampilkan any diperlakukan sebagai wajib: #38551
  2. Penetapan properti ke metode statis deklarasi jeda class: #38553
  3. Deklarasi subclass dengan konstruktor no-args dan super-class dengan konstruktor args menghilangkan konstruktor turunan: #41397

Bug ini menyoroti bahwa, untuk kasus 99%, compiler TypeScript adalah fondasi yang kuat untuk dibangun. Ya, bug yang tidak jelas ini kadang-kadang menyebabkan masalah untuk DevTools, namun sering kali bug tersebut cukup kabur sehingga kami bisa dengan mudah mengatasinya.

Satu-satunya masalah yang menyebabkan kebingungan adalah output non-deterministik file .tsbuildinfo: #37156. Di Chromium, kami mengharuskan dua build dari commit Chromium yang sama menghasilkan output yang sama persis. Sayangnya, engineer build Chromium kami menemukan bahwa output .tsbuildinfo tidak dapat ditentukan: crbug.com/1054494. Untuk mengatasi masalah ini, kami harus melakukan Monkey-patch file .tsbuildinfo (yang pada dasarnya berisi JSON) dan melakukan pascapemrosesan untuk menampilkan output deterministik: https://crrev.com/c/2091448 Untungnya, tim TypeScript telah menyelesaikan masalah upstream dan kami dapat segera menghapus solusi tersebut. Terima kasih kepada tim TypeScript karena telah menerima laporan bug dan segera memperbaiki masalah ini.

Secara keseluruhan, kami puas dengan ketepatan (jenis) compiler TypeScript. Kami berharap bahwa Devtools sebagai project JavaScript open source besar telah membantu memperkuat dukungan JavaScript di TypeScript.

Menganalisis akibat

Kami dapat membuat kemajuan yang baik dalam mengatasi jenis kesalahan ini dan perlahan-lahan meningkatkan jumlah kode yang diperiksa oleh TypeScript. Namun, pada Agustus 2020 (9 bulan setelah migrasi ini), kami melakukan pemeriksaan dan mendapati bahwa kami tidak akan mencapai batas waktu dengan kecepatan kami saat ini. Salah satu engineer kami membuat grafik analisis untuk menunjukkan progres "TypeScriptification" (nama yang kami berikan untuk migrasi ini).

Progres Migrasi TypeScript

Progres Migrasi TypeScript - Melacak baris kode yang tersisa yang perlu dimigrasikan

Estimasi kapan kami akan mencapai nol baris yang tersisa berkisar dari Juli 2021 hingga Desember 2021, hampir setahun setelah batas waktu kami. Setelah berdiskusi dengan manajemen dan engineer lainnya, kami setuju untuk menambah jumlah engineer yang berupaya bermigrasi ke dukungan compiler TypeScript. Hal ini memungkinkan karena kami merancang migrasi agar dapat diparalelkan sehingga beberapa engineer yang mengerjakan beberapa file berbeda tidak akan bertentangan satu sama lain.

Pada tahap ini, proses TypeScriptification menjadi upaya seluruh tim. Dengan bantuan tambahan tersebut, kami dapat menyelesaikan migrasi pada akhir November 2020, 13 bulan setelah memulai, dan lebih dari setahun sebelum perkiraan perkiraan awal kami.

Secara total, ada 771 daftar perubahan (serupa dengan Permintaan Pull) yang dikirimkan oleh 18 engineer. Bug pelacakan kami (https://crbug.com/1011811) memiliki lebih dari 1.200 komentar (hampir semuanya merupakan postingan otomatis dari daftar perubahan). Sheet pelacakan kami memiliki lebih dari 500 baris untuk semua file yang akan diketik, penerima tugas, dan di daftar perubahan mana file tersebut “Dijeniskan”.

Mengurangi dampak performa compiler TypeScript

Masalah terbesar yang saat ini kita hadapi saat ini adalah performa lambat dari compiler TypeScript. Mengingat banyaknya engineer yang membangun Chromium dan DevTools, hambatan ini menjadi mahal. Sayangnya, kami tidak dapat mengidentifikasi risiko ini sebelum migrasi, dan pada saat kami memigrasikan sebagian besar file ke TypeScript, kami menemukan peningkatan signifikan waktu yang dihabiskan di seluruh build Chromium: https://crbug.com/1139220

Kami telah melaporkan masalah ini upstream ke tim compiler Microsoft TypeScript, tetapi sayangnya mereka memutuskan bahwa perilaku ini disengaja. Kami berharap mereka akan mempertimbangkan kembali masalah ini, tetapi sementara itu kami berupaya mengurangi dampak performa yang lambat pada sisi Chromium sebanyak mungkin.

Sayangnya, solusi yang tersedia bagi kita saat ini tidak selalu cocok untuk kontributor non-Googler. Karena kontribusi open source ke Chromium sangat penting (terutama kontribusi dari tim Microsoft Edge), kami secara aktif mencari alternatif yang cocok untuk semua kontributor. Namun, saat ini kami belum menemukan solusi alternatif yang sesuai.

Status TypeScript saat ini di DevTools

Saat ini, kami telah menghapus pemeriksa jenis compiler Closure dari codebase kami dan hanya mengandalkan compiler TypeScript. Kita bisa menulis file yang ditulis TypeScript dan menggunakan fitur khusus TypeScript (seperti antarmuka, generik, dll...), yang membantu kita setiap hari. Kami telah meningkatkan keyakinan bahwa compiler TypeScript akan menangkap error dan regresi jenis, seperti yang kami harapkan akan terjadi saat pertama kali mulai mengerjakan migrasi ini. Migrasi ini, seperti kebanyakan migrasi lainnya, berjalan lambat, unik, dan sering kali menantang, tetapi karena kami memberikan manfaatnya, kami yakin tindakan tersebut sepadan.

Mendownload saluran pratinjau

Pertimbangkan untuk menggunakan Chrome Canary, Dev, atau Beta sebagai browser pengembangan default Anda. Saluran pratinjau ini memberi Anda akses ke fitur DevTools terbaru, menguji API platform web tercanggih, dan menemukan masalah di situs Anda sebelum pengguna melakukannya.

Menghubungi tim Chrome DevTools

Gunakan opsi berikut untuk membahas fitur dan perubahan baru di postingan, atau hal lain yang berkaitan dengan DevTools.

  • Kirim saran atau masukan kepada kami melalui crbug.com.
  • Laporkan masalah DevTools menggunakan Opsi lainnya   Lainnya   > Bantuan > Laporkan masalah DevTools di DevTools.
  • Tweet di @ChromeDevTools.
  • Berikan komentar di video YouTube Apa yang baru di DevTools atau video YouTube Tips DevTools.