מה התרחש?!
הצעה לתכונה של שפת 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.