שאלות נפוצות על SmooshGate

למה ה-smoosh קרה?!

הצעה לתכונה של שפת JavaScript שנקראת Array.prototype.flatten התבררה כבלתי תואמת לאינטרנט. השקת התכונה ב-Firefox Nightly גרמה לבעיה לפחות באתר פופולרי אחד. מכיוון שהקוד הבעייתי הוא חלק מספריית MooTools הנפוצה, סביר להניח שעוד הרבה אתרים מושפעים ממנו. (למרות ש-MooTools לא נמצא בשימוש נפוץ באתרים חדשים בשנת 2018, הוא היה פופולרי מאוד בעבר ועדיין נמצא באתרים רבים בסביבת הייצור).

מחבר ההצעה הציע בצחוק לשנות את השם של flatten ל-smoosh כדי למנוע את בעיית התאימות. הבדיחה לא הייתה ברורה לכולם, חלק מהאנשים התחילו לחשוב בטעות שהשם החדש כבר הוחלט, והמצב החמיר במהירות.

מה Array.prototype.flatten עושה?

הפונקציה Array.prototype.flat, שנקראה במקור Array.prototype.flatten, משטחת מערכי נתונים באופן רקורסיבי עד לערך depth שצוין, שהברירת המחדל שלו היא 1.

// Flatten one level:
const array = [1, [2, [3]]];
array.flat();
// → [1, 2, [3]]

// Flatten recursively until the array contains no more nested arrays:
array.flat(Infinity);
// → [1, 2, 3]

ההצעה הזו כוללת גם את Array.prototype.flatMap, שדומה ל-Array.prototype.map, אלא שהוא מיישר את התוצאה למערך חדש.

[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]

מה MooTools עושה שגורם לבעיה הזו?

ל-MooTools מוגדרים גרסה לא סטנדרטית של Array.prototype.flatten:

Array.prototype.flatten = /* non-standard implementation */;

ההטמעה של flatten ב-MooTools שונה מהתקן המוצע. עם זאת, זו לא הבעיה! כשדפדפנים כוללים את Array.prototype.flatten באופן מקורי, MooTools מבטלים את ההטמעה המקורית. כך מוודאים שהקוד שמסתמך על ההתנהגות של MooTools פועל כמצופה, גם אם flatten לא זמין. עד עכשיו, הכול טוב ויפה!

לצערנו, לאחר מכן קורה משהו אחר. MooTools מעתיקה את כל שיטות המערך בהתאמה אישית אל Elements.prototype (כאשר Elements הוא API ספציפי ל-MooTools):

for (var key in Array.prototype) {
  Elements.prototype[key] = Array.prototype[key];
}

for-in מבצעים חזרה על תכונות 'ניתנות לספירה', שלא כוללות שיטות מקוריות כמו Array.prototype.sort, אבל כן כוללות תכונות שהוקצתה להן ערך באופן קבוע כמו Array.prototype.foo = whatever. אבל — וכאן הנה הכותרת המקדימה — אם מחליפים נכס שאינו נתון לספירה, למשל Array.prototype.sort = whatever, לא ניתן לספור אותו.

בשלב זה, Array.prototype.flatten = mooToolsFlattenImplementation יוצר נכס flatten שניתן למדידה, כך שהוא מועתק מאוחר יותר אל Elements. עם זאת, אם הדפדפנים שולחים גרסה מקורית של flatten, היא הופכת ללא ניתנת לספירה ולא מועתקת אל Elements. כל קוד שמסתמך על Elements.prototype.flatten של MooTools לא עובד עכשיו.

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

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

למה לא נשאיר את השם הקיים ונגרום לשיבושים באינטרנט?

ב-1996, לפני ששירות CSS הפך לתפוצות, והרבה לפני ש-HTML5 הפך לדבר, האתר של Space Jam עלה לאוויר. האתר עדיין פועל באותו אופן שבו הוא פעל לפני 22 שנה.

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

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

  • המבקרים באתרים המושפעים חווים פתאום חוויית משתמש שבורה.
  • בעלי האתר עברו מאתר שפועל בצורה מושלמת לאתר לא פונקציונלי בלי שהם שינו משהו.
  • ספקי דפדפנים שמספקים את התכונה החדשה עלולים לאבד נתח שוק, כי משתמשים עוברים לדפדפנים אחרים אחרי שהם מגלים שהתכונה 'פועלת בדפדפן X'.
  • אחרי שמזהים את בעיית התאימות, ספקי דפדפנים אחרים מסרבים לשלוח אותה. מפרט התכונה לא תואם למציאות ("nothing but a work of fiction"), וזה רע לתהליך הסטנדרטיזציה.

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

האם זה אומר שלעולם לא ניתן להסיר ממשקי API לא תקינים מפלטפורמת האינטרנט?

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

<applet>,‏ <keygen> ו-showModalDialog() הם דוגמאות לממשקי API לא תקינים שהוסרו בהצלחה מפלטפורמת האינטרנט.

למה לא פשוט מתקנים את MooTools?

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

האם אנשים לא יכולים פשוט לעדכן את העותק שלהם של MooTools?

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

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

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

איך פועל התהליך ב-TC39?

TC39 היא הוועדה שאחראית לפיתוח שפת JavaScript באמצעות תקן ECMAScript.

#SmooshGate גרם לחלק מהאנשים לחשוב ש-"TC39 רוצה לשנות את השם של flatten ל-smoosh", אבל זו הייתה בדיחה פנימית שלא הועברה בצורה טובה לגורמים חיצוניים. אנחנו לא מקבלים החלטות חשובות כמו שינוי שם של הצעה בקלות, לא אדם אחד מקבל אותן ובטח שלא מקבלים אותן בן לילה על סמך תגובה אחת ב-GitHub.

ב-TC39 פועלים לפי תהליך ברור של שלבי פיתוח להצעות תכונות. הצעות ל-ECMAScript ושינויים משמעותיים בהן (כולל שינוי השם של שיטות) נדונים במהלך פגישות TC39, וצריך לקבל אישור מכל הוועדה כדי שהן יהיו רשמיות. במקרה של Array.prototype.flatten, ההצעה כבר עברה כמה שלבים של אישור, עד שלב 3, שמציין שהתכונה מוכנה להטמעה בדפדפני אינטרנט. בדרך כלל מתגלות בעיות נוספות במפרט במהלך ההטמעה. במקרה הזה, המשוב החשוב ביותר התקבל אחרי כשניסינו לשלוח אותו: התכונה, במצבה הנוכחי, ניתקת את האינטרנט. בעיות קשות לחיזוי, כמו אלה, הן חלק מהסיבות לכך שתהליך TC39 לא מסתיים רק לאחר שדפדפנים שולחים תכונה.

TC39 פועל בכפוף להסכמה, כלומר הוועדה צריכה להסכים לגבי כל שינוי חדש. גם אם הייתה הצעה רצינית ל-smoosh, נראה שחברי ועדה יתנגדו אליה לטובת שם נפוץ יותר, כמו compact או chain.

שינוי השם מ-flatten ל-smoosh (גם אם זה לא היה בדיחה) אף פעם לא נדון בפגישה של TC39. לכן, העמדה הרשמית של TC39 בנושא הזה לא ידועה כרגע. אף אחד לא יכול לדבר בשם כל TC39 עד שמגיעים להסכמה בפגישה הבאה.

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

איך הבעיה ב-SmooshGate נפתרה בסופו של דבר?

במהלך פגישת TC39 במאי 2018, הבעיה של #SmooshGate נפתרה באופן רשמי על ידי שינוי השם של flatten ל-flat.

Array.prototype.flat ו-Array.prototype.flatMap נשלחו ב-V8 v6.9 וב-Chrome 69.