داستان مل
این داستان در ۲۱ می ۱۹۸۳، توسط نویسندهاش Ed Nather nather@astro.as.utexas.edu در Usenet ارسال شده است.
یکی از مقالاتی که اخیرا منتشر شده است، اظهار کرده است که: «برنامهنویسان حقیقی با FORTRAN برنامه مینویسند.» شاید امروز آنها این کار را انجام میدهند، در عصر آبجوهای رژیمی، ماشین حسابهای دستی و نرمافزار «کاربر پسند». اما در روزهای خوب گذشته، هنگامی که عبارت «نرمافزار» خندهدار به نظر میرسید و کامپیوترهای واقعی از بشکه و لولههای جاروبرقی ساخته میشدند، برنامهنویسان حقیقی به زبان ماشین مینوشتند. نه FORTRAN، نه RATFOR و نه حتی زبان اسمبلی. زبان ماشین. مستقیما با اعداد شانزدهتاییِ زشت و خام. شاید هیچ کدام از برنامهنویسان نسل جدید از آن گذشتهٔ باشکوه اطلاع نداشته باشند. من وظیفهٔ خود میدانم که از میان شکاف نسلها، تا آنجایی که در توانم است، توضیح دهم که یک برنامهنویس حقیقی چگونه کد مینوشت. من او را مِل خواهم نامید، چرا که این نام واقعیاش است.
من اولین بار مِل را هنگامی ملاقات کردم که برای کار در شرکت Royal McBee، شرکتی جدید و از بین رفته که تابع شرکت typewriter بود، استخدام شده بودم. یک شرکت کوچک که LGP-30، یک کامپیوتر کوچک با حافظهٔ گردان و ارزان قیمت (با معیارهای روز) را تولید میکرد. و به تازگی شروع به تولید RPC-4000، یک مدل بزرگتر، بهتر و سریعتر با حافظهٔ گردان کرده بود. این کار بسیار هزینهبر بود، و چندان هم دوام نیاورد (به همین دلیل است که شما چیزی دربارهٔ شرکت و این مدل کامپیوتر نشنیدهاید.) من استخدام شده بودم تا برای این سیستم فوقالعاده یک کامپایلرِ FORTRAN بنویسم و مِل مرا در مورد شگفتیهای مدل جدید راهنمایی میکرد. این کامپیوترها مورد پسند مِل نبودند. میپرسید: «اگر برنامه نتواند کد خود را بازنویسی کند، خوبیاش چیست؟»
مِل محبوبترین برنامهای را که شرکت در اختیار داشت با کدهای شانزدهتایی نوشته بود. این برنامه بر روی LGP-30 اجرا میشد و بازی بلکجک را با مشتریان بالقوهٔ شرکت در نمایشگاهها انجام میداد. تاثیر آن همواره عالی بود. در تمام نمایشگاهها غرفهٔ LGP-30 پر ازدحام بود، و فروشندگان IBM همان اطراف ایستاده بودند و با یکدیگر صحبت میکردند. این که این برنامه باعث فروش کامپیوترها میشد یا نه، موضوعی بود که ما هرگز دربارهٔ آن حرف نمیزدیم.
وظیفهٔ مِل این بود که برنامهٔ بلکجک را برای RPC-4000 بازنویسی کند. کامپیوتر جدید یک طرح آدرس دهیِ یک به علاوهٔ یک داشت. در این طرح، هر دستور ماشین، به علاوهٔ کد دستور و آدرسی که برای عملوند خود احتیاج دارد، یک آدرس ثانوی داشت که به محل دستور بعدی بر روی حافظهٔ گردان اشاره میکرد. در اصطلاح امروزی، پس از هر دستور یک GO TO میآمد. مِل عاشق RPC-4000 بود چرا که میتوانست کد خود را بهینه سازی کند: محل دستور را در حافظهٔ گردان مشخص کند و بنابراین درست همان لحظهای که یک دستور کار خود را به اتمام میرساند، دیگری در «هد خواندن» منتظر و آمادهٔ اجرا بود. برنامهای وجود داشت به نام «بهینهساز اسمبلی» که این کار را انجام میداد، اما مِل از آن استفاده نمیکرد. او توضیح میداد: «هیچ وقت نمیتوانی بفهمی قرار است چیزها را کجا قرار دهد، پس مجبوری از ثابتهای مجزا استفاده کنی.» و این خیلی پیش از آن بود که بتوانم این سخن را درک کنم. از آنجایی که مِل مقادیر اعداد را برای هر کد دستور میدانست، و آدرسهای مختص خود را به آنها نسبت میداد، هر دستوری که او مینوشت میتوانست شامل یک ثابت عددی نیز باشد. میتوانست یک دستور «جمع» را پیشاپیش بردارد، و به عنوان مثال، اگر شامل مقدار درست بود، آن را در یک عدد ضرب کند. ویرایش کدی که او مینوشت، برای دیگران دشوار بود.
من برنامهای که مِل به صورت دستی بهینهسازی کرده بود را با آنچه «بهینهساز اسمبلی» تولید کرده بود مقایسه کردم، و برنامهٔ مِل همیشه سریعتر اجرا میشد. دلیلاش این بود که شیوهٔ طراحی «بالا به پایین» هنوز ابداع نشده بود و به هر حال مِل از آن استفاده نمیکرد. او درونیترین حلقههای برنامه را در ابتدا مینوشت، بنابراین آنها میتوانستند بهینهترین مکانهای آدرس بر روی حافظه را در اختیار گیرند. برنامهٔ «بهینهساز اسمبلی» به اندازهٔ کافی باهوش نبود تا بتواند چنین کاری انجام دهد. همچنین مِل هرگز چرخههای تاخیر زمانی نمینوشت، حتی هنگامی که برنامهٔ نافرمانِ Flexowriter برای درست عمل کردن احتیاج به تاخیر میان کاراکترهای خروجی داشت. او تنها محل دستورها را بر روی حافظهٔ گردان مشخص میکرد، و دستور بعدی درست در همان لحظهای که به آن نیاز بود، از زیر هد خواندن عبور میکرد؛ و حافظهٔ گردان برای پیدا کردن دستور بعدی مجبور بود یک دستور عجیب دیگر را اجرا کند.
او یک واژهٔ فراموش نشدنی را برای این فرایند ابداع کرده بود. از آنجایی که «بهینه» همانند «یکتا» یک واژهٔ مطلق بود، پیدا کردن واژهٔ مناسب به نوعی مسابقه بدل شده بود: «نه کاملا بهینه» یا «کمتر بهینه» یا «نه خیلی بهینه». مِل مکانهای با حداکثر تاخیر زمانی را «بدبینانهترین مکانها» مینامید.
بعد از اینکه او برنامهٔ بلکجک را به پایان رساند و آن را برای اجراشدن تحویل داد (او با افتخار میگفت: «حتی شروع کنندهٔ آن نیز بهینه سازی شده است.») از طرف بخش فروش درخواست انجام تغییراتی را دریافت کرد. برنامه از یک تولید کنندهٔ اعداد تصادفی زیبا (بهینه شده) برای بُر زدن دستهٔ ورقها استفاده میکرد، و بعضی از مسئولان فروش احساس میکردند که این کار زیادی عادلانه است، چرا که گاهی اوقات مشتری میباخت. آنها از مِل خواستند که برنامه را به گونهای تغییر دهد که با فعال کردن کلیدی بر روی کامپیوتر، بتوانند شرایط را به گونهای تغییر دهند که مشتری برنده شود.
مِل قبول نکرد. او احساس میکرد که این کار تقلب است، که در حقیقت بود، و اخلاقیات او را به عنوان یک برنامه نویس زیر پا میگذارد، که در حقیقت میگذاشت. بنابراین او از انجام آن سرپیچی کرد.
سرپرست فروش با مِل صحبت کرد، رئیس بزرگ به همراه چند برنامهنویس دیگر نیز با او صحبت کردند. سرانجام مِل قبول کرد و برنامه را نوشت، اما به طور معکوس. هنگامی که کلید فعال میشد برنامه تقلب میکرد و همیشه برنده میشد. مِل از انجام این کار لذت میبرد و با ادعای این که ذهنش به صورت ناخودآگاه اخلاقی عمل میکند، با یکدندگی از درست کردن آن سرباز زد.
هنگامی که مِل شرکت را ترک کرد تا چراگاه سرسبزتری بیابد، رئیس بزرگ از من خواست تا نگاهی به کد بیندازم، و عملکرد آن را معکوس کنم. تقریبا با بیمیلی قبول کردم که نگاهی به آن بیندازم. دنبال کردن کدِ مِل یک ماجراجویی حقیقی بود. من اغلب احساس میکردم که آن سبک برنامه نویسی نوعی هنر است، که ارزشاش را تنها یک شاعر از همان فرقهٔ مخفی هنری درک میکند. جواهرات دوست داشتنی و پیروزیهای شگفت انگیزی وجود دارند که بوسیلهٔ فرایندهای طبیعی، گاهی اوقات برای همیشه، از دید و تحسین انسانها دور میمانند. با خواندن کد دیگران، حتی هنگامی که با اعداد شانزدهتایی نوشته شده باشد، میتوانید چیزهای بسیاری دربارهٔ نویسندهٔ آن فرا گیرید. فکر میکنم مِل نابغهای شناخته نشده بود.
شاید بزرگترین شوک هنگامی به من وارد آمد که متوجه شدم درون حلقهٔ اصلی برنامه هیچ شرطی برای پایان حلقه وجود نداشت. هیچ شرطی. هیچ.
غریزه میگفت که این حلقه باید بسته باشد، جایی که برنامه در یک دایره، برای همیشه و بدون پایان بچرخد. اما برنامه درست از میان آن گذر میکرد، و به هر صورت، بدون هیچ مشکلی از سوی دیگر خارج میشد. دو هفته طول کشید تا چگونگی عملکرد آن را درک کنم.
کامپیوتر RPC-4000 یک قابلیت مدرن درون خود داشت که به نام ثَبّاتِ شاخص (index register) شناخته میشد. این ثَبّات به برنامه نویس اجازه میداد که یک حلقه بنویسد که از یک دستور شاخص گذاری شده استفاده میکند؛ هر بار عددی که در ثَبّات بود به آدرسِ این دستور اضافه میشد و به محل دستور بعدی در حلقه اشاره میکرد. و تنها کافی بود که هربار یک واحد به ثبّات اضافه شود. مِل هرگز از این قابلیت استفاده نکرد. به جای آن، دستور را در یکی از ثبّاتهای ماشین قرار میداد، یک واحد به آدرس آن اضافه کرده و دوباره آن را ذخیره میکرد. سپس دستور تغییر یافته را مستقیماً از ثبّات اجرا میکرد. این حلقه به گونهای نوشته شده بود که از زمانی که برای اجرای این دستور اضافی صرف میشود بهره گیرد—درست هنگامی که اجرای این دستور به پایان میرسید، دستور بعدی درست زیر هدِ خواندنِ حافظهٔ گردان قرار میگرفت و آمادهٔ اجرا.
اما حلقه یک شرط پایان نیز درون خود داشت. مدرکی که برای حل این معما نیاز داشتم هنگامی بدست آمد که ثبّات شاخص را برسی کردم، بیتی که بین آدرس و کد دستور آن قرار میگرفت روشن شده بود—با این حال از آنجایی که مِل هرگز از ثبّات شاخص استفاده نکرده بود، مقدار آن را همشه صفر نگه میداشت. نوری که از درک موضوع بر من تابید تقریبا کورم کرد. او اطلاعاتی را که با آنها کار میکرد تقریبا در بالای حافظه نگاه داشته بود—بزرگترین مکانی که دستورات برنامه میتوانستند آدرس دهی شوند—بنابراین بعد از اینکه آخرین دستور اجرا شد، اضافه کردن یک واحد به آدرس باعث سرریز میشد. رقم نقلی یک واحد به کد دستور اضافه میکرد، و آن را به دستور بعدی تبدیل میکرد: یک دستور پرش. به اندازهٔ کافی مطمئن بودم که دستور بعدی در مکان صفرِ حافظه قرار دارد، و برنامه با خوش حالی به راه خود ادامه میداد.
من دیگر با مِل در تماس نبودم، بنابراین نمیدانم که آیا او هرگز درون موجِ تغییر که تمام شیوههای برنامهنویسی را تغییر داد گرفتار آمد یا نه. خوش دارم فکر کنم که اینطور نیست.
آنقدر تحت تاثیر قرار گرفته بودم که دیگر به دنبال تغییر کد نبودم و به رئیس بزرگ گفتم که نتوانستم آن را درست کنم. او چندان تعجب نکرد. هنگامی که من آن شرکت را ترک کردم، برنامهٔ بلکجک همچنان هنگام فعال کردن کلید تقلب میکرد، و فکر میکنم این همان چیزی است که باید باشد. هرگز از اینکه کد یک برنامه نویسی حقیقی را هک کردم، احساس خوبی نداشتم.