داستان یک Date بد!

👁 759 بازدید ❤️ 22 واکنش 📤 19 فوروارد

داستان یک Date بد!


گاهی بزرگ‌ترین باگ‌ها، اون‌هایی نیستن که همون لحظه خطا بدن یا سیستم رو متوقف کنن. بلکه گاهی باگ، ۲۰ سال، ۳۰ سال، یا حتی بیشتر کنار ما زندگی می‌کنه. همه هم می‌دونن که بده. همه هم تجربه‌اش کردن. همه هم حداقل یک بار بهش فحش و فضیحت دادن. ولی چون میلیون‌ها خط کد بهش وابسته‌ است، کسی جرأت نمی‌کنه مستقیم دست ببره و درستش کنه.


شروع ماجرا: ده روز فرصت و یک تصمیم عجولانه

سال ۱۹۹۵، Brendan Eich در Netscape، شرکتی که بعدها پروژه Mozilla از دلش بیرون اومد؛ فقط ده روز وقت داشت تا زبونی بسازه که بعداً اسمش شد JavaScript. دستور مدیریت هم روشن بود: «شبیه جاوا بسازش.» در چنین شرایطی، برای بخش تاریخ و زمان، ساده‌ترین راه رو رفت: Date رو مستقیم از java.util.Date کپی کرد (به بیان دقیق‌تر: در عمل Date جاوا به JavaScript منتقل شد؛ حتی Brendan بعدتر توضیح داده که این بخش، port مستقیمی از Date جاوا به C بوده. Ken Smith که یکی از توسعه‌دهنده‌های Netscape بود قبلاً از Borland اومده بود؛ java.util.Date نسخه JDK 1.0 جاوا رو port کرد. این port مستقیماً برای موتور JavaScript Netscape انجام شد، که عمدتاً به زبان C بو که بعدتر به ++C نوشته شد.)!


نکته‌ی جالب اینجاست که خودِ اون پیاده‌سازی جاوا هم از اول مشکل‌دار بود؛ اونقدر افتضاح بود که فقط دو سال بعد، توی جاوا ۱.۱، تقریباً اکثر متدهاش منسوخ شدن و با یه API جدید جایگزین شدن. یعنی جاوااسکریپت یک طراحی معیوب رو از زبانی به ارث برد که خودش هم اون رو منسوخ کرد بعداً. و چون طبق اصل بنیادین TC39 یعنی «don't break the web» هیچ تغییری در Date مجاز به شکستن کدهای موجود نبود، این طراحی معیوب دقیقاً همون‌طور که بود، در استاندارد ECMAScript 1 (سال ۱۹۹۷) رسمی و منجمد شد.

فهرست مشکلات هم که برای هر کسی که با جاوااسکریپت کار کرده آشناست:

ماه‌ها zero-indexed هستند (0 میشه ژانویه) ولی روزها و سال‌ها نه! یک ناهماهنگی بی‌دلیل که فقط باگ تولید می‌کرد.

آبجکت قابل تغییر (mutable) است؛ یعنی هر تابعی که یک Date بهش پاس بده می‌تونه بی‌سروصدا مقدارش رو عوض کنه.

هیچ پشتیبانی واقعی از timezone وجود نداشت و فقط UTC و timezone محلی سیستم.

رفتار parser اون‌قدر غیرقابل پیش‌بینی بود که در عمل غیرقابل‌اعتماد محسوب می‌شد.

هیچ پشتیبانی از تقویم‌های غیرمیلادی (هجری و…) نداشت.

برای دو دهه، راه‌حل اکوسیستم این بود که این مشکلات رو دور بزنن، و نه اینکه حل کنن. کتابخونه‌هایی مثل Moment.js (که خودش mutable بود و باندل سنگینی داشت)، بعدتر هم چندین کتابخونه دیگه که هرکدوم یک لایه‌ی محافظتی روی یه هسته‌ی خراب ساختن، از راه رسیدن. الگویی که هر مهندسی می‌شناسه: وقتی یک مشکل بنیادین رو نمی‌شه حل کرد، دورش دیوار می‌کشیم و اسمش رو می‌گذاریم best practice 😅


نقطهٔ شروع واقعی: یک گفتگوی توییتری

اینجا بخشی از داستانه که کمتر روایت می‌شه و برای منی که سال‌هاست دنبال «لحظه‌های شروع» می‌گردم، جالب‌ترین قسمت ماجراست. سال ۲۰۱۷، Maggie Pint که اون موقع یه مهندس نرم‌افزار توی مایکروسافت بود و هنوز لید هم نشده بود، طی یک گفتگوی توییتری با Brendan Eich (خالق جاوااسکریپت) و Matt Johnson (نگهدارندهٔ Moment.js) درباره‌ی همین ذات خراب Date صحبت می‌کردن. و همون گفتگو بود که Brendan تاریخچه‌ی تصمیم ده‌روزه‌اش رو براشون تعریف می‌کنه. از دل همین صحبت، Maggie با Brian Terlson (نمایندهٔ مایکروسافت توی TC39 و ویراستار وقت ECMA262) هم آشنا می‌شه و همون‌جا تصمیم می‌گیرن که وقتش رسیده این مشکل رو از بیخ حل کنن.

نکته‌ای که باید با دقت گفت: این داستانِ «یک نفر که تنهایی یه مشکل بیست‌ساله‌ی زبان رو حل کرد» نیست؛ و اینجوری گفتنش، بی‌احترامی به شخصیت کاری این افراد، و به واقعیتِ پروژه است. اونچه واقعاً اتفاق افتاده این بوده که یک گفتگوی غیررسمی توی توییتر، نقطهٔ شروع یک تلاش چندساله و رسمی در TC39 شده؛ با آدم‌های مهمی مثل Philipp Dunkel، Maggie Pint ،Matt Johnson-Pint، و Shane F. Carr، به‌علاوه‌ی توسعه‌دهنده‌هایی مثل Bloomberg و Igalia که پروپوزال Temporal رو رسماً همون سال ۲۰۱۷ باز کردن. جالب اینجاست که این تلاش عظیم و چندساله، سرمنشأیی به این کوچکی و این غیررسمی داشته.


حالا چرا این‌قدر طول کشید؟

پروپوزال Temporal مسیر استاندارد TC39 رو طی کرد:

سال ۲۰۱۷ — Stage 1: پذیرش پروپوزال به‌عنوان یک مسیر اکتشافی.

سال ۲۰۱۹ — Stage 2: انتشار طراحی اولیه.

سال ۲۰۲۱ — Stage 3: تکمیل spec و پیاده‌سازی‌های آزمایشی شروع شدن.

مارس ۲۰۲۶ — Stage 4: که Temporal رسماً بخشی از ECMAScript 2026 می‌شه.

عملا ۹ سال، فقط برای طی‌کردن این مراحل. چرا؟ چون این بار قرار نبود همون اشتباه تکرار بشه. طراحی Temporal باید همه‌چیز رو پوشش می‌داد: تقویم‌های قمری-شمسی چینی، تقویم اسلامی، عبری، امپراتوری ژاپن؛ دیتابیس جهانی timezone یعنی IANA TZDB با تمام گذارهای DST؛ محاسبات duration با ماه‌ها و سال‌های با طول متغیر؛ و یکپارچگی عمیق با Intl. توی این مسیر، هر ادعای «تمام شد» با یک edge case جدید (مثل رفتار مبهم wall-clock در لحظهٔ تغییر ساعت DST) نقض می‌شده و spec دوباره اصلاح می‌شده.

یک تلنگر جالب هم در سال ۲۰۲۲ اتفاق افتاده: آسیب‌پذیری path traversal در Moment.js (CVE-2022-31129) نشون داد که حتی کتابخونه‌های پایه‌ای هم بخشی از سطح حمله اپلیکیشن می‌شن. این اتفاق استدلال برای وجود یک راه‌حل native رو قوی‌تر کرد.


رسیدن به مقصد: Node.js 26

پنجم ماه می امسال، Node.js 26 منتشر شد و برای اولین‌بار Temporal بدون هیچ flag یا پیش‌نیازی، به‌صورت پیش‌فرض فعال بود. دیگه نیازی به فلگ و کتابخونه اضافی نیست.

نتیجه، چیزیه که هر کسی که این ۳۱ سال با این زبونِ پرحاشیه زندگی کرده، حسرتش رو داشته!


💡 چیزی که این داستان یادم می‌اندازه

من سال‌هاست درباره‌ی فاصله‌ی بین «مهارت فنی» و «ownership» زیاد نوشتم، صحبت کردم و تلاش کردم توی مسیر رشد دیگران قرار بدم. این داستان، دقیقاً همون فاصله رو نشون می‌ده، اما در سطح یک اکوسیستم کامل. تصمیم Brendan Eich در ۱۹۹۵ نه غیرمنطقی بود و نه بی‌کفایتی؛ او ده روز وقت داشت. مشکل واقعی جای دیگه‌ای بود: این بدهی فنی برای دو دهه به رسمیت شناخته می‌شد، دورش مستندسازی و کتابخونه ساخته می‌شد، ولی هیچ گروه مشخصی مسئولیت حل ریشه‌ای‌اش رو عهده نمی‌گرفتن! تا اینکه یک گفتگوی غیررسمی، افراد درست رو در یک اتاق (یا یک رشتو توییتری) کنار هم گذاشت.

نکته برای من این نیست که «یک نفر جسور مشکل بیست‌سی‌ساله‌ی یه زبون رو حل کرد». نکته اینه که حل بدهی فنی بزرگ، همیشه به یک لحظهٔ شروع کوچیک نیاز داره. یک نفر که تصمیم می‌گیره به‌جای دورزدن مشکل، درباره‌ی ریشه‌اش صحبت کنه. بعدش کار سخت، یعنی ۹ سال طراحی دقیق و صبورانه، شروع می‌شه. و اون بخش، هیچ‌وقت کار یک نفر نیست.


پی‌نوشت: این بخش کوچکی از یه ارائه مفصل چند جلسه‌ای برای گروهی از تازه لیدِ فنی شده‌های یه سازمان بزرگ بود؛ گاهی برای یادگیری؛ مثال و داستان بهتر از شمردن نکته‌ها و تیترهاییه که یا سریع از خاطر می‌رن یا تبدیل می‌شن به لقلقه زبون آدم‌ها برای شوآف. اگر دوست داشتید؛ PostgreSQL یا MongoDB یا داستان Mel و Monorail و... هر کدوم مثل حکایت‌های کلیله و دمنه یا بوستان سعدی هستن (البته در مثال محل مناقشه نیست) که در قالب یه قصه میشه ده‌ها صفحه درس و نکته رو یاد گرفت. علاقه‌مند بودید لابلای وبلاگ پدیدآورنده‌ها و ردیت و توییتر، داستان‌های جذابی پیدا می‌شه. یا سری مصاحبه‌های Ryan Peterman یا داستان‌های Dave Plummer


پی‌نوشت۲: احتمالا مطلب بعدی یا A2UI خواهد بود یا در مورد روش‌های ارزیابی عملکرد دوره‌ای تیم‌های فنی. اگر پیشنهاد یا نکته‌ای دارید حتمن کامنت کنید :)


← بازگشت به همه پست‌ها