نماد علمی، و یک برنامه‌نویس بدشانس

خوش و خرم نشسته بودم که یکی از مشتری‌ها تماس گرفت و گفت یکی از پست‌های وبلاگش را نمی‌تواند باز کند.

مورد جالبی بود. برنامه همه‌ی پست‌های مشابه دیگر را باز می‌کرد، جز همین یکی!

هرچه رکوردش را بررسی کردم، اختلاف سرنوشت‌سازی در کار نبود. حتی همه‌ی محتویات یک رکورد دیگر را هم در آن رکورد ریختم و باز هم باز نشد. و همه‌ی محتوای آن رکورد معیوب را در جای دیگر ریختم و باز شد!

چند دقیقه‌ای طول کشید تا عامل مزاحمت را یافتم و چند دقیقه‌ی دیگر هم طول کشید تا بفهمم آخر چرا!

ملاحظه بفرمایید:

خودتان هم بروید و بعداً آزمایش کنید.
خودتان هم بروید و بعداً آزمایش کنید.

شرح ماجرا

می‌دانیم که در جداول بانک اطلاعاتی، هر رکورد یک id دارد که با آن شناخته می‌شود و اگر این شناسه را داشته باشیم، راحت می‌گردیم و رکورد مورد نظر را برمی‌داریم و استفاده می‌کنیم.

این را هم می‌دانیم که نمایش id واقعی یک رکورد در آدرس‌های url فکر خوبی نیست. هر کسی با دیدن یک عدد در نشانی بالای براوزر، ممکن است به سرش بزند که آن را عوض کند و عدد دیگری را امتحان کند و این وسط، هزار اتفاق پیش‌بینی‌نشده ممکن است بیافتد. مثل این ماجرا که یک سال و نیم پیش برای بانک ملت رخ داد و باعث شد ظرف دو ساعت بعد از توییت من، سایت بانک را برای اصلاح پایین بیاورند و شب هم در تلویزیون داشتند شایعه‌ی مطرح‌شده در فضای مجازی را تکذیب می‌کردند.

الان دیگر امتحانش نکنید. قضیه مال همان موقع بود و فوراً اصلاح شد.
الان دیگر امتحانش نکنید. قضیه مال همان موقع بود و فوراً اصلاح شد.

من برای دفع این خطر، از ابزار Hashids استفاده می‌کنم که پکیجی برای تقریباً همه‌ی زبان‌های برنامه‌نویسی و فریمورک‌های معروف دارد و کارش این است که هر عدد مثل ۱۲۳ را به کد عجیب و غریب و بی‌ربطی مثل doe2Ez تبدیل کند که حضورش در url بی‌خطر باشد و بازگرداندنش به مقدار اصلی، نیازی به کوئری زدن و محاسبات پیچیده نداشته باشد، و در عین حال فقط شامل ارقام نباشد و کلمه‌ی معنی‌داری در زبان انگلیسی هم ساخته نشود.

پکیج Hashids در لاراول، از تنظیماتی استفاده می‌کند که می‌توانید نمک تغییر و الفبای مورد استفاده و حداقل تعداد کاراکتر را برایش تعیین کنید. من از چیزی شبیه این استفاده می‌کردم:

هشدار: پیش از انتشار عکس چنین صحنه‌هایی، حتماً کمی عوضش بکنید. آدم عاقل کلید رمزش را به بقیه نشان نمی‌دهد.

طبیعتاً الفبای مورد استفاده را باید طوری تعیین کنیم که برای حضور در آدرس بالای براوزر مشکلی نداشته باشند. برای مثال، در چنین رشته‌ای نباید کاراکترهایی مثل علامت سؤال یا هشتگ را داشته باشیم که ممکن است مفهوم خاصی برای نشانی داشته باشند.

بیان خودِ مشکل

من پیش از کوئری زدن، محض اطمینان چک می‌کردم که اگر کد دریافتی، یک هش‌آی‌دیِ مجاز نبود، یا اصلاً از نوع رشته‌ای (string) نبود، زحمت کوئری نکشیم و همان جا بگوییم چنین صفحه‌ای نیست.

و مشکل هم از همین جا شروع شد.

خیالم راحت بود که پکیج Hashids هیچ وقت خروجی‌ای فقط عددی به من نمی‌دهد، اما در این مورد اتفاقی افتاده بود که شاید شانس وقوع آن یک در میلیارد هم نباشد.

خروجی Hashids چیزی شبیه 344E3 بود و تابع is_numeric در php، آن را عدد تشخیص می‌داد! (به عکس بالای صفحه مراجعه کنید. هر کاری کردم نتوانستم آن را دوباره اینجا بگذارم و ویرگول بعد از انتشار، آن را برمی‌داشت و می‌انداخت دور!)

اما چرا؟!

در ریاضی، مفهومی به نام «نماد علمی» داریم که به بیان ویکی‌پدیا، «روشی است برای نوشتن اعدادی که خیلی بزرگ یا خیلی کوچکند و نمی‌توان به سادگی آن‌ها را در نماد ده‌دهی نوشت».

خودِ ریاضی‌دان‌ها به شکل زیر از نماد علمی استفاده می‌کنند:

که معنا و مفهوم آن ۳۴۴ با سه تا صفر است، یا به عبارتی، ۳۴۴،۰۰۰.

اما چون امکان نوشتن چنین قالبی در ماشین‌حساب‌های علمی قدیمی وجود نداشت و همین حالا هم در خیلی از ویرایشگرها نمی‌توانیم آن را درست تایپ کنیم و همه جا هم که مثل ویرگول نمی‌شود عکسش را آپلود کرد، صورت دیگری برای نمایشش اختراع شد،‌ و آن استفاده از نماد E بود که باید حواسمان باشد با عدد نپر اشتباه گرفته نشود.

344E3

به عنوان یک قاعده‌ی اساسی در زندگی، هرچقدر هم که احتمال وقوع یک اتفاق کم باشد، برای من حتماً پیش خواهد آمد.

با وجود ملاحظه‌ای که Hashids کرده بود تا هیچ گاه «عدد» تحویل ندهد و مراقبتی که من کرده بودم تا عدد تحویل نگیرم، هیچ کدام حساب این جای کار را نکرده بودیم.

راه حل

خیلی ساده، سراغ تنظیمات Hashids رفتم و الفبا را طوری تغییر دادم که برای ساخت هش‌آی‌دیِ مورد استفاده در این جور کارها، دیگر هیچ وقت از هیچ عددی استفاده نکند.