چه اتفاقی افتاده؟!
یک پیشنهاد برای یک ویژگی زبان جاوا اسکریپت به نام Array.prototype.flatten
معلوم می شود که با وب ناسازگار است. ارسال این ویژگی در فایرفاکس نایتی باعث شکسته شدن حداقل یک وب سایت محبوب شد. با توجه به اینکه کد مشکل ساز بخشی از کتابخانه گسترده 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، جاوا اسکریپت و هر استاندارد دیگری است که به طور گسترده در وب استفاده می شود. اگر ارسال یک ویژگی مرورگر جدید باعث از کار افتادن وبسایتهای موجود شود، برای همه بد است:
- بازدیدکنندگان وبسایتهای آسیبدیده به طور ناگهانی یک تجربه کاربری شکسته دریافت میکنند.
- صاحبان وبسایت از داشتن یک وبسایت کاملاً کارآمد به یک وبسایت غیرعملکردی بدون تغییر چیزی تبدیل شدند.
- فروشندگان مرورگر که ویژگی جدید را ارسال می کنند، سهم بازار خود را از دست می دهند، زیرا کاربران بعد از اینکه متوجه شدند «در مرورگر X کار می کند» مرورگرها را تغییر می دهند.
- هنگامی که مشکل سازگاری مشخص شد، سایر فروشندگان مرورگر از ارسال آن خودداری می کنند. مشخصات ویژگی با واقعیت مطابقت ندارد ( "هیچ چیز جز یک اثر تخیلی" )، که برای فرآیند استانداردسازی بد است.
مطمئناً، در نگاهی به گذشته، MooTools کار اشتباهی انجام داد - اما شکستن وب آنها را مجازات نمی کند، بلکه کاربران را مجازات می کند. این کاربران نمی دانند ابزار moo چیست. از طرف دیگر، ما می توانیم راه حل دیگری پیدا کنیم و کاربران می توانند به استفاده از وب ادامه دهند. انتخاب آسان است.
آیا این بدان معناست که API های بد هرگز نمی توانند از پلتفرم وب حذف شوند؟
بستگی دارد. در موارد نادر، ویژگی های بد را می توان از وب حذف کرد . حتی فهمیدن اینکه آیا امکان حذف یک ویژگی وجود دارد یا خیر، تلاش بسیار دشواری است، که به تله متری گسترده برای تعیین کمیت تعداد صفحات وب که رفتارشان تغییر می کند، نیاز دارد. اما زمانی که این ویژگی به اندازه کافی ناامن است، برای کاربران مضر است، یا به ندرت استفاده می شود، می توان این کار را انجام داد.
<applet>
، <keygen>
و showModalDialog()
همگی نمونههایی از APIهای بدی هستند که با موفقیت از پلتفرم وب حذف شدند.
چرا ما فقط MooTools را تعمیر نمی کنیم؟
اصلاح MooTools به طوری که دیگر اشیاء داخلی را گسترش ندهد ایده خوبی است. با این حال، مشکل موجود را حل نمی کند. حتی اگر MooTools یک نسخه وصلهشده را منتشر کند، تمام وبسایتهای موجود که از آن استفاده میکنند باید بهروزرسانی شوند تا مشکل سازگاری برطرف شود.
آیا مردم نمی توانند نسخه MooTools خود را به روز کنند؟
در یک دنیای کامل، MooTools یک پچ منتشر میکند و هر وبسایتی که از MooTools استفاده میکند، روز بعد بهطور جادویی بهروزرسانی میشود. مشکل حل شد، نه؟!
متأسفانه، این غیر واقعی است. حتی اگر کسی بخواهد مجموعه کاملی از وبسایتهای آسیبدیده را شناسایی کند، اطلاعات تماس هر یک از آنها را پیدا کند، با موفقیت به همه صاحبان وبسایت دسترسی پیدا کند و همه آنها را متقاعد کند که بهروزرسانی را انجام دهند (که ممکن است به معنای بازسازی مجدد آنها باشد. کل پایه کد)، کل فرآیند در بهترین حالت سال ها طول می کشد.
به خاطر داشته باشید که بسیاری از این وب سایت ها قدیمی هستند و احتمالاً نگهداری نمی شوند. حتی اگر نگهدارنده هنوز در اطراف باشد، ممکن است آنها یک توسعه دهنده وب بسیار ماهر مانند شما نباشند. ما نمی توانیم انتظار داشته باشیم که همه بروند و وب سایت 8 ساله خود را به دلیل مشکل سازگاری وب تغییر دهند.
فرآیند TC39 چگونه کار می کند؟
TC39 کمیته ای است که مسئول تکامل زبان جاوا اسکریپت از طریق استاندارد ECMAScript است.
#SmooshGate باعث شد برخی بر این باور باشند که «TC39 میخواهد نام flatten
به smoosh
تغییر دهد»، اما این یک شوخی بود که به خوبی از خارج پخش نشد. تصمیمات مهمی مانند تغییر نام یک پیشنهاد ساده گرفته نمیشوند، توسط یک نفر گرفته نمیشوند و قطعاً یک شبه بر اساس یک نظر GitHub گرفته نمیشوند.
TC39 بر روی یک فرآیند مرحله بندی واضح برای پیشنهادات ویژه عمل می کند. پیشنهادات ECMAScript و هرگونه تغییر عمده در آنها (از جمله تغییر نام روش) در طول جلسات TC39 مورد بحث قرار می گیرد و قبل از رسمی شدن باید توسط کل کمیته تأیید شود. در مورد Array.prototype.flatten
، این پیشنهاد قبلاً چندین مرحله از توافق را طی کرده است، تا مرحله 3، که نشان میدهد این ویژگی برای پیادهسازی در مرورگرهای وب آماده است. معمولاً در حین پیاده سازی مسائل مربوط به مشخصات اضافی مطرح می شود. در این مورد، مهمترین بازخورد پس از تلاش برای ارسال آن صورت گرفت: این ویژگی، در وضعیت فعلی خود، وب را می شکند. پیشبینی مشکلاتی از این دست بخشی از دلایلی است که فرآیند TC39 تنها زمانی که مرورگرها یک ویژگی را ارسال میکنند به پایان نمیرسد.
TC39 بر اساس اجماع عمل می کند، به این معنی که کمیته باید در مورد تغییرات جدید موافقت کند. حتی اگر smoosh
یک پیشنهاد جدی بود، به نظر می رسد که یکی از اعضای کمیته به نفع نام رایج تر مانند compact
یا chain
به آن اعتراض کند.
تغییر نام از flatten
به smoosh
(حتی اگر شوخی نبود) هرگز در جلسه TC39 مورد بحث قرار نگرفته است. به این ترتیب، موضع رسمی TC39 در مورد این موضوع در حال حاضر ناشناخته است. هیچ فردی نمی تواند به نمایندگی از همه TC39 صحبت کند تا زمانی که در جلسه بعدی اجماع حاصل شود.
در جلسات TC39 عموماً افرادی با سوابق بسیار متنوع شرکت میکنند: برخی از آنها سالها تجربه طراحی زبان برنامهنویسی دارند، برخی دیگر بر روی یک مرورگر یا موتور جاوا اسکریپت کار میکنند، و تعداد فزایندهای از همراهان برای نشان دادن جامعه توسعهدهندگان جاوا اسکریپت در آنجا حضور دارند.
سرانجام SmooshGate چگونه حل شد؟
در جلسه می 2018 TC39 ، #SmooshGate رسما با تغییر نام flatten
به flat
حل شد.
Array.prototype.flat
و Array.prototype.flatMap
در نسخه 8 نسخه 6.9 و کروم 69 ارسال شدند.
چه اتفاقی افتاده؟!
یک پیشنهاد برای یک ویژگی زبان جاوا اسکریپت به نام Array.prototype.flatten
معلوم می شود که با وب ناسازگار است. ارسال این ویژگی در فایرفاکس نایتی باعث شکسته شدن حداقل یک وب سایت محبوب شد. با توجه به اینکه کد مشکل ساز بخشی از کتابخانه گسترده 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، جاوا اسکریپت و هر استاندارد دیگری است که به طور گسترده در وب استفاده می شود. اگر ارسال یک ویژگی مرورگر جدید باعث از کار افتادن وبسایتهای موجود شود، برای همه بد است:
- بازدیدکنندگان وبسایتهای آسیبدیده به طور ناگهانی یک تجربه کاربری شکسته دریافت میکنند.
- صاحبان وبسایت از داشتن یک وبسایت کاملاً کارآمد به یک وبسایت غیرعملکردی بدون تغییر چیزی تبدیل شدند.
- فروشندگان مرورگر که ویژگی جدید را ارسال می کنند، سهم بازار خود را از دست می دهند، زیرا کاربران بعد از اینکه متوجه شدند «در مرورگر X کار می کند» مرورگرها را تغییر می دهند.
- هنگامی که مشکل سازگاری مشخص شد، سایر فروشندگان مرورگر از ارسال آن خودداری می کنند. مشخصات ویژگی با واقعیت مطابقت ندارد ( "هیچ چیز جز یک اثر تخیلی" )، که برای فرآیند استانداردسازی بد است.
مطمئناً، در نگاهی به گذشته، MooTools کار اشتباهی انجام داد - اما شکستن وب آنها را مجازات نمی کند، بلکه کاربران را مجازات می کند. این کاربران نمی دانند ابزار moo چیست. از طرف دیگر، ما می توانیم راه حل دیگری پیدا کنیم و کاربران می توانند به استفاده از وب ادامه دهند. انتخاب آسان است.
آیا این بدان معناست که API های بد هرگز نمی توانند از پلتفرم وب حذف شوند؟
بستگی دارد. در موارد نادر، ویژگی های بد را می توان از وب حذف کرد . حتی فهمیدن اینکه آیا امکان حذف یک ویژگی وجود دارد یا خیر، تلاش بسیار دشواری است، که به تله متری گسترده برای تعیین کمیت تعداد صفحات وب که رفتارشان تغییر می کند، نیاز دارد. اما زمانی که این ویژگی به اندازه کافی ناامن است، برای کاربران مضر است، یا به ندرت استفاده می شود، می توان این کار را انجام داد.
<applet>
، <keygen>
و showModalDialog()
همگی نمونههایی از APIهای بدی هستند که با موفقیت از پلتفرم وب حذف شدند.
چرا ما فقط MooTools را تعمیر نمی کنیم؟
اصلاح MooTools به طوری که دیگر اشیاء داخلی را گسترش ندهد ایده خوبی است. با این حال، مشکل موجود را حل نمی کند. حتی اگر MooTools یک نسخه وصلهشده را منتشر کند، تمام وبسایتهای موجود که از آن استفاده میکنند باید بهروزرسانی شوند تا مشکل سازگاری برطرف شود.
آیا مردم نمی توانند نسخه MooTools خود را به روز کنند؟
در یک دنیای کامل، MooTools یک پچ منتشر میکند و هر وبسایتی که از MooTools استفاده میکند، روز بعد بهطور جادویی بهروزرسانی میشود. مشکل حل شد، نه؟!
متأسفانه، این غیر واقعی است. حتی اگر کسی بخواهد مجموعه کاملی از وبسایتهای آسیبدیده را شناسایی کند، اطلاعات تماس هر یک از آنها را پیدا کند، با موفقیت به همه صاحبان وبسایت دسترسی پیدا کند و همه آنها را متقاعد کند که بهروزرسانی را انجام دهند (که ممکن است به معنای بازسازی مجدد آنها باشد. کل پایه کد)، کل فرآیند در بهترین حالت سال ها طول می کشد.
به خاطر داشته باشید که بسیاری از این وب سایت ها قدیمی هستند و احتمالاً نگهداری نمی شوند. حتی اگر نگهدارنده هنوز در اطراف باشد، ممکن است آنها یک توسعه دهنده وب بسیار ماهر مانند شما نباشند. ما نمی توانیم انتظار داشته باشیم که همه بروند و وب سایت 8 ساله خود را به دلیل مشکل سازگاری وب تغییر دهند.
فرآیند TC39 چگونه کار می کند؟
TC39 کمیته ای است که مسئول تکامل زبان جاوا اسکریپت از طریق استاندارد ECMAScript است.
#SmooshGate باعث شد برخی بر این باور باشند که «TC39 میخواهد نام flatten
به smoosh
تغییر دهد»، اما این یک شوخی بود که به خوبی از خارج پخش نشد. تصمیمات مهمی مانند تغییر نام یک پیشنهاد ساده گرفته نمیشوند، توسط یک نفر گرفته نمیشوند و قطعاً یک شبه بر اساس یک نظر GitHub گرفته نمیشوند.
TC39 بر روی یک فرآیند مرحله بندی واضح برای پیشنهادات ویژه عمل می کند. پیشنهادات ECMAScript و هرگونه تغییر عمده در آنها (از جمله تغییر نام روش) در طول جلسات TC39 مورد بحث قرار می گیرد و قبل از رسمی شدن باید توسط کل کمیته تأیید شود. در مورد Array.prototype.flatten
، این پیشنهاد قبلاً چندین مرحله از توافق را طی کرده است، تا مرحله 3، که نشان میدهد این ویژگی برای پیادهسازی در مرورگرهای وب آماده است. معمولاً در حین پیاده سازی مسائل مربوط به مشخصات اضافی مطرح می شود. در این مورد، مهمترین بازخورد پس از تلاش برای ارسال آن صورت گرفت: این ویژگی، در وضعیت فعلی خود، وب را می شکند. پیشبینی مشکلاتی از این دست بخشی از دلایلی است که چرا فرآیند TC39 تنها زمانی که مرورگرها یک ویژگی را ارسال میکنند به پایان نمیرسد.
TC39 بر اساس اجماع عمل می کند، به این معنی که کمیته باید در مورد تغییرات جدید موافقت کند. حتی اگر smoosh
یک پیشنهاد جدی بود، به نظر می رسد که یکی از اعضای کمیته به نفع نام رایج تر مانند compact
یا chain
به آن اعتراض کند.
تغییر نام از flatten
به smoosh
(حتی اگر شوخی نبود) هرگز در جلسه TC39 مورد بحث قرار نگرفته است. به این ترتیب، موضع رسمی TC39 در مورد این موضوع در حال حاضر ناشناخته است. هیچ فردی نمی تواند به نمایندگی از همه TC39 صحبت کند تا زمانی که در جلسه بعدی اجماع حاصل شود.
در جلسات TC39 عموماً افرادی با سوابق بسیار متنوع شرکت میکنند: برخی از آنها سالها تجربه طراحی زبان برنامهنویسی دارند، برخی دیگر بر روی یک مرورگر یا موتور جاوا اسکریپت کار میکنند، و تعداد فزایندهای از همراهان برای نشان دادن جامعه توسعهدهندگان جاوا اسکریپت در آنجا حضور دارند.
سرانجام SmooshGate چگونه حل شد؟
در جلسه می 2018 TC39 ، #SmooshGate رسما با تغییر نام flatten
به flat
حل و فصل شد.
Array.prototype.flat
و Array.prototype.flatMap
در نسخه 8 نسخه 6.9 و کروم 69 ارسال شدند.
چه اتفاقی افتاده؟!
یک پیشنهاد برای یک ویژگی زبان جاوا اسکریپت به نام Array.prototype.flatten
معلوم می شود که با وب ناسازگار است. ارسال این ویژگی در فایرفاکس نایتی باعث شکسته شدن حداقل یک وب سایت محبوب شد. با توجه به اینکه کد مشکل ساز بخشی از کتابخانه گسترده 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، جاوا اسکریپت و هر استاندارد دیگری است که به طور گسترده در وب استفاده می شود. اگر ارسال یک ویژگی مرورگر جدید باعث از کار افتادن وبسایتهای موجود شود، برای همه بد است:
- بازدیدکنندگان وبسایتهای آسیبدیده به طور ناگهانی یک تجربه کاربری شکسته دریافت میکنند.
- صاحبان وبسایت از داشتن یک وبسایت کاملاً کارآمد به یک وبسایت غیرعملکردی بدون تغییر چیزی تبدیل شدند.
- فروشندگان مرورگر که ویژگی جدید را ارسال می کنند، سهم بازار خود را از دست می دهند، زیرا کاربران بعد از اینکه متوجه شدند «در مرورگر X کار می کند» مرورگرها را تغییر می دهند.
- هنگامی که مشکل سازگاری مشخص شد، سایر فروشندگان مرورگر از ارسال آن خودداری می کنند. مشخصات ویژگی با واقعیت مطابقت ندارد ( "هیچ چیز جز یک اثر تخیلی" )، که برای فرآیند استانداردسازی بد است.
مطمئناً، در نگاهی به گذشته، MooTools کار اشتباهی انجام داد - اما شکستن وب آنها را مجازات نمی کند، بلکه کاربران را مجازات می کند. این کاربران نمی دانند ابزار moo چیست. از طرف دیگر، ما می توانیم راه حل دیگری پیدا کنیم و کاربران می توانند به استفاده از وب ادامه دهند. انتخاب آسان است.
آیا این بدان معناست که API های بد هرگز نمی توانند از پلتفرم وب حذف شوند؟
بستگی دارد. در موارد نادر، ویژگی های بد را می توان از وب حذف کرد . حتی فهمیدن اینکه آیا امکان حذف یک ویژگی وجود دارد یا خیر، تلاش بسیار دشواری است، که به تله متری گسترده برای تعیین کمیت تعداد صفحات وب که رفتارشان تغییر می کند، نیاز دارد. اما زمانی که این ویژگی به اندازه کافی ناامن است، برای کاربران مضر است، یا به ندرت استفاده می شود، می توان این کار را انجام داد.
<applet>
، <keygen>
و showModalDialog()
همگی نمونههایی از APIهای بدی هستند که با موفقیت از پلتفرم وب حذف شدند.
چرا ما فقط MooTools را تعمیر نمی کنیم؟
اصلاح MooTools به طوری که دیگر اشیاء داخلی را گسترش ندهد ایده خوبی است. با این حال، مشکل موجود را حل نمی کند. حتی اگر MooTools یک نسخه وصلهشده را منتشر کند، تمام وبسایتهای موجود که از آن استفاده میکنند باید بهروزرسانی شوند تا مشکل سازگاری برطرف شود.
آیا مردم نمی توانند نسخه MooTools خود را به روز کنند؟
در یک دنیای کامل، MooTools یک پچ منتشر میکند و هر وبسایتی که از MooTools استفاده میکند، روز بعد بهطور جادویی بهروزرسانی میشود. مشکل حل شد، نه؟!
متأسفانه، این غیر واقعی است. حتی اگر کسی بخواهد مجموعه کاملی از وبسایتهای آسیبدیده را شناسایی کند، اطلاعات تماس هر یک از آنها را پیدا کند، با موفقیت به همه صاحبان وبسایت دسترسی پیدا کند و همه آنها را متقاعد کند که بهروزرسانی را انجام دهند (که ممکن است به معنای بازسازی مجدد آنها باشد. کل پایه کد)، کل فرآیند در بهترین حالت سال ها طول می کشد.
به خاطر داشته باشید که بسیاری از این وب سایت ها قدیمی هستند و احتمالاً نگهداری نمی شوند. حتی اگر نگهدارنده هنوز در اطراف باشد، ممکن است آنها یک توسعه دهنده وب بسیار ماهر مانند شما نباشند. ما نمی توانیم انتظار داشته باشیم که همه بروند و وب سایت 8 ساله خود را به دلیل مشکل سازگاری وب تغییر دهند.
فرآیند TC39 چگونه کار می کند؟
TC39 کمیته ای است که مسئول تکامل زبان جاوا اسکریپت از طریق استاندارد ECMAScript است.
#SmooshGate باعث شد برخی بر این باور باشند که «TC39 میخواهد نام flatten
به smoosh
تغییر دهد»، اما این یک شوخی بود که به خوبی از خارج پخش نشد. تصمیمات مهمی مانند تغییر نام یک پیشنهاد ساده گرفته نمیشوند، توسط یک نفر گرفته نمیشوند و قطعاً یک شبه بر اساس یک نظر GitHub گرفته نمیشوند.
TC39 بر روی یک فرآیند مرحله بندی واضح برای پیشنهادات ویژه عمل می کند. پیشنهادات ECMAScript و هرگونه تغییر عمده در آنها (از جمله تغییر نام روش) در طول جلسات TC39 مورد بحث قرار می گیرد و قبل از رسمی شدن باید توسط کل کمیته تأیید شود. در مورد Array.prototype.flatten
، این پیشنهاد قبلاً چندین مرحله از توافق را طی کرده است، تا مرحله 3، که نشان میدهد این ویژگی برای پیادهسازی در مرورگرهای وب آماده است. معمولاً در حین پیاده سازی مسائل مربوط به مشخصات اضافی مطرح می شود. در این مورد، مهمترین بازخورد پس از تلاش برای ارسال آن صورت گرفت: این ویژگی، در وضعیت فعلی خود، وب را می شکند. پیشبینی مشکلاتی از این دست بخشی از دلایلی است که فرآیند TC39 تنها زمانی که مرورگرها یک ویژگی را ارسال میکنند به پایان نمیرسد.
TC39 بر اساس اجماع عمل می کند، به این معنی که کمیته باید در مورد تغییرات جدید موافقت کند. حتی اگر smoosh
یک پیشنهاد جدی بود، به نظر می رسد که یکی از اعضای کمیته به نفع نام رایج تر مانند compact
یا chain
به آن اعتراض کند.
تغییر نام از flatten
به smoosh
(حتی اگر شوخی نبود) هرگز در جلسه TC39 مورد بحث قرار نگرفته است. به این ترتیب، موضع رسمی TC39 در مورد این موضوع در حال حاضر ناشناخته است. هیچ فردی نمی تواند به نمایندگی از همه TC39 صحبت کند تا زمانی که در جلسه بعدی اجماع حاصل شود.
در جلسات TC39 عموماً افرادی با سوابق بسیار متنوع شرکت میکنند: برخی از آنها سالها تجربه طراحی زبان برنامهنویسی دارند، برخی دیگر بر روی یک مرورگر یا موتور جاوا اسکریپت کار میکنند، و تعداد فزایندهای از همراهان برای نشان دادن جامعه توسعهدهندگان جاوا اسکریپت در آنجا حضور دارند.
سرانجام SmooshGate چگونه حل شد؟
در جلسه می 2018 TC39 ، #SmooshGate رسما با تغییر نام flatten
به flat
حل شد.
Array.prototype.flat
و Array.prototype.flatMap
در نسخه 8 نسخه 6.9 و کروم 69 ارسال شدند.
چه اتفاقی افتاده؟!
یک پیشنهاد برای یک ویژگی زبان جاوا اسکریپت به نام Array.prototype.flatten
معلوم می شود که با وب ناسازگار است. ارسال این ویژگی در فایرفاکس نایتی باعث شکسته شدن حداقل یک وب سایت محبوب شد. با توجه به اینکه کد مشکل ساز بخشی از کتابخانه گسترده 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، جاوا اسکریپت و هر استاندارد دیگری است که به طور گسترده در وب استفاده می شود. اگر ارسال یک ویژگی مرورگر جدید باعث از کار افتادن وبسایتهای موجود شود، برای همه بد است:
- بازدیدکنندگان وبسایتهای آسیبدیده به طور ناگهانی یک تجربه کاربری شکسته دریافت میکنند.
- صاحبان وبسایت از داشتن یک وبسایت کاملاً کارآمد به یک وبسایت غیرعملکردی بدون تغییر چیزی تبدیل شدند.
- فروشندگان مرورگر که ویژگی جدید را ارسال می کنند، سهم بازار خود را از دست می دهند، زیرا کاربران بعد از اینکه متوجه شدند «در مرورگر X کار می کند» مرورگرها را تغییر می دهند.
- هنگامی که مشکل سازگاری مشخص شد، سایر فروشندگان مرورگر از ارسال آن خودداری می کنند. مشخصات ویژگی با واقعیت مطابقت ندارد ( "هیچ چیز جز یک اثر تخیلی" )، که برای فرآیند استانداردسازی بد است.
مطمئناً، در نگاهی به گذشته، MooTools کار اشتباهی انجام داد - اما شکستن وب آنها را مجازات نمی کند، بلکه کاربران را مجازات می کند. این کاربران نمی دانند ابزار moo چیست. از طرف دیگر، ما می توانیم راه حل دیگری پیدا کنیم و کاربران می توانند به استفاده از وب ادامه دهند. انتخاب آسان است.
آیا این بدان معناست که API های بد هرگز نمی توانند از پلتفرم وب حذف شوند؟
بستگی دارد. در موارد نادر، ویژگیهای بد را میتوان از وب حذف کرد . حتی فهمیدن اینکه آیا امکان حذف یک ویژگی وجود دارد یا خیر، تلاش بسیار دشواری است، که به تله متری گسترده برای تعیین کمیت تعداد صفحات وب که رفتارشان تغییر می کند، نیاز دارد. اما زمانی که این ویژگی به اندازه کافی ناامن است، برای کاربران مضر است، یا به ندرت استفاده می شود، می توان این کار را انجام داد.
<applet>
، <keygen>
و showModalDialog()
همگی نمونههایی از APIهای بدی هستند که با موفقیت از پلتفرم وب حذف شدند.
چرا ما فقط MooTools را تعمیر نمی کنیم؟
وصله MooTools به طوری که دیگر اشیاء داخلی را گسترش ندهد ایده خوبی است. با این حال ، مشکل مورد نظر را حل نمی کند. حتی اگر Mootools یک نسخه وصله دار را منتشر کند ، تمام وب سایت های موجود که از آن استفاده می کنند ، برای از بین رفتن مشکل سازگاری باید به روز شوند.
آیا مردم فقط نمی توانند نسخه خود را از Mootools به روز کنند؟
در یک دنیای عالی ، Mootools یک پچ منتشر می کند ، و هر وب سایت با استفاده از Mootools روز بعد به طرز جادویی به روز می شود. مشکل حل شد ، درست است؟!
متأسفانه ، این غیر واقعی است. حتی اگر کسی بخواهد مجموعه کاملی از وب سایت های آسیب دیده را به نوعی شناسایی کند ، می تواند اطلاعات تماس را برای هر یک از آنها پیدا کند ، با موفقیت به همه صاحبان وب سایت دسترسی پیدا کند و همه آنها را متقاعد کند که به روزرسانی را انجام دهند (که این به معنای اصلاح مجدد آنهاست. کل پایه کد) ، کل فرآیند سالها طول می کشد.
به خاطر داشته باشید که بسیاری از این وب سایت ها قدیمی هستند و احتمالاً غیرقابل تحمل هستند. حتی اگر نگهدارنده هنوز در اطراف باشد ، ممکن است آنها یک توسعه دهنده وب بسیار ماهر مانند خودتان نباشند. ما نمی توانیم انتظار داشته باشیم که همه به دلیل مسئله سازگاری در وب ، وب سایت 8 ساله خود را تغییر دهند.
روند TC39 چگونه کار می کند؟
TC39 کمیته مسئول تحول زبان جاوا اسکریپت از طریق استاندارد ECMAScript است.
#Smooshgate باعث شد برخی اعتقاد داشته باشند که "TC39 می خواهد flatten
به smoosh
تغییر دهد" ، اما این یک جکوک بود که از نظر بیرونی کاملاً سازگار نبود. تصمیمات اساسی مانند تغییر نام پیشنهادی به آرامی اتخاذ نمی شود ، توسط یک شخص مجرد گرفته نمی شود و قطعاً براساس یک اظهار نظر GitHub شبانه روزی گرفته نمی شود.
TC39 برای پیشنهادات ویژگی بر روی یک فرآیند مرحله بندی روشن عمل می کند. پیشنهادات ECMAScript و هرگونه تغییر عمده در آنها (از جمله تغییر نام روش) در جلسات TC39 مورد بحث قرار می گیرد و قبل از رسمی شدن باید توسط کل کمیته تأیید شود. در مورد Array.prototype.flatten
، این پیشنهاد در حال حاضر چندین مرحله از توافق را طی کرده است ، تمام راه تا مرحله 3 ، نشان می دهد که این ویژگی آماده اجرای در مرورگرهای وب است. این معمول است که موضوعات خاص اضافی در حین اجرا مطرح شود. در این حالت ، مهمترین بازخورد پس از تلاش برای ارسال آن به وجود آمد: این ویژگی ، در وضعیت فعلی خود ، وب را می شکند. موضوعات سخت پیش بینی مانند اینها بخشی از دلیل این است که فرایند TC39 فقط به محض ارسال مرورگرها یک ویژگی پایان نمی یابد.
TC39 با اجماع عمل می کند ، به این معنی که کمیته باید در مورد هرگونه تغییر جدید توافق کند. حتی اگر smoosh
یک پیشنهاد جدی بوده است ، به نظر می رسد که یک عضو کمیته به نفع یک نام رایج تر مانند compact
یا chain
به آن اعتراض کند.
تغییر نام از flatten
به smoosh
(حتی اگر این شوخی نبوده است) هرگز در جلسه TC39 مورد بحث قرار نگرفته است. به همین ترتیب ، موضع رسمی TC39 در مورد این موضوع در حال حاضر ناشناخته است. هیچ فرد مجرد نمی تواند به نمایندگی از همه TC39 صحبت کند تا اینکه در جلسه بعدی به اجماع برسد.
جلسات TC39 به طور کلی توسط افرادی که پیشینه بسیار متنوعی دارند برگزار می شود: برخی از سالها تجربه طراحی زبان برنامه نویسی دارند ، برخی دیگر روی یک مرورگر یا موتور جاوا اسکریپت کار می کنند و تعداد فزاینده ای از شرکت کنندگان در آنجا برای نمایندگی جامعه توسعه دهنده جاوا اسکریپت وجود دارد.
سرانجام چگونه Smooshgate برطرف شد؟
در جلسه TC39 مه 2018 ، #SMOOSHGATE با تغییر نام flatten
به flat
رسماً حل شد.
Array.prototype.flat
و Array.prototype.flatMap
در V8 V6.9 و Chrome 69 ارسال شده است.