چه اتفاقی افتاده؟!
یک پیشنهاد برای یک ویژگی زبان جاوا اسکریپت به نام 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 ارسال شدند.