تازه سازی معماری DevTools: انتقال DevTools به TypeScript

تیم ون در لیپه
Tim van der Lippe

این پست بخشی از یک سری پست های وبلاگ است که تغییراتی را که ما در معماری DevTools ایجاد می کنیم و نحوه ساخت آن را توضیح می دهد.

با پیگیری مهاجرت خود به ماژول های جاوا اسکریپت و مهاجرت به مؤلفه های وب ، امروز مجموعه پست های وبلاگ خود را در مورد تغییراتی که در معماری Devtools ایجاد می کنیم و نحوه ساخت آن ادامه می دهیم. (اگر قبلاً آن را ندیده‌اید، ما ویدیویی را در مورد ارتقاء معماری DevTools به وب مدرن با 14 نکته در مورد چگونگی بهبود پروژه‌های وب خود ارسال کردیم.)

در این پست، سفر 13 ماهه خود را در حال دور شدن از جستجوگر نوع کامپایلر بسته شدن به TypeScript شرح خواهیم داد.

مقدمه

با توجه به اندازه پایگاه کد DevTools و نیاز به ارائه اطمینان به مهندسین که روی آن کار می کنند، استفاده از جستجوگر نوع یک ضرورت است . برای این منظور، DevTools در سال 2013 کامپایلر بسته شدن را به کار گرفت. پذیرش بستن، مهندسان DevTools را قادر ساخت تا تغییرات را با اطمینان انجام دهند. کامپایلر Closure برای اطمینان از اینکه همه ادغام‌های سیستم به خوبی تایپ شده‌اند، نوع بررسی را انجام می‌دهد.

با این حال، با گذشت زمان، چکرهای نوع جایگزین در توسعه وب مدرن محبوب شدند. دو مثال قابل توجه عبارتند از TypeScript و Flow . علاوه بر این، TypeScript به یک زبان برنامه نویسی رسمی در گوگل تبدیل شد. در حالی که محبوبیت این چکرهای نوع جدید افزایش یافته است، ما همچنین متوجه شدیم که ما رگرسیون هایی را ارسال می کنیم که باید توسط یک چک کننده تایپ دستگیر می شد. بنابراین، ما تصمیم گرفتیم که انتخاب نوع جستجوگر خود را دوباره ارزیابی کنیم و مراحل بعدی توسعه در DevTools را مشخص کنیم.

ارزیابی نوع چکرز

از آنجایی که DevTools قبلاً از جستجوگر نوع استفاده می کرد، سؤالی که ما باید پاسخ دهیم این بود:

آیا به استفاده از Closure Compiler ادامه می دهیم یا به یک جستجوگر نوع جدید مهاجرت می کنیم؟

برای پاسخ به این سوال، ما مجبور شدیم تایپ چک ها را بر اساس چندین ویژگی ارزیابی کنیم. از آنجایی که استفاده ما از نوع چک کننده بر اعتماد مهندس تمرکز دارد، مهمترین جنبه برای ما صحت نوع است. به عبارت دیگر: تایپ‌گر چقدر در کشف مسائل واقعی قابل اعتماد است؟

ارزیابی ما بر روی رگرسیون هایی که ارسال کرده بودیم و تعیین اینکه علت اصلی آنها چیست متمرکز بود. فرض در اینجا این است که، چون ما قبلاً از Closure Compiler استفاده می‌کردیم، Closure این مسائل را نمی‌گرفت. بنابراین، ما باید تعیین کنیم که آیا هر نوع جستجوگر دیگری قادر به انجام این کار بوده است یا خیر.

صحت تایپ در TypeScript

از آنجایی که TypeScript یک زبان برنامه نویسی رسمی بود که در گوگل پشتیبانی می شد و به سرعت در حال افزایش محبوبیت بود، تصمیم گرفتیم ابتدا TypeScript را ارزیابی کنیم. TypeScript انتخاب جالبی بود، زیرا خود تیم TypeScript از DevTools به عنوان یکی از پروژه های آزمایشی خود برای ردیابی سازگاری آنها با بررسی نوع جاوا اسکریپت استفاده می کند. خروجی آزمایش مرجع پایه آنها نشان داده بود که TypeScript تعداد زیادی از مشکلات نوع را پیدا می کند - مسائلی که کامپایلر Closure لزوماً آنها را تشخیص نمی داد. بسیاری از این مسائل احتمالاً علت اصلی عقب‌نشینی‌هایی هستند که ما ارسال می‌کردیم. این به نوبه خود باعث شد باور کنیم که TypeScript می تواند گزینه مناسبی برای DevTools باشد.

در طول مهاجرت خود به ماژول‌های جاوا اسکریپت ، قبلاً متوجه شده بودیم که Closure Compiler مشکلات بیشتری را نسبت به قبل کشف کرده است. حرکت به یک قالب ماژول استاندارد توانایی Closure را برای درک پایگاه کد ما افزایش داده و بنابراین کارایی بررسی‌کننده‌های نوع را افزایش داده است. با این حال، تیم TypeScript از یک نسخه پایه DevTools استفاده می کرد که قبل از مهاجرت ماژول های جاوا اسکریپت بود. بنابراین، باید بفهمیم که آیا مهاجرت به ماژول‌های جاوا اسکریپت میزان خطاهایی را که کامپایلر TypeScript دریافت می‌کند نیز کاهش داده است.

ارزیابی TypeScript

DevTools بیش از یک دهه است که وجود داشته است، که در آن به یک برنامه وب با اندازه قابل توجه و با ویژگی های غنی تبدیل شده است. در زمان نوشتن این پست وبلاگ، DevTools شامل تقریباً 150000 خط کد جاوا اسکریپت شخص اول است. هنگامی که ما کامپایلر TypeScript را بر روی کد منبع خود اجرا کردیم، حجم عظیمی از خطاها بسیار زیاد بود. ما توانستیم بفهمیم که در حالی که کامپایلر TypeScript خطاهای کمتری مربوط به وضوح کد منتشر می‌کند (2000 خطا)، هنوز 6000 خطا در پایگاه کد ما مربوط به سازگاری نوع وجود دارد.

این نشان داد که در حالی که TypeScript قادر به درک چگونگی حل انواع است، مقدار قابل توجهی از ناسازگاری‌های نوع را در پایگاه کد ما پیدا کرد. تجزیه و تحلیل دستی این خطاها نشان داده بود که TypeScript (بیشتر اوقات) درست است. دلیل اینکه TypeScript قادر به تشخیص این موارد بود و Closure نبود این بود که اغلب کامپایلر Closure یک نوع را Any استنباط می کرد، در حالی که TypeScript استنتاج نوع را بر اساس انتساب انجام می داد و نوع دقیق تری را استنباط می کرد. به این ترتیب، TypeScript واقعاً در درک ساختار اشیاء ما بهتر بود و کاربردهای مشکل‌ساز را کشف کرد .

یک نکته مهم در این مورد این است که استفاده از کامپایلر Closure در DevTools شامل استفاده مکرر از @unrestricted نیز می‌شود. حاشیه نویسی یک کلاس با @unrestricted به طور موثر بررسی های دقیق ویژگی کامپایلر Closure را برای آن کلاس خاص خاموش می کند، به این معنی که یک توسعه دهنده می تواند تعریف کلاس را به میل خود بدون ایمنی نوع اضافه کند. ما نتوانستیم زمینه تاریخی پیدا کنیم که چرا استفاده از @unrestricted در پایگاه کد DevTools رایج بود، اما منجر به اجرای کامپایلر Closure در حالت عملکرد کمتر امن برای بخش‌های بزرگی از پایگاه کد شد.

تجزیه و تحلیل متقابل رگرسیون‌های ما با خطاهای نوع کشف‌شده TypeScript همپوشانی را نشان داد که ما را به این باور رساند که TypeScript می‌توانست از این مشکلات جلوگیری کند (به شرط اینکه خود انواع درست باشند).

برقراری any تماس

در این مرحله، ما باید بین بهبود استفاده از کامپایلر بسته یا مهاجرت به TypeScript تصمیم می‌گیریم. (از آنجایی که Flow نه در Google و نه در Chromium پشتیبانی نمی‌شد، مجبور شدیم از این گزینه صرف نظر کنیم.) بر اساس بحث و توصیه‌های مهندسان Google که بر روی ابزار جاوا اسکریپت/تایپ اسکریپت کار می‌کنند، ما کامپایلر TypeScript را انتخاب کردیم. (ما اخیراً یک پست وبلاگ در مورد مهاجرت Puppeteer به TypeScript منتشر کردیم.)

دلایل اصلی کامپایلر TypeScript بهبود صحت نوع بود، در حالی که مزایای دیگر شامل پشتیبانی از تیم های TypeScript داخلی در Google و ویژگی های زبان TypeScript، مانند interfaces (بر خلاف typedefs در JSDoc) بود.

انتخاب کامپایلر TypeScript به این معنی بود که ما باید به میزان قابل توجهی روی پایگاه کد DevTools و معماری داخلی آن سرمایه گذاری می کردیم. به این ترتیب، ما تخمین زدیم که حداقل یک سال برای مهاجرت به TypeScript (با هدف Q3 2020) نیاز داریم.

انجام مهاجرت

بزرگترین سوالی که باقی ماند: چگونه می خواهیم به TypeScript مهاجرت کنیم؟ ما 150000 خط کد داریم و نمی‌توانیم آن را به یکباره انتقال دهیم. ما همچنین می دانستیم که اجرای TypeScript در پایگاه کد ما هزاران خطا را آشکار می کند.

ما چندین گزینه را ارزیابی کردیم:

  1. تمام خطاهای TypeScript را دریافت کنید و آنها را با یک خروجی "طلایی" مقایسه کنید . این رویکرد مشابه چیزی است که تیم TypeScript دارد. بزرگترین نقطه ضعف این رویکرد، وقوع زیاد تضادهای ادغام است، زیرا ده ها مهندس در یک پایگاه کد کار می کنند.
  2. همه انواع مشکل ساز را روی any تنظیم کنید. این اساساً باعث می شود تایپ اسکریپت خطاها را سرکوب کند. ما این گزینه را انتخاب نکردیم، زیرا هدف ما برای مهاجرت، صحت نوع بود که سرکوب آن را تضعیف می کرد.
  3. تمام خطاهای TypeScript را به صورت دستی برطرف کنید. این امر مستلزم رفع هزاران خطا است که زمان بر است.

علیرغم تلاش زیاد مورد انتظار، گزینه 3 را انتخاب کردیم. دلایل دیگری نیز وجود داشت که چرا این گزینه را انتخاب کردیم: به عنوان مثال، این امکان را به ما می داد که همه کدها را بررسی کنیم و هر دهه یک بار بررسی همه عملکردها، از جمله اجرای آن را انجام دهیم. . از منظر کسب و کار، ما ارزش جدیدی ارائه نکردیم، بلکه وضعیت موجود را حفظ کردیم. این امر توجیه گزینه 3 به عنوان انتخاب صحیح را دشوارتر می کرد.

با این حال، با پذیرش TypeScript، ما قویاً معتقد بودیم که می‌توانیم از مشکلات آینده، به ویژه در مورد رگرسیون‌ها جلوگیری کنیم . به این ترتیب، استدلال کمتر این بود که "ما در حال افزودن ارزش تجاری جدید هستیم" و بیشتر "ما تضمین می کنیم که ارزش کسب و کار به دست آمده را از دست نمی دهیم".

پشتیبانی جاوا اسکریپت از کامپایلر TypeScript

پس از ایمن سازی خرید ورود و ایجاد طرحی برای اجرای هر دو کامپایلر Closure و TypeScript روی کد جاوا اسکریپت یکسان ، با چند فایل کوچک شروع کردیم. رویکرد ما عمدتاً از پایین به بالا بود: با کد اصلی شروع کنید و تا زمانی که به پانل های سطح بالا برسیم به سمت معماری حرکت کنید.

ما توانستیم با اضافه کردن پیشگیرانه @ts-nocheck به هر فایل در DevTools، کار خود را موازی کنیم. فرآیند "تثبیت TypeScript" حذف حاشیه نویسی @ts-nocheck و رفع هر گونه خطایی است که TypeScript پیدا می کند. این بدان معنی بود که ما مطمئن بودیم که هر فایل بررسی شده است و تا آنجا که ممکن است مشکلات نوع حل شده است.

به طور کلی، این رویکرد با مسائل کمی کار می کرد. ما در کامپایلر TypeScript با چندین باگ مواجه شدیم، اما اکثر آنها مبهم بودند:

  1. یک پارامتر اختیاری با یک نوع تابع که any برمی گرداند، به صورت مورد نیاز در نظر گرفته می شود: #38551
  2. تخصیص ویژگی به یک متد استاتیک از یک کلاس، اعلان: #38553 را می شکند
  3. اعلان یک کلاس فرعی با سازنده no-args و یک کلاس فوق العاده با سازنده args، سازنده فرزند را حذف می کند: #41397

این اشکالات نشان می دهد که برای 99٪ موارد، کامپایلر TypeScript یک پایه محکم برای ساختن است. بله، این اشکالات مبهم گاهی اوقات مشکلاتی را برای DevTools ایجاد می‌کردند، اما بیشتر اوقات به اندازه‌ای مبهم بودند که می‌توانستیم به راحتی آنها را حل کنیم.

تنها مشکلی که باعث سردرگمی شده بود، خروجی غیر قطعی فایل‌های .tsbuildinfo : #37156 بود. در Chromium، ما نیاز داریم که هر دو ساخت از یک Chromium commit یک خروجی دقیقاً یکسان داشته باشند. متأسفانه، مهندسان ساخت Chromium ما متوجه شدند که خروجی .tsbuildinfo غیر قطعی است: crbug.com/1054494 . برای حل این مشکل، مجبور شدیم فایل .tsbuildinfo را (که در اصل حاوی JSON است) وصله کنیم و آن را پس از پردازش برای بازگرداندن یک خروجی قطعی انجام دهیم: https://crrev.com/c/2091448 خوشبختانه، تیم TypeScript مشکل را حل کرد. مشکل بالادستی بود و ما به زودی توانستیم راه حل خود را حذف کنیم. از تیم TypeScript برای استقبال از گزارش های اشکال و رفع سریع این مشکلات سپاسگزاریم!

به طور کلی، ما از صحت (نوع) کامپایلر TypeScript راضی هستیم. ما امیدواریم که Devtools به عنوان یک پروژه بزرگ جاوا اسکریپت منبع باز به تقویت پشتیبانی جاوا اسکریپت در TypeScript کمک کرده باشد.

تحلیل عواقب بعدی

ما توانستیم پیشرفت خوبی در حل این خطاهای نوع داشته باشیم و به آرامی مقدار کد بررسی شده توسط TypeScript را افزایش دهیم. با این حال، در آگوست 2020 (9 ماه پس از این مهاجرت) ما یک بررسی انجام دادیم و متوجه شدیم که ضرب الاجل خود را با سرعت فعلی خود انجام نمی دهیم. یکی از مهندسان ما یک نمودار تحلیلی برای نشان دادن پیشرفت "TypeScriptification" (نامی که برای این مهاجرت گذاشتیم) ساخت.

پیشرفت مهاجرت TypeScript

پیشرفت مهاجرت TypeScript - ردیابی خطوط کد باقیمانده که نیاز به مهاجرت دارند

تخمین‌ها برای رسیدن به خط صفر باقیمانده از ژوئیه 2021 تا دسامبر 2021، تقریباً یک سال پس از ضرب‌الاجل ما، متغیر بود. پس از بحث و گفتگو با مدیریت و سایر مهندسان، ما موافقت کردیم که تعداد مهندسانی را که برای مهاجرت به پشتیبانی کامپایلر TypeScript کار می کنند، افزایش دهیم. این امکان پذیر بود زیرا ما مهاجرت را موازی‌پذیر طراحی کردیم به طوری که چندین مهندس که روی چندین فایل مختلف کار می‌کنند با یکدیگر تضاد نداشته باشند.

در این مرحله، فرآیند TypeScriptification به یک تلاش گروهی تبدیل شد. با کمک اضافی، ما توانستیم مهاجرت خود را در پایان نوامبر 2020، 13 ماه پس از شروع، و بیش از یک سال قبل از پیش بینی اولیه ما، به پایان برسانیم.

در مجموع، 771 لیست تغییر (شبیه به یک درخواست کشش) توسط 18 مهندس ارسال شده بود. اشکال ردیابی ما ( https://crbug.com/1011811 ) بیش از 1200 نظر دارد (تقریباً همه آنها پست‌های خودکار از فهرست‌های تغییر هستند). برگه ردیابی ما دارای بیش از 500 ردیف برای همه فایل‌هایی بود که باید تایپ‌سازی شوند، اختصاص‌دهنده آن‌ها و در کدام فهرست تغییرات «Typescriptified» بودند.

کاهش تأثیر عملکرد کامپایلر TypeScript

بزرگترین مشکلی که امروزه با آن دست به گریبان هستیم، عملکرد کند کامپایلر TypeScript است. با توجه به تعداد مهندسان سازنده Chromium و DevTools، این تنگنا هزینه بر است. متأسفانه، ما قبل از مهاجرت نتوانستیم این خطر را شناسایی کنیم، و تنها زمانی که اکثر فایل‌ها را به TypeScript منتقل کرده بودیم، متوجه افزایش قابل توجه زمان صرف شده در ساخت‌های Chromium شدیم: https://crbug .com/1139220

ما این مشکل را در بالادست به تیم کامپایلر Microsoft TypeScript گزارش کرده‌ایم ، اما متأسفانه آنها این رفتار را عمدی تشخیص دادند. ما امیدواریم که آنها در این موضوع تجدید نظر کنند، اما در عین حال، ما در حال کار بر روی کاهش تأثیر عملکرد کند در سمت Chromium تا حد ممکن هستیم.

متأسفانه، راه‌حل‌هایی که امروز در دسترس ما هستند، همیشه برای مشارکت‌کنندگان غیر Google مناسب نیستند. از آنجایی که مشارکت‌های منبع باز به Chromium بسیار مهم هستند (مخصوصاً مواردی که از تیم Microsoft Edge انجام می‌شود)، ما فعالانه به دنبال جایگزین‌هایی هستیم که برای همه مشارکت‌کنندگان کارساز باشد. با این حال، در حال حاضر ما راه حل جایگزین مناسبی پیدا نکرده ایم.

وضعیت فعلی TypeScript در DevTools

در حال حاضر، بررسی‌کننده نوع کامپایلر Closure را از پایگاه کد خود حذف کرده‌ایم و تنها به کامپایلر TypeScript متکی هستیم. ما می‌توانیم فایل‌های تایپ اسکریپت بنویسیم و از ویژگی‌های خاص تایپ اسکریپت (مانند رابط‌ها، ژنریک‌ها و غیره) استفاده کنیم که به صورت روزانه به ما کمک می‌کند. ما اطمینان داریم که کامپایلر TypeScript خطاها و رگرسیون‌های نوع را دریافت می‌کند، این همان چیزی است که امیدوار بودیم در ابتدای کار روی این مهاجرت اتفاق بیفتد. این مهاجرت، مانند بسیاری دیگر، آهسته، ظریف و اغلب چالش برانگیز بود، اما از آنجایی که ما از مزایای آن بهره می‌بریم، معتقدیم ارزشش را داشت.

کانال های پیش نمایش را دانلود کنید

استفاده از Chrome Canary ، Dev یا Beta را به عنوان مرورگر توسعه پیش‌فرض خود در نظر بگیرید. این کانال‌های پیش‌نمایش به شما امکان دسترسی به جدیدترین ویژگی‌های DevTools را می‌دهند، به شما اجازه می‌دهند APIهای پلتفرم وب پیشرفته را آزمایش کنید و به شما کمک می‌کنند تا قبل از کاربران، مشکلات سایت خود را پیدا کنید!

با تیم Chrome DevTools در تماس باشید

از گزینه‌های زیر برای بحث در مورد ویژگی‌های جدید، به‌روزرسانی‌ها یا هر چیز دیگری مربوط به DevTools استفاده کنید.