העברת ה-Puppeteer ל-TypeScript

אנחנו צוות גדול של מעריצי TypeScript בכלי הפיתוח – עד כדי כך שאנחנו כותבים קוד חדש בכלי הפיתוח באמצעות TypeScript, ונמצאים בעיצומו של מעבר גדול של כל בסיס הקוד לבדיקת סוגים באמצעות TypeScript. מידע נוסף על המעבר הזה זמין בהרצאה שלנו ב-Chrome Dev Summit 2020. לכן, היה הגיוני לחפש דרך להעביר גם את בסיס הקוד של Puppeteer ל-TypeScript.

תכנון ההעברה

כשתיכננו את תהליך ההעברה, רצינו להתקדם בצעדים קטנים. כך מצמצמים את התקורה של ההעברה – אתם עובדים רק על חלק קטן מהקוד בכל פעם – וגם מצמצמים את הסיכון. אם משהו משתבש באחד מהשלבים, אפשר לבטל אותו בקלות. ל-Puppeteer יש הרבה משתמשים, וגרסה פגומה עלולה לגרום לבעיות להרבה מהם, ולכן היה חשוב לנו לצמצם למינימום את הסיכון לשינויי תוכנה שעלולים לגרום לכשל.

היה לנו גם מזל של-Puppeteer יש מערך חזק של בדיקות יחידה שמכסה את כל הפונקציונליות שלה. המשמעות היא שיכולנו להיות בטוחים שלא נשבור קוד במהלך ההעברה, וגם שלא נבצע שינויים ב-API שלנו. המטרה של ההעברה הייתה להשלים אותה בלי שמשתמשי Puppeteer יבינו בכלל שביצענו העברה, והבדיקות היו חלק חיוני מהאסטרטגיה הזו. אם לא היה לנו כיסוי טוב של בדיקות, היינו מוסיפים אותו לפני שהיינו ממשיכים בהעברה.

ביצוע שינוי בקוד בלי בדיקות הוא מסוכן, אבל שינויים שבהם נוגעים בקבצים שלמים או בכל בסיס הקוד מסוכנים במיוחד. כשמבצעים שינויים טכניים, קל לפספס שלב, ובמקרים רבים הבדיקות זיהו בעיה שחמקה מעיני המטמיע והבודק.

השקענו זמן מראש בהגדרת אינטגרציה רציפה (CI). שמנו לב שהרצות של CI בבקשות משיכה היו לא יציבות ולעיתים קרובות נכשלו. זה קרה כל כך הרבה פעמים שהתרגלנו להתעלם מה-CI ולמזג את בקשות המשיכה בכל מקרה, מתוך הנחה שהכשל היה בעיה חד-פעמית ב-CI ולא בעיה ב-Puppeteer.

אחרי תחזוקה כללית והשקעת זמן בתיקון של כמה בעיות שקורות בבדיקות באופן קבוע, הצלחנו להגיע למצב שבו הבדיקות עוברות באופן עקבי הרבה יותר, כך שאפשר להסתמך על תוצאות ה-CI ולדעת שאם הבדיקה נכשלת, יש בעיה אמיתית. העבודה הזו לא זוהרת, וזה מתסכל לצפות בהרצות אינסופיות של CI, אבל היה חיוני שחבילת מקרים לבדיקה שלנו תפעל בצורה מהימנה בהתחשב במספר בקשות משיכה (pull request) שההעברה זרקה עליה.

בחירה והעלאה של קובץ אחד

בשלב הזה, ההעברה הייתה מוכנה לביצוע והיה לנו שרת CI חזק מלא בבדיקות שישמשו כרשת ביטחון. במקום להתחיל עם קובץ אקראי, בחרנו בכוונה קובץ קטן להעברה. זהו תרגיל מועיל כי הוא מאפשר לכם לאמת את התהליך המתוכנן שאתם עומדים לבצע. אם זה עובד בקובץ הזה, הגישה שלכם נכונה. אם לא, אפשר לחזור להתחלה.

בנוסף, העבודה על כל קובץ בנפרד (ובמקביל, עם גרסאות רגילות של Puppeteer, כך שלא כל השינויים נכללו באותה גרסת npm) צמצמה את הסיכון. בחרנו בקובץ DeviceDescriptors.js כקובץ הראשון, כי הוא היה אחד הקבצים הפשוטים ביותר בבסיס הקוד. אולי זה נראה קצת מאכזב לעשות את כל עבודת ההכנה הזו בשביל שינוי כל כך קטן, אבל המטרה היא לא לעשות שינויים עצומים מיד, אלא להתקדם בזהירות ובאופן שיטתי, קובץ אחר קובץ. הזמן שמושקע באימות הגישה חוסך זמן בהמשך ההעברה, כשמגיעים לקבצים מורכבים יותר.

צריך להוכיח את התבנית ולחזור עליה

למזלנו, השינוי ב-DeviceDescriptors.js נכנס לבסיס הקוד, והתוכנית פעלה כמו שקיווינו. בשלב הזה, אנחנו מוכנים להתחיל לעבוד, וזה בדיוק מה שעשינו. שימוש בתווית GitHub הוא דרך טובה מאוד לקבץ את כל בקשות המיזוג, והיא הייתה שימושית למעקב אחר ההתקדמות.

להעביר את האתר ולשפר אותו בהמשך

לגבי כל קובץ JavaScript בנפרד, התהליך שלנו היה:

  1. משנים את השם של הקובץ מ-.js ל-.ts.
  2. מריצים את הקומפיילר של TypeScript.
  3. פותרים את הבעיות.
  4. יוצרים את בקשת משיכה (pull request).

רוב העבודה בבקשות המיזוג הראשוניות האלה הייתה לחלץ ממשקי TypeScript למבני נתונים קיימים. במקרה של בקשת המיזוג הראשונה שהעבירה את DeviceDescriptors.js שדיברנו עליה קודם, הקוד עבר מהמצב הבא:

module.exports = [
  { 
    name: 'Pixel 4',
    … // Other fields omitted to save space
  }, 
  …
]

והפכו ל:

interface Device {
  name: string,
  …
}

const devices: Device[] = [{name: 'Pixel 4', …}, …]

module.exports = devices;

כחלק מהתהליך הזה, עברנו על כל שורה בבסיס הקוד כדי לבדוק אם יש בעיות. כמו בכל בסיס קוד שקיים כבר כמה שנים והתפתח עם הזמן, יש תחומים שבהם אפשר לבצע ארגון הקוד מחדש (Refactoring) של הקוד ולשפר את המצב. במיוחד עם המעבר ל-TypeScript, ראינו מקומות שבהם שינוי קל במבנה הקוד יאפשר לנו להסתמך יותר על הקומפיילר ולקבל מניעת שגיאות הקלדה טובה יותר.

חשוב לא לבצע את השינויים האלה באופן מיידי. המטרה של ההעברה היא להעביר את בסיס הקוד ל-TypeScript, ובמהלך העברה גדולה צריך תמיד לחשוב על הסיכון לגרימת שיבושים בתוכנה ולמשתמשים. הסיכון הזה נשאר נמוך כי צמצמנו למינימום את השינויים הראשוניים. אחרי שהקובץ מוזג והועבר ל-TypeScript, יכולנו לבצע שינויים נוספים כדי לשפר את הקוד ולנצל את מערכת הטיפוסים. חשוב להגדיר גבולות ברורים להעברה ולנסות לפעול במסגרתם.

העברת הבדיקות כדי לבדוק את הגדרות הסוגים שלנו

אחרי שהעברנו את כל קוד המקור ל-TypeScript, יכולנו להתמקד בבדיקות שלנו. הבדיקות שלנו כיסו היקף רחב, אבל כולן נכתבו ב-JavaScript. זה אומר שהם לא בדקו את הגדרות הסוגים שלנו. אחת מהמטרות לטווח הארוך של הפרויקט (שאנחנו עדיין עובדים עליה) היא לשלוח הגדרות סוגים באיכות גבוהה ישירות מהקופסה עם Puppeteer, אבל לא היו לנו בדיקות בבסיס הקוד לגבי הגדרות הסוגים שלנו.

כשהעברנו את הבדיקות ל-TypeScript (באותו תהליך, קובץ אחרי קובץ), מצאנו בעיות ב-TypeScript שהמשתמשים היו צריכים למצוא בשבילנו. עכשיו הבדיקות שלנו לא רק מכסות את כל הפונקציונליות שלנו, אלא גם משמשות כבדיקת איכות של TypeScript!

כמהנדסים שעובדים על בסיס הקוד של Puppeteer, כבר נהנינו מאוד מ-TypeScript. בזכות סביבת ה-CI המשופרת שלנו, אנחנו יכולים להיות פרודוקטיביים יותר כשאנחנו עובדים על Puppeteer, ו-TypeScript יכולה לזהות באגים שאחרת היו מגיעים לגרסת npm. אנחנו שמחים לשלוח הגדרות TypeScript באיכות גבוהה כדי שכל המפתחים שמשתמשים ב-Puppeteer יוכלו ליהנות מהעבודה הזו.

הורדת ערוצי התצוגה המקדימה

כדאי להשתמש ב-Chrome Canary,‏ Dev או Beta כדפדפן ברירת המחדל לפיתוח. ערוצי התצוגה המקדימה האלה נותנים לכם גישה לתכונות העדכניות ביותר של כלי הפיתוח, מאפשרים לכם לבדוק ממשקי API מתקדמים של פלטפורמות אינטרנט ועוזרים לכם למצוא בעיות באתר לפני שהמשתמשים שלכם ייתקלו בהן.

יצירת קשר עם הצוות של כלי הפיתוח ל-Chrome

אתם יכולים להשתמש באפשרויות הבאות כדי לדון בתכונות החדשות, בעדכונים או בכל דבר אחר שקשור לכלי הפיתוח.