Coders at Work
Insights from the Minds of Great Software Engineers
توضیحات
کتاب Coders at Work: Reflections on the Craft of Programming نوشتهی Peter Seibel مجموعهای از مصاحبههای عمیق و بلند با ۱۵ تن از برجستهترین برنامهنویسان و دانشمندان کامپیوتر تاریخ است. نویسنده طی دو سال تقریباً ۸۰ ساعت مصاحبه انجام داده و نتیجه، کتابی است که کمتر به فناوری و بیشتر به فلسفه، عادت، و تفکر پشت کدنویسی میپردازد.
مصاحبهشوندگان شامل چهرههایی هستند که تاریخ نرمافزار را شکل دادهاند:
- Donald Knuth — نویسندهی The Art of Computer Programming
- Ken Thompson — خالق Unix و زبان B
- Peter Norvig — Director of Research در Google، نویسندهی AI: A Modern Approach
- Simon Peyton Jones — طراح اصلی زبان Haskell
- Joe Armstrong — خالق زبان Erlang
- Joshua Bloch — طراح Java Collections API، نویسندهی Effective Java
- Jamie Zawinski — توسعهدهندهی Netscape و XEmacs
- Guy Steele — طراح زبان Scheme و مشارکت در Java
- Fran Allen — اولین زن برندهی جایزهی Turing
- و ۶ مصاحبهشوندهی دیگر
نظر
امتیاز: 08/10به دیگران توصیه میکنم: بلهدوباره میخوانم: خیرایده برجسته: بزرگترین برنامهنویسان تاریخ هنوز باprintدیباگ میکنند — این نه نشانهی ضعف بلکه نشانهی تفکر دقیق است؛ ابزار ساده اغلب feedback loop سریعتری دارد. علاوه بر این، تقریباً همه با یک چیز موافقند: خواندن کد دیگران مهارتی است که اکثر توسعهدهندگان از آن فرار میکنند اما بیشترین رشد را میدهدتاثیر در من: احساس imposter syndrome را با دیدن اینکه حتی Donald Knuth و Joe Armstrong هم دربارهی بخشهایی از کارشان احساس ناامنی میکنند، بهتر میتوان مدیریت کرد. همچنین نگاهم به خواندن کد تغییر کرد — documentation میگوید کد چه باید بکند، کد خودش میگوید چه میکند؛ این دو همیشه یکی نیستندنکات مثبت: کیفیت استثنایی سوالات — Peter Seibel برخلاف مصاحبهگران معمول، از پیش تحقیق عمیق انجام داده و سوالات را شخصیسازی کرده؛ امکان مقایسهی دیدگاههای افراد مختلف روی موضوعات مشابه؛ انگیزهبخش بدون شعارزدگی؛ کتاب هیچ فناوری خاصی را تبلیغ نمیکندنکات منفی: برخی فصلها — بهخصوص مصاحبههای مربوط به literate programming و formal proofs — کشش کمتری دارند و پاسخها تکراری میشوند؛ کتاب به سال ۲۰۰۹ تعلق دارد و دنیایی که مصاحبهشوندگان از آن صحبت میکنند گاهی از دنیای امروز (cloud، AI، microservices) فاصله دارد؛ فرمت مصاحبهای باعث میشود نتوان از کتاب یک نتیجهگیری منسجم گرفت
مشخصات
نویسنده: Peter Seibelانتشارات: Apressصفحه مشخصات: codersatwork.com
بخشهایی از کتاب
برنامهنویسی به عنوان یک تلاش نوپای بشری (Programming as a Young Endeavor)
اگر سهم تاریخی Ada Lovelace در قرن نوزدهم (که نخستین الگوریتمها را برای ماشین تحلیلی نیمهکارهی Charles Babbage طراحی کرد) کنار بگذاریم، برنامهنویسی کامپیوتر به عنوان یک تخصص و مجاهدت بشری، قدمتی کمتر از طول عمر یک انسان دارد.
تحلیل تاریخی این تکامل کوتاه را میتوان در چند نقطه عطف کلیدی خلاصه کرد:
۱. ماشین الکترومکانیکی Z3 (سال ۱۹۴۱): نخستین کامپیوتر چندمنظوره و عملیاتی جهان که توسط Konrad Zuse رونمایی شد. این رویداد سرآغاز رسمی ورود ماشینهای محاسباتی برنامهپذیر به جهان واقعی بود.
۲. پروژه ENIAC (سال ۱۹۴۵): اولین کامپیوتر الکترونیکی چندمنظوره که برنامهنویسی عملیاتی آن توسط شش زن بااستعداد صورت گرفت:
- Kay Antonelli
- Jean Bartik
- Betty Holberton
- Marlyn Meltzer
- Frances Spence
- Ruth Teitelbaum
این گروه که پیشتر در ارتش ایالات متحده وظیفه محاسبات دستی جداول بالستیک را بر عهده داشتند و به عنوان computer corps شناخته میشدند، عملاً به نخستین توسعهدهندگان مهندسی نرمافزار بدل شدند.
بخش بزرگی از نسلهای زنده کنونی (از جمله نسل موسوم به Baby Boomers و والدین آنها)، در دنیایی متولد شدهاند که هنوز مفهومی به نام «برنامهنویس کامپیوتر» در آن وجود نداشت. جوانی مفرط این حوزه علمی، ریشه اصلی بسیاری از چالشهای فعلی ما در مدیریت پیچیدگی، فقدان استانداردهای مهندسیِ به بلوغ رسیده و تلاش مستمر ما برای رسیدن به متدولوژیهای پایدار توسعه نرمافزار است. برخلاف رشتههایی نظیر معماری یا عمران که از تجارب مهندسی هزاران ساله بهره میبرند، مهندسی نرمافزار هنوز در مراحل آغازین تکامل اصول خود قرار دارد.
انفجار جمعیت برنامهنویسان و بحران هویت صنعت (The Demographics Boom and Identity Crisis)
امروزه جهان با موج عظیمی از توسعهدهندگان روبرو است. بر اساس آمارهای رسمی، تنها در ایالات متحده در سال ۲۰۰۸، تقریباً از هر ۱۰۶ شاغل، یک نفر به عنوان برنامهنویس یا مهندس نرمافزار (Software Engineer) مشغول به کار بوده است (چیزی بیش از ۱.۲۵ میلیون نفر). این آمار شامل برنامهنویسان خارج از ایالات متحده، دانشجویان، توسعهدهندگان آماتور و افرادی که وظایف ثانویه محاسباتی دارند اما بخش بزرگی از زمان خود را صرف مجبور کردن ماشین به اجرای خواستههایشان میکنند، نمیشود.
با این حال، با وجود میلیاردها خط کدِ نوشتهشده از ابتدای پیدایش این رشته، همچنان این حس قوی وجود دارد که ما در این مسیر، قوانین را در حین حرکت ابداع میکنیم (making it up as we go along). هنوز جامعه علمی و صنعتی بر سر تعریف بنیادین برنامهنویسی توافق نظر ندارد:
- آیا برنامهنویسی بخشی از ریاضیات (Mathematics) است یا مهندسی (Engineering)؟
- آیا یک پیشه تخصصی (Craft)، هنر (Art)، یا یک علم (Science) است؟
این سردرگمی ساختاری خود را در مناقشات شدید پیرامون «بهترین روش توسعه» نشان میدهد؛ بهطوری که بستر اینترنت انباشته از متدولوژیها، زبانهای برنامهنویسی جدید و رویکردهای نوین فکری برای مهار این پیچیدگی است.
فلسفه کتاب: کاوش در ذات برنامهنویسی از طریق گفتگو (The Q&A Tradition)
کتاب پیشرو رویکرد متفاوتی را برای درک ماهیت برنامهنویسی برگزیده است. این روش الهامگرفته از سنت مجله ادبی The Paris Review است که با ارسال مصاحبهکنندگان برای گفتگو با نویسندگانی چون E.M. Forster (که بعداً در کتاب Writers at Work گردآوری شد)، تلاش کرد ذات خلق اثر ادبی را فرموله کند.
این رویکرد متمایز، بر مبنای گفتگو با ۱۵ برنامهنویس برجسته از طیفهای مختلف فناوری شکل گرفته است؛ از هکرهای سیستمهای سطحپایین مانند Ken Thompson (خالق Unix) و Bernie Cosell (از پیادهسازان اولیه ARPANET) تا دانشمندان برجسته دانشگاهی که اعتبار هکری بالایی دارند نظیر Donald Knuth، Guy Steele و Simon Peyton Jones. هدف این مصاحبهها کاوش در چالشهای روزمرهای است که همه برنامهنویسان با آن دستبهگریبان هستند:
- چگونه باید نرمافزار را طراحی کرد؟
- زبانهای برنامهنویسی چه نقشی در افزایش بهرهوری و کاهش خطاها دارند؟
- چگونه میتوان فرآیند یافتن باگهای سخت و پیچیده را تسهیل کرد؟
فصل اول: جیمی زاوینسکی (Jamie Zawinski)
بخش نخست: خاستگاه هک و ورود به دنیای لیسپ (Lisp) در CMU
جیمی زاوینسکی (شناختهشده با نام مستعار jwz)، هکر برجسته لیسپ، توسعهدهنده کلیدی نسخههای اولیه مرورگر Netscape و یکی از محرکهای اصلی پروژه متنباز mozilla.org در کنار برندن آیک (Brendan Eich) است . او برنامهنویسی را از سنین نوجوانی در محیط کار با کامپیوترهای TRS-80 و زبان BASIC آغاز کرد . در آن دوران به دلیل عدم دسترسی به تجهیزات ذخیرهسازی، برنامهها را مستقیماً از روی مجلات تایپ میکرد و حتی کدهای خود را برای زبانهایی مانند APL و Fortran که ابزاری برای اجرای آنها نداشت، روی کاغذ مینوشت .
مسیر ورود زاوینسکی به دنیای مهندسی جدی نرمافزار، از یک ارتباط غیررسمی با گروه کاربران اپل در دانشگاه کارنگی ملون (CMU) شکل گرفت . این ارتباط منجر به استخدام او و دوستش، دن زیگموند (Dan Zigmond)، توسط اسکات فالمن (Scott Fahlman) در آزمایشگاه هوش مصنوعی CMU شد . فالمن این دو نوجوان مشتاق را برای کارهای خدماتی سطح پایین سیستم، نظیر کامپایل مجدد پکیجها به دلیل تغییر مداوم نسخههای کامپایلر، استخدام کرد . این کار ساده اما حیاتی، آنها را در محاصره دانشجویان دکترا و محققان برجسته هوش مصنوعی قرار داد .
زاوینسکی برنامهنویسی واقعی و حرفهای را روی ایستگاههای کاری PERQ (بخشی از پروژه Spice) و با پیادهسازی لیسپ موسوم به Spice Lisp (که بعدها به CMU Common Lisp تبدیل شد) آموخت . او در جلسات هفتگی توسعه نرمافزار شرکت میکرد و مفاهیم طراحی سیستم را با گوش دادن به بحثهای فنی تحلیلگران ارشد فرامیگرفت . یکی از مربیان تأثیرگذار او در این دوران، راب مکلاکلن (Rob MacLachlan) بود؛ مربیای که زاوینسکی سبک بازخورد او را به مکتب ذن (Zen Approach) تشبیه میکند . مکلاکلن بدون سخن گفتن پشت سر او میایستاد، تایپ کردن او را تماشا میکرد و در صورت بروز خطا، با گفتن جمله کوتاه “غلط است!” صحنه را ترک میکرد؛ رفتاری که زاوینسکی را مجبور میکرد ساعتها به تفکر عمیق و مدیتیشن روی منطق کد خود بپردازد .
گذار به دنیای تجاری و همکاری با پیتر نورویگ (Transition to Industry and Working with Peter Norvig)
زاوینسکی پس از اتمام دوران دبیرستان، به دلیل علاقه شدید به هوش مصنوعی و لیسپ، تمایلی به ادامه تحصیل آکادمیک نداشت. با توصیه اسکات فالمن، او در استارتآپ ETI (Expert Technologies) مشغول به کار شد؛ شرکتی که تمرکز آن بر ساخت سیستمهای خبره برای صفحهآرایی خودکار صفحات زرد (Yellow Pages) با استفاده از لیسپ بود. این تجربه به او نشان داد که بقای حرفهای بدون تحصیلات دانشگاهی نیز ممکن است، هرچند ترس از شکست باعث شد برای مدتی کوتاه وارد دانشگاه کارنگی ملون شود که آن را هم به سرعت رها کرد.
نقطه عطف بعدی او، استخدام در دانشگاه برکلی توسط Peter Norvig (دانشمند برجسته هوش مصنوعی) بود. وظیفه زاوینسکی در این پروژه، یکپارچهسازی و کامپایل کدهای پراکنده و بدون ساختاری بود که توسط دانشجویان دکتری رشته زبانشناسی نوشته شده بود. زاوینسکی این کار را بسیار دشوار و فرساینده توصیف میکند؛ زیرا او پسزمینه علمی لازم برای درک مفاهیم پیچیده زبانشناسی ساختاری درون کدها را نداشت. در این دوران، او زمان زیادی را صرف کار روی سیستمهای پنجرهدهی (Window Systems)، دستکاری کدهای UI و خلق اسکرینسیورها برای سرگرمی کرد. نورویگ با درک شرایط، با صبوری علمی با او برخورد میکرد، اما زاوینسکی به دلیل حس عدم بهرهوری و نیاز به کار در محیطی با برنامهنویسان واقعی (نه تئوریسینها)، برکلی را به مقصد شرکت Lucid ترک کرد.
ورود به لوسید و بهینهسازی در سطح هسته (Lucid Common Lisp & Performance Engineering)
شرکت Lucid یکی از دو قطب اصلی توسعه سیستمهای نرمافزاری لیسپ در آن دوران بود. یکی از اولین پروژههای جدی زاوینسکی در لوسید، کار روی یک معماری موازی عجیب ۱۶ پردازندهای (16-processor parallel computer) با نسخهای سفارشی از Lucid Common Lisp بود.
دغدغه اصلی زاوینسکی در این پروژه، کاهش سربار (Overhead) فرآیند ساخت و مدیریت نخها (Thread Spawning) در سطح پایینی ساختار حافظه لیسپ بود. هدف او بهینهسازی مفسر به گونهای بود که حتی اجرای موازی توابع بازگشتی سنگین مانند فیبوناچی، تحت تأثیر هزینه سنگین ایجاد ساختار پشته جدید برای هر نخ (Stack Group Allocation) قرار نگیرد و بازدهی پردازش موازی به حداکثر برسد.
چالشهای مهندسی معکوس و راهاندازی لیسپ (Loader Deciphering & Reverse Engineering)
کار دیگر زاوینسکی در لوسید، انتقال و پورت کردن لیسپ به معماریهای سختافزاری جدید بود. این فرآیند فرساینده شامل مراحل زیر بود: ۱. کامپایل بکاند کامپایلر برای معماری جدید توسط تیم دیگر. ۲. بازنویسی و رمزگشایی فرمت لودر با استفاده از یک برنامه کمکی به زبان C. ۳. لود کردن کدهای باینری به حافظه، تغییر مجوزهای دسترسی صفحه حافظه به حالت قابل اجرا (Executable Page)، و پرش به آدرس شروع برای بالا آوردن پرامپت اولیه لیسپ.
بزرگترین مانع در این مسیر، مستندات فنی اشتباه، قدیمی یا ناقص سختافزارها بود. متدولوژی زاوینسکی برای حل این چالش، مهندسی معکوس مستقیم بود: کامپایل یک برنامه نمونه به زبان C روی سختافزار مقصد، بررسی بایتبهبایت باینری سالم در ادیتور امکس، و مقایسه آن با باینری معیوب. او با تغییر دادن بایتها و مشاهده اثر آن روی رفتار اجرا، ساختار پنهان لودرها را کشف میکرد.
سختترین باگ تاریخ کاری: نبرد با اجرای حدسی و دیباگر GDB
پیچیدهترین باگی که زاوینسکی در دوران کاری خود برطرف کرد، به زمان بوت کردن لیسپ روی یکی از سختافزارهای اولیه دارای فناوری اجرای حدسی (Speculative Execution) مربوط میشود. لیسپ پس از اجرای حدود ۵۰۰ دستورالعمل اسمبلی، به صورت تصادفی کرش میکرد. نکته عجیب این بود که محل کرش در هر بار اجرای خطبهخط (Single-Stepping) تغییر میکرد.
تحلیل زاوینسکی نشان داد که مشکل از کدهای لیسپ نبود، بلکه خطایی در هسته دیباگر GDB وجود داشت:
- پردازندههای مجهز به اجرای حدسی، هر دو مسیر یک دستور شرطی (Branch) را به صورت همزمان اجرا میکردند تا نتیجه شرط مشخص شود.
- دیباگر GDB در هنگام عبور خطبهخط از روی دستورات شرطی، به اشتباه ثباتها را تغییر میداد یا همواره یک مسیر خاص شرط را انتخاب میکرد که منجر به تخریب وضعیت پردازنده (Register Stomping) میشد.
زاوینسکی برای اثبات این فرضیه، متدولوژی دیباگ خود را تغییر داد: به جای استپ کردن مستقیم روی دستور شرطی، نقطه توقف (Breakpoint) را روی هر دو مسیر خروجی شرط قرار داد و دستور اجرای پیوسته (Continue) را صادر کرد. او با این روش وجود باگ در GDB را اثبات کرد، هرچند به دلیل پیچیدگی معماری داخلی GDB، اصلاح نهایی آن در سطح دیباگر عملاً یک هفته زمان برد.
بازنویسی کامپایلر بایتکد و نخستین اصطکاک با ریچارد استالمن (Byte-code Compiler Rewrite & Stallman)
در زمان حضور در شرکت Lucid، تمرکز شرکت به سمت ساخت یک محیط توسعه یکپارچه (IDE) برای زبان C++ به نام Energize معطوف شد . جیمی زاوینسکی در این پروژه وظیفه یکپارچهسازی ویرایشگر متن Emacs با این محیط توسعه را بر عهده داشت .
او پیش از این، پایگاه داده اطلاعات مخاطبین خود موسوم به BBDB (Big Brother Database) را توسعه داده بود که روی امکس اجرا میشد؛ اما سرعت پایین اجرای آن زاوینسکی را به تحلیل عمیق دلایل افت کارایی واداشت . تحلیلهای او نشان داد که ریشه اصلی مشکل در ضعف مفرط کامپایلر بایتکد امکس است . در نتیجه، او تصمیم به بازنویسی کامل کامپایلر بایتکد امکس گرفت .
زاوینسکی در این بازنویسی اصلاحاتی در سطح زبان C انجام داد؛ از جمله اضافه کردن دستورالعملهای جدید به مفسر بایتکد امکس (Byte-code Interpreter) تا سرعت اجرا بهطور چشمگیری افزایش یابد . کامپایلر جدید بهگونهای طراحی شده بود که میتوانست بایتکدهای سازگار با نسخههای قدیمی یا بایتکدهای بهینهشده جدید را تولید کند .
ارائه این بهینهسازی ساختاری، آغازگر اولین رویارویی زاوینسکی با Richard Stallman (بنیانگذار بنیاد نرمافزار آزاد) بود . استالمن در ابتدا با این تغییر مخالفت کرد و گفت: «نیازی به این تغییر نمیبینم» . پاسخ بعدی استالمن این بود: «یک فایل تفاضلی (Diff) از تغییرات بفرست و هر خطی را که تغییر دادهای توضیح بده» . زاوینسکی که کامپایلر را کاملاً از نو نوشته بود، این درخواست را نامعقول دانست و از ارائه آن خودداری کرد . در نهایت، به دلیل استقبال گسترده هزاران کاربر از کامپایلر زاوینسکی و فشارهای مداوم جامعه کاربری، استالمن پس از دو سال مجبور به ادغام این تغییرات در نسخه اصلی امکس شد .
انشعاب بزرگ امکس و شکلگیری XEmacs (The Great Emacs Split)
برخلاف شایعات و باورهای رایج در مورد وجود موانع حقوقی میان شرکت Lucid و بنیاد نرمافزار آزاد (FSF)، زاوینسکی تأکید میکند که حق مالکیت معنوی (Copyright Assignment) تمام کدهای نوشتهشده توسط تیم Lucid بدون وقفه به FSF واگذار میشد . با این حال، به دلیل ناهماهنگیهای اداری در FSF (مانند ادعای مکرر گم شدن مدارک واگذاری مالکیت معنوی از سوی آنها) و کندی شدید در پذیرش وصلههای نرمافزاری، Lucid تصمیم گرفت نسخه اختصاصی خود از امکس را توسعه دهد .
این نسخه در ابتدا Lucid Emacs نام داشت و بعدها به XEmacs تغییر نام داد . تلاش زاوینسکی در توسعه Lucid Emacs بر این فرضیه استوار بود که امکس باید یک پلتفرم قدرتمند شبیه به ماشینهای لیسپ باشد . او برای نیل به این هدف، تغییرات بنیادینی در معماری امکس ایجاد کرد؛ از جمله معرفی Event Objects بهجای نمایش سنتی رویدادها به صورت یک لیست حاوی عدد . با وجود زیبایی طراحی، این تغییرات ساختاری در بلندمدت مشکلات سازگاری (Compatibility Issues) جدی با پکیجهای شخص ثالث امکس ایجاد کرد؛ خطایی تاکتیکی که زاوینسکی بعدها اقرار کرد اگر از ابعاد تخریبی آن آگاه بود، رویکرد متفاوتی را در پیش میگرفت .
گذار به دنیای تجاری Netscape و فلسفه مخالفت با C++
با افول شرکت Lucid و وقوع تعدیل نیروهای گسترده، زاوینسکی از طریق مکاتبه با Marc Andreessen (از توسعهدهندگان مرورگر Mosaic) متوجه تأسیس یک استارتآپ جدید شد و بلافاصله به عنوان یکی از اعضای تیم اولیه توسعه به Netscape پیوست .
در Netscape، زاوینسکی مسئولیت توسعه بخش کلاینت سیستمعامل Unix را بر عهده گرفت . ورود به این پروژه به معنای هجرت از دنیای مجلل لیسپ به دنیای سختگیرانه زبان C بود . او زبان C را به عنوان «اسمبلی پردازنده PDP-11 که تصور میکند یک زبان برنامهنویسی است» توصیف میکند .
با این حال، زاوینسکی موضع بسیار سرسختانهای علیه C++ اتخاذ کرد و آن را یک «افتضاح به تمام معنا» (Abomination) نامید . استدلالهای فنی او علیه استفاده از C++ در مرورگر نتاسکیپ بر چند محور استوار بود:
۱. کاهش کارایی و تورم حافظه (Bloating): کدهای تولیدشده توسط C++ به محض استفاده از کتابخانهها به شدت حجیم میشدند که این امر اجرای برنامه را روی سیستمهای ضعیف آن دوران غیرممکن میساخت .
۲. عدم بلوغ کامپایلرها (Compiler Instability): در اوایل دهه ۹۰ میلادی، کامپایلرهای C++ در پلتفرمهای مختلف فاقد استاندارد یکپارچه و در حال تغییر مداوم بودند که توسعه چندسکویی (Multi-platform) را به کابوس مبدل میکرد . برای مثال، توافق جمعی روی بخشهای امن زبان (مانند Templates) وجود نداشت و پیادهسازی قالبها در کامپایلرهای مختلف رفتارهای متناقضی نشان میداد .
به همین دلیل، تیم اولیه نتاسکیپ توسعه مرورگر را بر پایه ANSI C بنا نهاد . این تصمیم به آنها اجازه داد تا مدیریت حافظه و ماژولار بودن سیستم را بدون هزینههای سربار ساختارهای پیچیده شیءگرایی مدیریت کنند .
فرهنگ مهندسی در نتاسکیپ: مذهبِ ضربالاجل و شتاب توسعه (Netscape Engineering: The Religion of Deadline)
خلق همهچیز از صفر (Blank Slate Development): هسته اولیه نتاسکیپ متشکل از توسعهدهندگان مرورگر NCSA Mosaic بود. با این حال، بر خلاف تصور عمومی و فرآیندهای حقوقی آن زمان، حتی یک خط کد از Mosaic در نتاسکیپ بازاستفاده نشد. تیم توسعه تمایل داشت نسخه دوم را بر پایهای کاملاً جدید بنا کند؛ زیرا معماری Mosaic اساساً ایراداتی مانند عدم امکان بارگذاری موازی تصاویر (Parallel Image Loading) داشت. بنابراین، کار روی هارد دیسکهای کاملاً خالی آغاز شد.
تمرکز مذهبی بر ددلاین (Obsessive Focus on Deadlines): عامل اصلی فرار تیم از «سندرم سیستم دوم» (Second-System Syndrome) در نسخه نخست، تمرکز بیرحمانه روی ضربالاجل ششماهه بود. فلسفه حاکم این بود: «یا تا شش ماه دیگر محصول نهایی را تحویل میدهیم، یا در تلاش برای آن میمیریم». برای تحقق این امر، ویژگیها (Features) به شدت هرس شدند. تیم کلاینت نتاسکیپ که تنها از شش یا هفت نفر تشکیل شده بود، روزهای متوالی را در جلسات طوفان فکری به بحثهای تند پیرامون ویژگیها و خط زدن موارد غیرضروری روی تخته سفید میگذراند. در نهایت، کار به گونهای تقسیم شد که در هیچ بخشی بیش از دو برنامهنویس فعالیت نمیکردند؛ به عنوان نمونه، جیمی زاوینسکی مسئولیت رابط کاربری نسخه یونیکس و لو مونتولی (Lou Montulli) مسئولیت بخش شبکه و بکاند را بر عهده داشتند.
ارتباطات ساینده اما سریع (Abrasive but Fast Communication): فرآیند توسعه نتاسکیپ با ساعات کاری طاقتفرسا (بیش از ۱۶ ساعت در روز) و جو شدیداً اصطکاکی، ساینده و صریح پیش میرفت. زاوینسکی این جو تنشزا را به دلیل افزایش چشمگیر سرعت تصمیمگیریهای فنی، بسیار کارآمد توصیف میکند. توسعهدهندگان بدون تعارف کدهای بد یکدیگر را به شدت و با لحنی تند نقد میکردند و این صراحت لهجه مانع از هدررفت زمان برای رفتارهای ملاحظهکارانه اجتماعی میشد. نتیجه این سرعت سرسامآور، عرضه نسخه بتا و استفاده از محصول توسط دو میلیون کاربر تنها در یک ماه بود؛ موفقیتی چشمگیر که خستگی ناشی از کار ۸۰ ساعته هفتگی را برای آنها توصیفپذیر میکرد.
طراحی سرویس ایمیل نتاسکیپ و فاجعه بازنویسی نسخه ۴.۰ (Netscape Mail Reader & The Version 4.0 Disaster)
معماری و توسعه سرویس ایمیل (Netscape Mail Reader): در نسخه ۲.۰، زاوینسکی با مأموریت طراحی سرویس ایمیل مواجه شد. او و همکار تازه استخدامشدهاش، تری وایزمن (Terry Weissman)، این پروژه را با پویایی متفاوتی نسبت به تنشهای تیم اصلی مرورگر پیش بردند. کار بدون ساختارهای مدیریت سنتی بالا به پایین و بر اساس توافقهای مداوم روی تقسیم ویژگیهای فنی انجام شد. این هماهنگی به قدری بالا بود که نسخه اولیه به سرعت پایدار شد و تمام ویژگیهای باقیمانده به نسخه ۲.۱ (که بعداً به عنوان نسخه پایدار ۳.۰ عرضه شد) منتقل گردید.
تصاحب شرکت Collabra و ورود به سندرم سیستم دوم: نقطه فروپاشی مهندسی نتاسکیپ با تصاحب شرکت Collabra آغاز شد. این شرکت که محصول تحت ویندوز ناموفق و شکستخوردهای در بازار داشت، پس از ادغام، مدیریت کل بخش کلاینت نتاسکیپ را به دست گرفت. تیم جدید تمام تجارب مهندسی و موفقیتهای تیم اولیه را نادیده گرفت و با نادیده گرفتن هشدارهای زاوینسکی و وایزمن، فرآیند بازنویسی کامل نرمافزار را کلید زد؛ تصمیمی که منجر به فاجعه نسخه ۴.۰ شد و در درازمدت سقوط شرکت را رقم زد.
فاجعه بازنویسی با C++ و نخها (The Multiplatform C++ Disaster): تیم مدیریت جدید تصمیم گرفت نسخه ۴.0 را کاملاً با C++ بازنویسی کند. استدلالهای زاوینسکی در مخالفت با این تصمیم محقق شد: ۱. تورم حافظه و افت کارایی: کدهای تولیدشده توسط C++ به دلیل ساختار کتابخانهها به شدت حجیم بودند و روی سیستمهای ضعیفتر (مانند ویندوزهای ۱۶ بیتی) اجرا نمیشدند. ۲. چالشهای جدی چندسکویی (Multiplatform): در آن دوران، توافق جمعی روی بخشهای استاندارد C++ مانند قالبها (Templates) وجود نداشت و کدهای نوشتهشده رفتارهای متناقضی روی کامپایلرهای مختلف نشان میدادند. به دلیل عدم درک توسعه چندسکویی همزمان از سوی تیم جدید (که معتقد بودند ابتدا باید نسخه ویندوز تمام شود و سپس به پلتفرمهای دیگر پورت شود)، نسخههای یونیکس و مک به یک فاجعه ناپایدار تبدیل شدند.
تلاش نافرجام برای بازنویسی با جاوا (The Java Rewrite - Grendel): پروژه بعدی، تلاش برای بازنویسی مرورگر و سرویس ایمیل در زبان جاوا با نام Grendel بود. زاوینسکی و تیم کوچک سهنفرهاش بخش ایمیل را به صورت کاملاً کارآمد و با بهرهگیری بهینه از چندنخی (Multithreading) توسعه دادند؛ به طوری که فرآیندهای نوشتن فایل در پسزمینه بدون هیچگونه وقفهای در UI اجرا میشد. با این حال، پروژه به دلیل مهندسی بیش از حد (Overengineering) در تیم لایه نمایش (Layout Group) به بنبست رسید. توسعهدهندگان لایه نمایش به صورت کاملاً آکادمیک با پروژه برخورد کرده و غرق در طراحی الگوهای طراحی پیچیده، لایههای انتزاعی مکرر، واسطها و نمایندگان بیپایان برای ساختار DOM و DTD شدند؛ امری که مانع از تحویل لایه رندر HTML شد و در نهایت منجر به لغو کامل پروژه گردید.
بدتر همان بهتر است: فلسفه ضدِ مهندسیِ بیش از حد (Worse is Better & Overengineering)
برتری محصول ناقصِ بهموقع بر محصول کاملِ دیرهنگام: زاوینسکی با تکیه بر مفهوم Worse is Better استدلال میکند که ایده ساخت یک فریمورک بینقص که بتواند نرمافزار را از نسخه ۱.۰ تا ۵.۰ بدون مشکل پشتیبانی کند، یک تله مهندسی است. طراحی چنین ساختار ایدهآلی زمان عرضه نسخه ۱.۰ را سالها به تعویق میاندازد، در حالی که رقیب با یک محصول ناقص اما کارآمد در شش ماه بازار را تصاحب میکند. رقیب به دلیل حضور در بازار و کسب درآمد، پتانسیل بازنویسی کدهای ضعیف خود را در آینده خواهد داشت، اما توسعهدهندهای که وسواس کیفیت داشته، اساساً شغلی برای بازنویسی نخواهد داشت. هدف نهایی برنامهنویسی، عرضه محصول مهندسیشده به مشتری است، نه صرفاً نوشتن کدهای زیبا.
محدودیتهای استفاده مجدد از کد (Code Reuse Limitations): زاوینسکی معتقد است گاهی اوقات تلاش برای درک، خطایابی و انطباق با کدهای نوشتهشده توسط دیگران، زمان بیشتری نسبت به بازنویسی کامل آنها از صفر طلب میکند. نوشتن یک بخش از صفر، حتی اگر تنها ۸۰ درصد از ویژگیهای مورد نیاز را پوشش دهد، اغلب رویکردی سریعتر و کارآمدتر برای حفظ کارایی و پایداری سیستم است.
لذت هکِ انفرادی، پورت XScreenSaver و فرار از سیاستهای صنعت (Solo Hacking & The Perfect Program)
جیمی زاوینسکی پس از فرسودگی شدید ناشی از بوروکراسی، نزاعهای مدیریتی در شرکتهای بزرگ و تنشهای فرساینده در دنیای نرمافزار آزاد، تصمیم گرفت از صنعت نرمافزار فاصله بگیرد تا از فرومایگی بحثهای آنلاین بیفایده و تصمیمات اداری ویرانگر که محصولات او را نابود میکردند، خلاص شود . با این حال، او اشتیاق خود را برای توسعه انفرادی در قالب پروژههای سرگرمکننده حفظ کرد .
یکی از نمونههای بارز خلاقیت مهندسی او در این دوره، پورت پروژه قدیمی XScreenSaver به سیستمعامل OS X (مک) بود . متدولوژی فنی او برای حل این چالش، به جای دستکاری مستقیم کدهای تکتک اسکرینسیورها، بازنویسی و پیادهسازی لایه زیرین گرافیکی Xlib بر پایه فریمورک Cocoa در زبان Objective-C بود . این رویکرد به او اجازه داد بدون تغییر در کدهای کلاینتِ اسکرینسیورها، آنها را به راحتی روی بستر بومی مک به اجرا درآورد؛ تجربهای که او آن را به دلیل ترکیبپذیری عالی کدهای C و Objective-C بسیار لذتبخش توصیف میکند .
او اسکرینسیورها را به عنوان «برنامههای بینقص» (The Perfect Programs) تعریف میکند . استدلال او این است که این برنامهها معمولاً از صفر آغاز میشوند، خروجیهای بصری زیبا و جذابی تولید میکنند و برخلاف نرمافزارهای تجاری، هیچگاه به نسخه ۲.۰ نیاز ندارند و کاربران هرگز درخواست ویژگیهای عجیب نظیر «زردتر شدن تصاویر» را برای آنها ارسال نمیکنند . این نبودِ فرآیندهای فرساینده نگهداری (Maintenance) و خطایابی، اسکرینسیورها را به بستری ایدهآل برای حل مسائل هندسی و ریاضیات گرافیکی بدون دغدغههای پسزمینه تبدیل کرده است .
طراحی ارگانیک و متدولوژی تعامل زودهنگام با سیستم (Organic Architecture & Visceral Feedback)
در حوزه معماری و طراحی سیستم، زاوینسکی رویکردی بسیار عملگرا و تکاملی دارد:
طراحی تکاملی تکفایلی (Single-File Prototyping): زاوینسکی در مراحل آغازین توسعه یک نرمافزار جدید، ترجیح میدهد تمام کدهای خود را در یک فایل واحد بنویسد . با رشد کد و عبور آن از مرزهای بحرانی (مثلاً رسیدن به هزار خط)، او شروع به کشف الگوها و رفتارهای مشابه در کد میکند و سپس ماژولها و توابع مستقل را به فایلهای مجزا منتقل میسازد . به باور او، طراحی معماری سیستم یک فرآیند پویا و مداوم است و تا زمان کامل شدن برنامه، ساختار نهایی آن مشخص نخواهد شد .
رسیدن سریع به وضعیت قابل استفاده (Visceral Usability): از دیدگاه او، حیاتیترین گام در مهندسی نرمافزار این است که برنامه در سریعترین زمان ممکن به وضعیتی برسد که خود برنامهنویس بتواند آن را اجرا کرده و خروجی اولیه (حتی در حد یک دکمه روی رابط کاربری) را ببیند . این رویکرد یک بازخورد حسی و ملموس (Visceral Feedback) به توسعهدهنده میدهد که گام بعدی توسعه و اولویت ویژگیهای بعدی را به وضوح مشخص میکند .
شناسایی مرزهای انحراف پروژه (Scope Slippage): او نشانهی خارج شدن پروژه از کنترل را زمانی میداند که تخمین اولیه زمان انجام کار (مثلاً نصف روز) به دلیل وابستگیهای نامشهود پنهان، ناگهان منجر به زنجیرهای طولانی از کارهای پیشنیاز بزرگ و حلنشده شود .
رویکرد عملگرایانه در عیبیابی: افول دیباگرهای نمادین و بازگشت به Print (The Pragmatic Debugging)
دیدگاه زاوینسکی در مورد ابزارهای خطایابی در طول سالهای فعالیتش دچار تحولی بنیادین شده است:
شکست مدلهای پیشرفته در دنیای واقعی: او در دوران طلایی لیسپ، از ابزارهای پیشرفته بازرسی حافظه (Inspectors) و مفسرهای تعاملی بسیار لذت میبرد؛ ابزارهایی که اجازه میدادند در میانه اجرای کد متوقف شده و درخت اشیاء را به صورت گرافیکی پیمایش کند . با این حال، تلاش برای بازآفرینی این تجربه در ابزارهایی مانند دیباگر GDB در دنیای C (به ویژه در پروژه Energize شرکت Lucid) به دلیل ضعفهای ساختاری زبان C و پیچیدگی فرآیندهایی نظیر Casting ارایهها به انواع واقعیشان شکست خورد . زاوینسکی معتقد است نقصهای فنی مکرر دیباگر GDB در مدیریت پشتهها و ثباتها در هنگام جابهجایی بین فریمها، اعتماد برنامهنویس به خروجی دیباگر را سلب میکند .
پرینت به عنوان خط مقدم دیباگ (The Printf Supremacy): در نتیجه این تجارب، زاوینسکی ابزارهای پیچیده دیباگ را کنار گذاشت و به روش کلاسیک و سادهی قرار دادن دستورات چاپ (Print Statements) روی آورد . به ویژه در محیطهای مدرنتر مانند جاوا اسکریپت یا پرل که فاقد دیباگرهای پایدار هستند، تحلیل چشمی کد (Eyeballing) و چاپ مقادیر متغیرها همچنان سریعترین و مطمئنترین راه برای کشف مغایرتها است .
فلسفه مدیریت خطا و تست محصول در شرایط بحرانی (Error Handling & Pragmatic Testing)
مدیریت خطای دفاعی در محیط تولید (Netscape Assert Policy): در پایگاه کد نتاسکیپ، بحثهای طولانی پیرامون نحوه برخورد با شکستِ ارزیابیها (Assertions) در جریان بود. بر خلاف رویکردهای آکادمیک که برنامه را در صورت بروز خطا بلافاصله متوقف میکنند (Fail-Fast)، سیاست مهندسی نتاسکیپ بر این اصل استوار بود: «در صورت شکست ارزیابی، مقدار صفر (یا خطا) را برگردان و امیدوار باش برنامه به کار خود ادامه دهد». استدلال فنی این بود که کرش کردن مرورگر و از دست رفتن دادههای کاربر، پیامدی به مراتب بدتر از نشت حافظه (Memory Leak) یا بازگشت به حلقه اصلی برنامه (Idle Loop) دارد. این نوع مدیریت خطا در زبانهایی مانند جاوا که مجهز به سیستم استثنا (Exception System) هستند، با گرفتن تمام خطاها در بالاترین سطح حلقه اصلی بسیار سادهتر و تمیزتر انجام میشود.
تست واحد و اولویتبندی در شرایط شتاب تجاری (Unit Testing): در دوران توسعه نتاسکیپ، تستهای خودکار توسعهدهنده (Unit Tests) عملاً جایگاهی نداشتند. با این حال، یک استثنای فنی وجود داشت: پارسکننده تاریخ در هدر ایمیلها (Mail Header Date Parser). به دلیل عدم رعایت استانداردها توسط کلاینتهای مختلف ایمیل، هدرها حاوی تاریخهایی با فرمتهای بسیار خراب و آشفته بودند. زاوینسکی مجموعهای عظیم از این تاریخهای معیوب و خروجی عددی مورد انتظار آنها را گردآوری کرد و یک مجموعه تست واحدِ اختصاصی برای آن نوشت تا با هر تغییر در کد پارسر، از عدم پسرفت (Regression) سیستم مطمئن شود.
به جز این مورد، زاوینسکی معتقد است تستهای واحد در پروژههایی با ضربالاجلهای شدید مهندسی، کارایی سیستم را کاهش میدهند. از دیدگاه او، اگر بین عرضه محصول در هفته آینده و نوشتن کدهای بینقص با پوشش تست بالا مجبور به انتخاب باشید، تست واحد اولین چیزی است که باید حذف شود؛ زیرا مشتریان هرگز بابت نبودِ تست واحد شکایت نمیکنند، اما تأخیر در عرضه محصول میتواند بازار را به رقیب واگذار کند. شوخی معروف تیم نتاسکیپ این بود: «ما ۱۰۰٪ به کیفیت متعهدیم؛ ما بالاترین کیفیت ممکن را در تاریخ ۳۱ مارس عرضه خواهیم کرد».
مواجهه با کدهای ارثرسیده و مستندسازی (Legacy Code & Documentation)
استراتژی ورود به کدهای بیگانه: برای درک یک کتابخانه یا پایگاه کد بزرگ که توسط دیگران نوشته شده است، زاوینسکی روش خواندن خطبهخط و ترتیبی را رد میکند. رویکرد عملیاتی او شامل مراحل زیر است: ۱. یافتن یک مأموریت مشخص و کوچک که قصد انجام آن را دارید (مثلاً اضافه کردن یک ویژگی ساده). ۲. بررسی سیستم ساخت پروژه (Build System) برای درک نحوه اتصال ماژولها به یکدیگر. ۳. حرکت از پایینترین لایههای ساختار داده (مانند بررسی ساختار سلولهای Cons در امکس) یا ردیابی مسیر اجرای یک دستور خاص از بالا به پایین در بدنه برنامه.
اصول مستندسازی و کدهای خوانا: مستندسازی توصیفکننده فرضیات پایهای سیستم و ساختارهای داده پیچیده (مانند ساختار هشتجدولهای تودرتو در پرل) بسیار حیاتی است. با این حال، زاوینسکی از کامنتهای بدیهی که صرفاً نام تابع را تکرار میکنند (مثلاً نوشتن کامنتِ
// This pushes to the stackبرای تابعpush_stack) بیزار است. در کدهای C، او اصرار دارد که برای هر فایل.cیک فایل هدر.hدقیق وجود داشته باشد که تمام توابع صادراتی (Exported) در آن تعریف شوند و سایر توابع داخلی به صورتstaticمحدود بمانند تا مرزهای واسط برنامهنویسی (API) کاملاً شفاف حفظ شوند.
ساختار تیمهای مهندسی و مدیریت منابع تخصصی (Engineering Team Structure & Talent)
مقیاسپذیری از طریق تیمهای کوچک: ساختار ایدهآل برای توسعه نرمافزارهای بزرگ، تقسیم پروژه به ماژولهای کاملاً مجزا و مستقل و واگذاری هر ماژول به تیمهای بسیار کوچک (حداکثر ۳ تا ۴ نفر) است. کلید موفقیت این مدل، تعریف واسطهای ارتباطی (Interfaces) فوقالعاده ساده و پایدار بین ماژولهاست تا نیاز به هماهنگیهای مداوم و بحثهای فرساینده بینتیمی به کمترین حد ممکن برسد.
مالکیت کد و توزیع دانش: اگرچه مالکیت اشتراکی کد (Shared Ownership) برای توزیع دانش فنی در تیم و جلوگیری از وابستگی به یک فرد مفید است، اما زاوینسکی معتقد است تخصصگرایی (Specialization) اجتنابناپذیر است. سیستم به افرادی نیاز دارد که روی بخشهای خاصی تمرکز عمیق داشته باشند. علاوه بر این، وجود «یک مسئول مشخص برای هر ماژول» به معنای وجود فردی است که در زمان بنبستهای فنی حرف آخر را بزند و مسئولیت نهایی تصمیمات را بپذیرد.
شناسایی استعدادها و مربیگری (Mentorship): مهمترین ویژگی یک برنامهنویس تازهکار از نظر زاوینسکی، اشتیاق شدید، کنجکاوی برای باز کردن دستگاهها و فهم سازوکار درونی آنها، و عدم هراس از ابراز بیاطلاعی است: «ندانستن چیزی به معنای حماقت نیست، بلکه فقط به این معنی است که هنوز آن را یاد نگرفتهاید». او در مصاحبههای استخدامی، میزان تسلط و اشتیاق داوطلب را با وادار کردن او به دفاع فنی از معماری و الگوریتمهای آخرین پروژهای که انجام داده، ارزیابی میکند.
هویت توسعهدهنده و مهارتهای بنیادین (Developer Identity & Fundamental Skills)
برنامهنویسی: میان هنر و پیشهوری (Craft vs. Art): زاوینسکی خود را نه دانشمند کامپیوتر میداند و نه مهندس؛ زیرا معتقد است این عناوین دارای تعهدات ریاضی و طراحیهای نقشه کشی رسمی هستند که او آنها را انجام نمیدهد. او جایگاه خود را جایی میان یک «پیشهور» (به دلیل ساخت ابزارهای کاربردی و فیزیکی مانند صندلی) و یک «هنرمند» (به دلیل خلق تصاویر پویا و ریاضی در اسکرینسیورها) میبیند.
کتابهای مرجع و آموزش مهندسی: از نظر او، آموزشهای دانشگاهی غالباً به جای آموزش تفکر حل مسئله، روی جزئیات سینتکس و جایگاه ویرگولها تمرکز دارند. او کتاب SICP (Structure and Interpretation of Computer Programs) را به عنوان بهترین منبع برای یادگیری عمیق مفاهیم برنامهنویسی بدون وابستگی به سینتکس یک زبان خاص توصیه میکند. همچنین کتابی از مایکروسافت پیرامون استفاده مؤثر از ارزیابیها (Assertions) را برای یادگیری خطایابی عملیاتی بسیار مفید میداند.
نقش ریاضیات در ذهن برنامهنویس: برخلاف تصور رایج، زاوینسکی تأکید میکند که برای تبدیل شدن به یک توسعهدهنده برجسته، نیازی به ریاضیات پیشرفته دانشگاهی نیست. برای او، برنامهنویسی به نوشتن نثر (Writing Prose) بسیار شبیهتر است تا ریاضیات؛ هر دو به توانایی بیان دقیق یک اندیشه، پرهیز از طولانینویسی و ساختاربندی منطقی نیاز دارند. مهارت ریاضی مورد نیاز در برنامهنویسی، محدود به درک شهودی از مرتبه بزرگی الگوریتمها (Orders of Magnitude)، اصول اولیه ترکیبیات (Combinatorics) و شناسایی الگوها (Pattern Matching) در سطحِ Gut-Level (غریزی) است.
فصل دوم: برد فیتزپاتریک (Brad Fitzpatrick)
بخش نخست: از کلونِ اپل تا امپراتوری تبلیغات کلیکی دبیرستانی (From Apple Clone to High School Ad Clicks)
برد فیتزپاتریک تنها برنامهنویس در میان مصاحبهشوندگان این کتاب است که هرگز دنیای بدون اینترنت یا کامپیوترهای شخصی را تجربه نکرده است . او متولد سال ۱۹۸۰ است و مسیر خود را در سنین بسیار پایین با یکی از عجیبترین شبیهسازهای سختافزاری آغاز کرد .
۱. خاستگاه و یادگیری زودهنگام در سایه سختافزار (The Hardware Shadow & Early Learning)
پدر برد، مهندس الکترونیک در شرکت Mostek بود . او و همسرش ماهها وقت صرف کردند تا قطعات یک کلونِ دستساز Apple II را روی یک برد مدار چاپی به یکدیگر لحیم کنند . چالش اصلی آنها دستیابی به تراشههای حافظه خواندنی (ROM) بود . پدر برد تراشههای معیوب و مرجوعی شرکت را (که به دلیل مشکلات کارخانهای، یک یا چند بیتِ آنها به صورت دائمی در وضعیت بالا (High) یا پایین (Low) قفل شده بود) دریافت میکرد و کدهای سیستمعامل اپل را آنقدر روی این تراشههای سوخته رایت میکرد تا در نهایت به ترکیبی برسد که در آن، بیتهای قفلشده تصادفاً با کدهای باینری بومی سیستمعامل مطابقت داشته باشند . برد از سن دو سالگی بازی با این کامپیوتر دستساز را آغاز کرد .
او برنامهنویسی را در پنجسالگی از پدرش آموخت . مادر برد نقل میکند که او همزمان با خواندن کتاب کودکانه «کلیفورد، سگ بزرگ قرمز»، به مطالعه کتاب مرجع برنامهنویسان اپل میپرداخت و به دلیل سن کم، اصطلاح تخصصی Variables (متغیرها) را Valuables (اشیاء گرانبها) تلفظ میکرد . نخستین خاطره برنامهنویسی او، نوشتن کدهای متداول روی کاغذ در آشپزخانه به همراه پدرش بود:
10 PRINT "HELLO"
20 GOTO 10
او کار خود را با BASIC آغاز کرد اما تا پیش از مهاجرت به زبان C به دلیل محدودیتهای سیستمعامل، امکان دسترسی به مودهای گرافیکی پیشرفته و کنترل ماوس را نداشت . در سنین ۸ تا ۱۰ سالگی، با انتقال پدرش به شرکت Intel برای کمک به طراحی پردازندههای 386 و 486، آنها همواره به جدیدترین سختافزارهای بازار دسترسی داشتند و برد کار با کامپایلر Turbo C را آغاز کرد . نخستین برنامه خلاقانهای که او نوشت، ابزاری روی Apple II بود که الگوهای ترسیمشده در مود گرافیکی پیشرفته را از طریق خواندن بایتهای حافظه فریمبافر، پردازش کرده و دستورات متناظر را برای چاپ روی پرینتر سوزنی Epson صادر میکرد .
۲. مهندسی معکوس کلاینتها و باتهای دوران نوجوانی (Automating Clients & Early Exploits)
مسیر ورود برد به مهندسی شبکههای مدرن با شیطنتهای پروتکلی آغاز شد . او در دوران نوجوانی به دلیل نوشتن باتهای اسپمر، سرازیر کردن ترافیک چترومها (Flooding) و اسکریپتنویسی کلاینت ویندوزی AOL از این سرویس اخراج شد . یکی از معروفترین کارهای او در این دوران، کشف رخنه در فرم آنلاین توزیع دیسکهای رایگان ۱۰۰ ساعته AOL بود .
او یک باتِ اختصاصی طراحی کرد که با دور زدن سیستم فیلترینگ تکرار (Duplicate Suppression) از طریق ایجاد تغییرات جزئی در نام کاربری، این فرم را چندین هزار بار سابمیت کرد . این فرآیند منجر به ارسال انبوهی از کارتنهای حاوی لوحهای فشرده AOL به آدرس پستی خانهاش شد که برد بعدها از آنها به عنوان پوشش تزئینی دیوارهای اتاق خوابگاه خود در دانشگاه استفاده کرد .
۳. کشف دنیای یونیکس و توسعه ابزارهای پویا (Dynamic Web & UNIX Transition)
پس از مسدود شدن حساب کاربری AOL، برد برای اولین بار یک حساب کاربری شل (Shell Account) از یک ارائهدهنده خدمات اینترنت محلی (ISP) دریافت کرد که دریچه ورود او به سیستمعامل Unix بود . در سالهای ۱۹۹۴ و ۱۹۹۵، او به عنوان کارآموز تابستانی در شرکت Tektronix مشغول به کار شد . در نخستین روز کار، او با یک ایستگاه کاری قدرتمند SPARCstation مواجه شد که رابط کاربری Motif و مرورگر Netscape 2 روی آن اجرا میشد .
در این محیط مهندسی، او کدهای اسکریپت CGI را برای اجرای فرآیندهای پویا در وب کشف کرد . او همان شب توانست یک برنامه سه خطیِ “Hello World” مبتنی بر CGI را اجرا کند که این رویداد، اشتیاق او را به توسعه وب پویا شعلهور ساخت .
برد پس از بازگشت به خانه، برنامهنویسی وب را به صورت جدی ادامه داد . او اسکریپتی به نام Voting Booth نوشت که به کاربران اجازه میداد نظرسنجی ایجاد کرده و به گزینهها رای مثبت دهند . این ابزار پس از مدتی به شدت محبوب شد و ترافیک سرور میزبان را به شدت تحت تأثیر قرار داد .
او نام این سرویس را به FreeVote تغییر داد . در آن دوران که مدلهای کسبوکار وب بر پایه تبلیغات بنری کلیکی در اوج خود بودند، FreeVote ترافیک فوقالعادهای جذب کرد؛ به طوری که برد در دوران دبیرستان، قراردادی منعقد کرد که به ازای هر کلیک روی بنرهای تبلیغاتی، ۲۷ سنت دریافت میکرد . این سیستم درآمدی در بالاترین حد خود، ماهانه بین ۲۵,۰۰۰ تا ۲۷,۰۰۰ دلار برای یک دانشآموز دبیرستانی سودآوری داشت . در نهایت، او در سال نخست دانشگاه، برای خلاص شدن از شر مسئولیتهای حقوقی و فنی نگهداری این سرورها، FreeVote را به قیمت ناچیز ۱۱,۰۰۰ دلار به یکی از دوستانش فروخت تا تمام تمرکز خود را روی پروژه جدیدش یعنی LiveJournal بگذارد .
مقیاسپذیری توزیعشده LiveJournal و معماری لایههای زیرساخت
توسعه و رشد سرسامآور پلتفرم LiveJournal، برد فیتزپاتریک را در سنین جوانی با چالشهای ترابرد ترافیک و مقیاسپذیری سیستمهای وب مواجه کرد. این تجربه عملی منجر به ابداع معماریها و ابزارهایی شد که امروزه شالوده بسیاری از وبسایتهای بزرگ جهان را تشکیل میدهند.
۱. گذار از CGI سنتی به FastCGI و جداسازی لایهها
پلتفرم LiveJournal در ابتدا روی یک سرور یونیکس اشتراکی (Shared UNIX Box) و به صورت اسکریپتهای سنتی CGI اجرا میشد . در این مدل سنتی، به ازای هر درخواست کاربر، سیستمعامل یک فرآیند کاملاً جدید ایجاد (Fork) و پس از پاسخ آن را نابود میکرد که این امر سربار پردازشی عظیمی به سیستم تحمیل کرده و سرور میزبان را به زانو درآورد .
فرآیند بهینهسازی سیستم توسط برد طی مراحل زیر پیش رفت:
- انتقال به FastCGI: برد با هدف حذف سربار ناشی از فرآیندِ مداومِ Fork کردن، سیستم را به پروتکل FastCGI منتقل کرد تا فرآیندهای مفسر برای پاسخدهی به درخواستهای بعدی در حافظه زنده بمانند .
- بهینهسازی وبسرور: تنظیم دقیق پارامترهای سرور Apache و غیرفعال کردن فرآیند زمانبرِ جستجوی معکوس دیاناس (Reverse DNS Lookups) برای هر کانکشن ورودی .
- جداسازی فیزیکی لایهها (Separation of Concerns): پس از جذب اولین کمکهای مالی مردمی از کاربران (حدود ۶ تا ۷ هزار دلار)، دو سرور فیزیکی ۶U تهیه شد . برد لایه وب (اجرای پروسسهای Apache) را از لایه ذخیرهسازی داده (پروسس MySQL) تفکیک کرد و ارتباط بین آنها را از طریق یک کابل کراساور شبکهای مستقیم برقرار ساخت .
۲. بنبست دیتابیس و کشف مستقل معماری شاردینگ (Database Sharding)
با افزایش ترافیک، لایه وب به راحتی و به صورت افقی با اضافه کردن سرورهای ارزانقیمت ۱U مقیاسپذیر شد؛ زیرا سرورهای وب کاملاً بدون وضعیت (Stateless) بودند . اما لایه پایگاه داده (MySQL) به سرعت دچار بنبست فیزیکی شدید در پهنای باند دیسک و پردازنده (I/O & CPU Bound) گردید . بهینهسازی کوئریها و ایندکسها تنها برای چند هفته مهلت خرید و مشکل اصلی پابرجا بود .
برد بدون آگاهی از تئوریهای تئوریک توزیع داده، به صورت کاملاً مستقل راهکار شاردینگ (Sharding) یا پارتیشنبندی پایگاه داده را طراحی و پیادهسازی کرد :
- توزیع افقی بر اساس شناسه کاربری (User ID): دیتابیس اصلی (Master) تنها برای نگهداری متادیتاهای جهانی کمترافیک حفظ شد و تمام دادههای مربوط به وبلاگها و کامنتها به کلاستری از پایگاههای داده مجزا منتقل شدند؛ به طوری که موقعیت هر کاربر بر اساس شناسه کاربریاش روی یک پارتیشن خاص تعیین میشد .
- پروتکل مهاجرت آنلاین (Live Zero-Downtime Migration): انتقال دادههای کاربران به کلاستر جدید در حین سرویسدهی فعال، چالش بزرگ بعدی بود . سیستم مهاجرت به این صورت طراحی شد که یک فلگ مشخصکننده شماره کلاستر برای هر کاربر تعریف گردید . در زمان انتقال داده، اکانت کاربر موقتاً قفل میشد تا جلوی نوشتن جدید (Write Mutation) گرفته شود . پس از کپی کامل دادهها به شارد جدید و تأیید عدم بروز ناسازگاری، سیستم جهتِ ارجاع را تغییر میداد (Pivot) و قفل اکانت باز میشد . این فرآیند دو ماه به طول انجامید اما مانع از خوابیدن یکهفتهای سایت برای این جابهجایی عظیم شد .
۳. ایده درخشان در حمام و تولد Memcached
خرید، پیکربندی و کالیبره کردن سرورهای دیتابیس جدید بسیار پرهزینه و زمانبر بود . برد یک روز در حمام متوجه شد که کلاستر سرورهای وب ارزانقیمت آنها حجم بسیار زیادی از حافظه رم بلااستفاده و خالی دارند . او همان شب پروتکل و نمونه اولیه ابزار Memcached را در زبان Perl نوشت .
- محدودیت کارایی پرل و بازنویسی به C: نمونه اولیه مبتنی بر Perl به دلیل تحمیل بار پردازشی شدید به پردازنده (CPU overhead) برای مدیریت اتصالات همزمان سقوط کرد . در نتیجه، برد هسته Memcached را کاملاً به زبان C بازنویسی کرد تا با مدیریت بهینه حافظه و سرعت بالا به کش توزیعشده دادهها بپردازد .
- اصل انتزاع کامل سیستمهای زیرساخت: یکی از مهمترین اصول مهندسی برد، توسعه زیرساختهای ماژولار و مستقل بود . در آن دوران شرکت او (Danga Interactive) در حال توسعه موازی یک سیستم مدیریت تصویر به نام FotoBilder بود . او تمام ابزارهای مقیاسپذیری از جمله Memcached، سیستمفایل توزیعشده MogileFS و لودبالانسر Perlbal را به صورت کاملاً انتزاعی و عاری از هرگونه وابستگی به LiveJournal طراحی کرد تا به راحتی در هر پروژه توزیعشده دیگری قابل استفاده باشند .
فلسفه تستنویسی، نگهداری بلندمدت و لذت بهینهسازی (Testing, Maintenance, & Optimization)
اصل بقای همیشگی کد و مالکیت ابدی آن: برد فیتزپاتریک معتقد است کدهایی که یک برنامهنویس مینویسد، هرگز از بین نمیروند و نویسنده آن برای تمام عمر به عنوان نگهدارنده (Maintainer) آن کد باقی خواهد ماند . او به طور مکرر بازخوردهایی درباره باگهای کدهایی دریافت میکند که بیش از ده سال پیش نوشته و در اینترنت رها کرده است . این تجربه به او آموخت که فرار از نگهداری کدهای قدیمی عملاً غیرممکن است .
مخالفت با هوشمندیهای پنهان (Cleverness) بدون پوشش تست: یکی از قواعد کلیدی فیتزپاتریک این است که هرگاه کدی با پیادهسازی هوشمندانه، پیچیده یا خاص مینویسد، فرض را بر این میگذارد که توسعهدهندگان بعدی فرضیات پایدار و ساختار داده او را درک نخواهند کرد . در نتیجه، برای این بخشها تستهای واحد ویژهای طراحی میکند که در صورت دستکاری اشتباه، با سر و صدای زیاد شکست بخورند (break loudly) و خطا را اعلام کنند . او نوشتن تست را به تمام برنامهنویسان خود تکلیف میکرد؛ چرا که اثبات کارکرد کد با تست، هزینههای نگهداری سیستم در آینده را به شدت کاهش میدهد .
بهینهسازی به عنوان یک رقابت و سرگرمی (Optimization as a Contest): از نظر فیتزپاتریک، بهینهسازی لذتبخشترین بخش برنامهنویسی است، زیرا زمانی به سراغ آن میروید که سیستم در وضعیت پایدار و کاملاً کارآمد قرار دارد و فشار ضربالاجلها برداشته شده است . او در دوران توسعه LiveJournal، بخشهای گلوگاهی سیستم (مانند ماژول پارس کردن هدرها در لودبالانسر) را به عنوان مسابقه بهینهسازی بین همکارانش مطرح میکرد تا با طراحی عبارات منظم (Regular Expressions) کارآمدتر و بدون بازگشت به عقب (Backtracking)، سرعت سیستم را ارتقا دهند؛ رقابتی که در نهایت با بازنویسی کامل آن بخش به زبان C توسط یکی از مهندسان پایان یافت .
کالبدشکافی کدهای بیگانه و متدولوژی خواندن سیستمهای بزرگ (Reading Legacy & Large-scale Codebases)
غلبه بر ترس از کدهای دیگران: فیتزپاتریک در سالهای نخست فعالیت خود صرفاً کدهای خودش را مینوشت و از ورود به کدهای بیگانه هراس داشت؛ زیرا تصور میکرد برای تغییر یک سیستم، باید کل معماری آن از ابتدا در ذهن برنامهنویس وجود داشته باشد . اما با ارسال اولین پچهای اصلاحی به پروژه Gaim (یک کلاینت پیامرسان متنباز تحت GTK)، او متوجه شد کدهای بیرونی نیز از الگوهای طراحی مشخصی پیروی میکنند و پس از درک این الگوها، خواندن کدهای دیگران برای او به ابزاری جذاب جهت کشف متدهای خلاقانه مهندسی تبدیل شد .
پروتکل عملیاتی برای مواجهه با کدهای غولپیکر (Wandering Aimlessly): او پروژههای عظیمی مانند اندروید، کروم و فایرفاکس را صرفاً برای ارضای کنجکاوی مهندسی مطالعه کرده است . فرآیند گامبهگام او برای کالبدشکافی کدهای بزرگ شامل مراحل زیر است:
- غلبه بر سد بیلد (Build Hurdle): دریافت سورسکد خام و تلاش برای کامپایل و بیلد موفقیتآمیز آن روی ماشین محلی؛ این مرحله معمولاً به دلیل وابستگیهای پیچیده سیستمهای ساخت، بزرگترین مانع برای توسعهدهندگان است .
- درک ساختار دایرکتوریها: هدایت خروجی دستور
findبه ابزارlessبرای اسکن چشمی ساختار کلی پوشهها و فایلها . - ورود تصادفی و گشتوگذار: باز کردن یک فایل تصادفی برای درک اتمسفر و سبک کدنویسی پروژه، و سپس چرخیدن هدفمند در کد بر اساس متدهایی که جلب توجه میکنند .
طراحی API، ابزارهای دیباگ سیستمی و درک کل پشته (API Design, Debugging, & Full-Stack Mastery)
طراحی نرمافزار بر پایه اینترفیسها و سند spec.txt: متدولوژی طراحی فیتزپاتریک، متمرکز بر واسطهای ارتباطی است . او کار خود را با نوشتن یک فایل متنی ساده به نام
spec.txtآغاز میکند و در آن به طراحی اینترفیسها، متدهای مشترک، فراخوانیهای RPC و چگونگی کوئریها میپردازد . اگر پروژه با دیتابیس سرکار داشته باشد، ابتدا چیدمان فیزیکی داده روی دیسک، لایه پایگاه داده و ایندکسهای مورد نیاز برای رایجترین کوئریها را طراحی کرده، سپس کدهای ساختگی (Mocks) را برای بخشهای مختلف پیادهسازی میکند تا به مرور زمان بدنه اصلی نرمافزار تکمیل شود . توصیه او به برنامهنویسان خودآموز، تلاش مداوم برای انجام کارهای سختتر و خارج از محدوده راحتیشان است .ضرورت درک کل پشته (Understanding the Whole Stack): فیتزپاتریک به شدت با رویکرد برنامهنویسانی که تنها به یک زبان سطح بالا (مانند Java) تسلط دارند و به انتزاعهای فریمورکها ایمان کورکورانه دارند، مخالفت میکند . استدلال فنی او این است که در دنیای واقعی، ابزارها و لایههای انتزاعی بسیار ضعیف پیادهسازی شدهاند و اگر برنامهنویس مسئول هزینه سرورها یا پایداری لایه تولید باشد، باید دقیقاً بداند زیر پوست سیستم (در سطح هسته سیستمعامل، فراخوانیهای سیستمی نظیر epoll، یا وقایع کارت شبکه) چه میگذرد .
سروری به نام strace به عنوان ابزار نهایی دیباگ: در جعبه ابزار خطایابی فیتزپاتریک، دستورات ساده چاپ مقدار متغیرها، دیباگرهای نمادین مانند GDB (که در گوگل به عنوان ابزاری irreplaceable به خوبی نگهداری میشود) و به ویژه ابزار strace جایگاه اصلی را دارند . او تأکید میکند که زندگی بدون strace برای او غیرممکن است؛ زیرا هر زمان که رفتار برنامهای نامشخص باشد، آن را تحت strace اجرا میکند تا تعامل دقیق آن با هسته سیستمعامل و فراخوانیهای سیستمی را بدون واسطه مشاهده کند .
قوانین استایلکد گوگل و مدیریت مخزن بومی (Google Style Guidelines & Monolithic Repository)
انضباط سختگیرانه در نگارش کد (Strict Coding Standards): برد فیتزپاتریک پس از ورود به گوگل، با فرهنگِ شدیداً قانونمندی در زمینه استایلکد مواجه شد . در گوگل برای ۶ یا ۷ زبان اصلی، دستورالعملهای نگارشی بسیار دقیقی وجود دارد که جزئیاتی مانند نحوه فاصلهگذاری، تورفتگیها، نامگذاری متغیرها، و حتی شیوه تعریف یک فیلد استاتیک را فرموله کرده است . فیتزپاتریک که پیش از آن در دنیای منعطف پرل (Perl) فعال بود، به اهمیت این موضوع پی برد؛ زیرا در پروژههای بزرگ، هماهنگی و یکپارچگی ظاهری کد در کل پایگاه کد، بر سلیقه شخصی توسعهدهنده اولویت دارد . او اکنون در هر پروژه جدید، اولین گام را تعریف یک استایلکد مشخص میداند .
مالکیت اشتراکی و ساختار مخزن یکپارچه (Monolithic Repository & Ownership): گوگل از یک درخت منبع واحد (One Massive Source Tree) و یک سیستم ساخت یکپارچه استفاده میکند که به هر برنامهنویسی اجازه میدهد کدهای هر بخشی از سیستم را تغییر دهد . با این حال، این آزادی عمل با دو لایه نظارتی کنترل میشود: ۱. بازبینی کد (Code Reviews): هیچ کدی بدون بازبینی و تأیید ثبت نمیشود . ۲. مالکیت دایرکتوری (Directory Owners): هر دایرکتوری حداقل دو مالک دارد که مسئول نهایی تأیید تغییرات در آن بخش هستند . ۳. گواهی خوانایی (Readability Certification): برای اعمال تغییر در یک زبان خاص، برنامهنویس باید تأییدیه رسمی خوانایی (مثلاً خوانایی در C++ یا Python) را از افراد مجرب آن زبان در شرکت دریافت کرده باشد تا تضمین شود کدهای جدید منطبق بر استانداردهای ساختاری شرکت هستند .
بازنویسی Memcached در گوگل و مدیریت حافظه (Memcached C++ Rewrite & Memory Management)
کنترل دقیق بر تخصیص حافظه (Exclusive Memory Control): در جریان توسعه زیرساختهای سرویس Google App Engine، فیتزپاتریک تصمیم گرفت ابزار محبوب خود، Memcached، را برای انطباق با زیرساختهای امنیتی و عملیاتی گوگل بازنویسی کند . اگرچه نسخه اصلی Memcached به زبان C نوشته شده بود، اما او نسخه جدید را کاملاً با C++ توسعه داد . دلیل اصلی این تصمیم فنی، نیاز به کنترل انحصاری بر لایه حافظه جهت جلوگیری از پدیده تکهتکهشدن حافظه (Memory Fragmentation) در فرآیندهای طولانیمدت سیستم بود . استفاده از ساختارهایی نظیر
scoped_pointerدر C++ به او اجازه داد تا بدون نیاز به استفاده مستقیم از کلمات کلیدیnewوdelete، از مدیریت ایمن حافظه بهرهمند شود .کاهش حجم کد در بازنویسی دوم (The Second-Time Advantage): نسخه بازنویسیشده Memcached به زبان C++، تقریباً با نیمی از حجم کد نسخه اولیه ساخته شد . فیتزپاتریک این کاهش چشمگیر در تعداد خطوط کد را صرفاً به ویژگیهای زبان C++ نسبت نمیدهد؛ بلکه آن را ناشی از قانون «توسعه مجدد» میداند: بار دومی که یک ابزار را طراحی میکنید، به دلیل اشراف کامل بر تمام زوایا و گوشههای مسئله، کدی به مراتب تمیزتر، خلاصهتر و کارآمدتر تولید خواهید کرد .
معماریهای توزیعشده و دیباگ در سطح سیستمعامل (Distributed Architectures & System Debugging)
الگوریتم حضور در شبکههای توزیعشده (Presence Discovery): تفکر توزیعشده فیتزپاتریک در جلسه مصاحبه فنی او در گوگل به چالش کشیده شد . مسئله مطرحشده این بود: «فرض کنید چندین سرور روی یک سوییچ شبکه قرار دارند و همزمان روشن میشوند؛ الگوریتمی طراحی کنید که هر ماشین بدون تحمیل بار سنگین به شبکه، وضعیت خاموش یا روشن بودن سایر ماشینها را کشف کند» . او با تحلیل مکانیزمهای پخش همگانی (Broadcast) و ارسال مستقیم بر اساس آدرسهای MAC، استراتژیهایی را برای به حداقل رساندن پهنای باند مصرفی و تاخیر کشف خرابی (Failure Detection Latency) در مقیاسهای بزرگ ارائه داد .
تحلیل رفتار سیستم از طریق strace: در جعبه ابزار دیباگ فیتزپاتریک، ابزار strace جایگاهی حیاتی دارد؛ به طوری که او حیات حرفهای خود را بدون آن غیرممکن میداند . هرگاه رفتار برنامهای مبهم باشد یا تعامل آن با لایه شبکه و دیسک دچار مشکل شود، او برنامه را تحت strace اجرا میکند تا دقیقاً فراخوانیهای سیستمیِ صادرشده به سمت هسته سیستمعامل را رصد کند . او همچنین ابزار GDB را که در گوگل به خوبی پشتیبانی میشود، در کنار ابزارهای تحلیل حافظه و پروفایلینگ مانند Valgrind و Callgrind برای بهینهسازی کدهای C++ ضروری میداند .
انتزاعهای مدرن و آموزش مهندسی (Modern Abstractions & Self-Discipline)
گوگل اپ انجین به عنوان بیسیکِ این نسل (App Engine as BASIC): از نظر فیتزپاتریک، پلتفرمهایی نظیر Google App Engine همان نقشی را برای نسل جدید برنامهنویسان ایفا میکنند که زبان BASIC در دهه ۸۰ میلادی ایفا میکرد . در گذشته، برنامهها به صورت محلی و تککاربره اجرا میشدند؛ اما امروزه تمام برنامهها ماهیت شبکهای دارند . سیستمهای ابری با حذف لایههای پیچیده پیکربندی سرور، تنظیمات شبکه و دیتابیس، به توسعهدهندگان جوان اجازه میدهند با نوشتن کدهای ساده پایتون و فشردن یک دکمه، محصول خود را مستقیماً در شبکه جهانی مستقر کنند .
مخالفت با ایمان کورکورانه به انتزاعها (Blind Faith in Abstractions): با وجود تایید کارآمدی ابزارهای ابری، فیتزپاتریک به شدت از برنامهنویسانی که بدون درک لایههای زیرین به انتزاعهای فریمورکها (مانند ماشین مجازی جاوا یا لایههای انتزاعی دیتابیس) تکیه میکنند، انتقاد میکند . برای مثال، برنامهنویسان جاوا به دلیل ترس از کرش کردن JVM، از استفاده از واسط برنامه بومی (JNI) اجتناب میکنند که این امر منجر به بازنویسیهای مکرر و بیهوده کدهای پایدار C++ به جاوا میشود .
توسعه مهارت شخصی از طریق انتخاب آگاهانه مسیرهای سخت (Deliberate Difficulty): متدولوژی فیتزپاتریک برای به بلوغ رساندن مهارتهای شخصی، نوشتن برنامهها با زبانهایی است که در آنها مهارت کافی ندارد یا برای آن کار ایده آل نیستند . به عنوان نمونه، او در گوگل بارها کارهای یکبارمصرف خود را به جای پرل با پایتون نوشت تا به این زبان مسلط شود؛ همچنین لودبالانسر معروف Perlbal را در ابتدا به زبان C# نوشت تا ساختارهای برنامهنویسی شیءگرای مایکروسافت را در عمل یاد بگیرد .
مدیریت منابع انسانی و روانشناسی تیمهای فنی (Engineering HR & Motivations)
تفکیک برنامهنویسان خودگردان از کارمندان وظیفهمحور: یکی از بزرگترین چالشهای فیتزپاتریک در زمان انتقال از هک انفرادی به مدیریت شرکت Danga Interactive، مدیریت منابع انسانی بود . او در ابتدا تصور میکرد همه برنامهنویسان مانند خودش خودگردان (Self-driven) هستند و نیازی به مدیریت ندارند . اما در عمل متوجه شد برخی افراد فاقد اشتیاق برای تعالی علمی هستند و صرفاً وظایف محوله را بدون خلاقیت انجام میدهند .
برخورد با برنامهنویسان سنتگرا (Artisan Programmers): او در تیم خود با برنامهنویسانی مواجه شد که به شدت روی استایل و معماریهای انتزاعی خود تعصب داشتند (برنامهنویسان هنرمند یا Artisan) . کدهای این افراد بسیار زیبا و انتزاعی بود اما در عمل سرعت پایینی داشت یا اصلاً اجرا نمیشد . فیتزپاتریک با این چالش مواجه بود که چگونه این افراد را به سمت حل مسائل واقعی لایه تولید سوق دهد .
بهرهگیری از مهارت نمونهسازی (Prototyping Talent): او متوجه شد که برنامهنویسان مهارتهای متفاوتی دارند؛ برخی در نگارش کدهای تولیدی دقیق تخصص دارند و برخی دیگر در هک سریع و راهاندازی نسخههای اولیه (Tinkering) فوقالعاده هستند . برای مثال، او یکی از کارمندانش را که کدهای پرل و C کثیفی مینوشت اما در برقراری ارتباط سریع بین قطعات سختافزاری و نرمافزارهای مختلف (مانند راهاندازی پل صوتی برای LiveJournal) نبوغ داشت، در جایگاه مسئول ساخت پروتوتایپها قرار داد و کدهای او را پس از تایید کارکرد اولیه، توسط مهندسان دیگر بازنویسی و بهینهسازی میکرد .
فصل سوم: داگلاس کراکفورد (Douglas Crockford)
بخش نخست: خاستگاه رسانهای، دوران کارتهای پانچ و کالبدشکافی ساختار درونی سیستمها
۱. ورود تصادفی به دنیای محاسبات از بستر رسانه (The Fluke Entry: From Television to Fortran)
داگلاس کراکفورد مسیر برنامهنویسی خود را به شکلی کاملاً تصادفی آغاز کرد . او در ابتدا با هدف تحصیل در رشته پخش تلویزیونی وارد دانشگاه ایالتی سانفرانسیسکو (SFSU) شد . در سال نخست تحصیل (سالهای ۱۹۷۱-۱۹۷۲)، به دلیل عدم امکان دسترسی به استودیوی تلویزیونی برای دانشجویان سال اول، او برای پر کردن واحدهای خود در یک کلاس زبان Fortran در دپارتمان ریاضی ثبتنام کرد . کشف استعداد بالا در حل مسائل برنامهنویسی، او را به ادامه این مسیر و گذراندن دوره ترم دوم ترغیب نمود .
شرایط یادگیری و معماری محیط محاسباتی او در آن سالها دارای ویژگیهای فنی خاصی بود:
- کارتهای پانچ در زیرزمین کتابخانه: برنامهنویسی در آن دوران از طریق ابزارهای فیزیکی مانند کارتهای پانچ و سیستمهای اشتراک زمانی (Timesharing) نوپا انجام میشد .
- توزیع نامتمرکز سیستمها: برخلاف دانشگاههای بزرگ که دارای دپارتمان مهندسی متمرکز و کنترلکننده تمام منابع پردازشی بودند، در دانشگاه سانفرانسیسکو کامپیوترها در سراسر محیط آموزشی توزیع شده بودند . دانشکدههای علوم طبیعی، بازرگانی، علوم تربیتی و علوم انسانی هرکدام آزمایشگاههای مستقل خود را داشتند . این گستردگی ساختاری به کراکفورد اجازه داد تا از همان ابتدا تعامل فرهنگها و دیسیپلینهای مختلف با کامپیوتر را خارج از چارچوب خشک مهندسی مشاهده کند .
۲. مهندسی معکوس و یادگیری خودآموز (Self-Teaching through Disassembly)
نخستین برنامه جدی و خلاقانهای که کراکفورد به یاد میآورد، ابزاری برای دیساسمبل کردن (Disassembler) سیستم زمان اجرای (Runtime) کامپایلر Fortran روی ماشین اشتراک زمانی بود . در آن دوران، کدهای منبع و مستندات سیستمها عموماً منتشر نمیشدند . رویکرد تاکتیکی کراکفورد برای یادگیری عمیق، خواندن مستقیم کدهای ماشین سیستم پس از دیساسمبل کردن آنها بود . این تجربه به او تفکر حل مسئله در پلتفرمهای بدون سند (Undocumented Systems) را آموخت و او را با نحوه تعامل سطح پایین نرمافزار با لایه انتزاع زمان اجرا آشنا کرد .
۳. تحول مفهوم کارایی و تاثیر قانون مور (The Evolution of Efficiency & Moore’s Law)
کراکفورد تفاوت بنیادین در رویکرد برنامهنویسان نسبت به کارایی را در دو دوران تاریخی تحلیل میکند:
- دهه اول فعالیت (دهه ۷۰ و اوایل ۸۰): به دلیل محدودیت شدید سختافزارها در دوران ریزپردازندههای اولیه (حافظههای به شدت کوچک و پردازندههای کند)، بهینهسازی و کارایی (Efficiency) در اولویت مطلق بود . توسعهدهندگان ناچار بودند برای ساخت بازیها یا برنامههای صوتی و تصویری مستقیماً به زبان اسمبلی متوسل شوند تا برنامه در محدودیتهای حافظه جا شود و با سرعت قابل قبول اجرا گردد .
- دوران مدرن (اجرای جاوااسکریپت در مرورگر): امروزه نرمافزارهای عظیم در بستر مرورگر با جاوااسکریپت اجرا میشوند . مرورگر نسبت به سیستمهای قدیمی یک محیط فوقالعاده ناکارآمد (Profoundly Inefficient) به شمار میرود، اما قانون مور (Moore’s Law) با جبران این ناکارآمدیها از طریق بهبود مستمر توان سختافزاری، اجرای این نرمافزارها را بدون نیاز به بهینهسازیهای شدید سطح پایین میسر ساخته است .
۴. مسیر شغلی اولیه: از مؤسسه تحقیقاتی SRI تا شرکت Basic Four
کراکفورد تحصیلات دانشگاهی خود را در رشته پخش رسانهای به پایان رساند و پس از یک سال حضور در دوره کارشناسی ارشد فناوری آموزشی (که آن را به دلیل عقب بودن سرفصلها از دانش شخصیاش رها کرد)، به عنوان پژوهشگر در مؤسسه تحقیقاتی معتبر SRI در منلو پارک مشغول به کار شد .
او سپس به شرکت Basic Four پیوست که در زمینه ساخت مینیکامپیوترهای تجاری برای کسبوکارهای کوچک فعالیت میکرد :
- توسعه واژهپرداز سیستمی: او در این شرکت یک سیستم واژهپرداز بومی توسعه داد .
- تلاش برای تغییر فرهنگ سازمانی: با معرفی رایانههای شخصی (PC) به بازار، کراکفورد پتانسیل انقلاب پردازش شخصی را درک کرد و تلاش نمود شرکت را به این سمت سوق دهد . او اولین کامپیوتر شخصی IBM را خریداری کرد و آن را روی میز خود قرار داد تا مهندسان شرکت ساختار سختافزاری و دستاوردهای IBM را از نزدیک بررسی کنند . با این حال، به دلیل رسوخ عمیق فرهنگ سنتی در Basic Four، او موفق به تغییر استراتژی شرکت نشد و در نهایت آنجا را ترک کرد .
دوران آتاری و پیوند هنر بازی با رسانه (The Atari Era & Games as Media)
خرید آتاری ۸۰۰ و محدودیتهای پردازنده ۶۵۰۲:
کراکفورد در کریسمس سال ۱۹۸۱ یک کامپیوتر Atari 800 را به دلیل جذابیت ساختاری بیشتر نسبت به Apple II خریداری کرد. نیت اولیه او، توسعه یک سیستم واژهپرداز یا طراحی یک زبان برنامهنویسی روی این سختافزار بود؛ اما معماری پردازنده MOS 6502 توانایی و ویژگیهای لازم برای پردازشهای متنی و سیستمی سنگین را نداشت. این محدودیت سختافزاری قاطع، او را به سمت دنیای بازیهای کامپیوتری سوق داد. او نخستین بازی خود را به شرکت آتاری فروخت و متعاقب آن، پیشنهاد کار در آزمایشگاه تحقیقاتی آتاری در سانیویل را دریافت کرد. این آزمایشگاه پیشرفته، همان مرکزی بود که Alan Kay پس از خروج از Xerox PARC تأسیس کرده بود و کراکفورد به مدت دو سال در آن به همکاری با مهندسان برجسته پرداخت.بازی به عنوان بستر تلاقی رسانهای:
جذابیت اصلی بازیهای کامپیوتری برای کراکفورد در این بود که بازی، نخستین حوزه تلاقی مستقیم فناوری تلویزیون (به عنوان یک رسانه تصویرمحور عمومی) با محاسبات کامپیوتری به شمار میرفت. این حوزه، اولین بستری بود که به عموم مردم اجازه میداد به جای تماشای غیرفعال، به صورت پویا و تعاملی در خروجیهای بصری کامپیوتر مشارکت کنند.
تجربه لوکاسفیلم و تولد پروژه هبیتات (Lucasfilm & The Genesis of Habitat)
حضور در لوکاسفیلم و ابداع دنیای مجازی:
کراکفورد پس از فروپاشی آتاری، به مدت هشت سال در شرکت لوکاسفیلم فعالیت کرد. در این دوران، دوست او Chip Morningstar پروژه انقلابی Habitat را کلید زد؛ پروژهای پیشگام که برای نخستین بار در تاریخ محاسبات، مفاهیمی چون آواتار (Avatar) و جهان مجازی گرافیکی (Graphical Virtual World) را اختراع و پیادهسازی کرد.محدودیتهای زیرساختی هبیتات:
نکته برجسته در مهندسی هبیتات، اجرای موفقیتآمیز یک پلتفرم گرافیکی توزیعشده بر روی کلاینتهای به شدت ضعیف Commodore 64 و بسترهای شبکهای غیر اوج X.25 بود. کراکفورد که خود به عنوان ناظر و مشوق پروژه حضور داشت، طراحی هوشمندانه و پیشبینیهای دقیق فنی Morningstar را در بهینهسازی این پروتکلهای ارتباطی توزیعشده ستایش میکند.
تأسیس شرکت Electric Communities و معماری غیرمتمرکز (Decentralization & Electric Communities)
گذار به بازارهای آنلاین:
موفقیتهای تئوریک هبیتات منجر به این شد که Chip Morningstar و Randy Farmer شرکت لوکاسفیلم را با هدف تأسیس American Information Exchange ترک کنند. فرضیه کار بر این بود که ایده سرورهای اجتماعی هبیتات به بستری برای بازارهای آنلاین تبدیل شود؛ سیستمی که به باور کراکفورد، در صورت توسعه در زمانی مناسبتر، پتانسیل تبدیل شدن به ساختاری شبیه به eBay را داشت.معماری توزیعشده بدون سرور واحد (Fully Distributed Platform):
پروژه بعدی آنها، تأسیس شرکت Electric Communities با هدف خلق یک پلتفرم جهانی توزیعشده بود که ابعاد سرگرمی، روابط اجتماعی و مبادلات تجاری را یکپارچه سازد. معماری این پلتفرم بر خلاف متدولوژیهای سنتی کلاینت-سرور، به صورت کاملاً توزیعشده طراحی شد تا دادهها و پیامها بدون نیاز به یک سرور مرکزی، در سراسر شبکه جریان یابند. این ساختار نیازمند مدلهای امنیتی فوقالعاده پیشرفته برای تضمین بقای پلتفرم در یک محیط کاملاً غیرمتمرکز بود.
سیر تکاملی زبانهای امن: از Joule تا زبان اسکریپتی E (The Evolution of Secure Languages)
چالشهای زبان Joule:
پلتفرم غیرمتمرکز Electric Communities برای اجرا نیازمند یک زبان برنامهنویسی به شدت ایمن بود. تلاش اول آنها به استفاده از زبان Joule معطوف شد؛ زبانی مبتنی بر مدل اکتور (Actor-based Language) که توسط شرکت Agorics توسعه مییافت. Joule از نظر تئوریک درخشان اما بسیار غیرمتداول و پیچیده بود، به طوری که ریسک عدم پذیرش آن از سوی جامعه برنامهنویسان تجاری بسیار بالا ارزیابی شد.تولد زبان E بر پایه جاوا:
برای مهار این پیچیدگی، تیم تصمیم گرفت مفاهیم بنیادین اکتور در Joule را استخراج کرده و آنها را به عنوان افزونهای بر بستر زبان جاوا پیادهسازی کند که منجر به شکلگیری نسخه اولیه زبان E شد. پس از مواجهه با چالشهای حقوقی و فنی با شرکت Sun Microsystems بر سر تغییر در ساختار جاوا، تیم در نهایت یک زبان اسکریپتنویسی سبکتر و ایمن با نام E را طراحی کرد که بعدها به عنوان یک پروژه متنباز مستقل به حیات خود ادامه داد.
کشف مفهوم Closure در جاوااسکریپت و تحول برنامهنویسی وب (The Discovery of JavaScript Closures)
آموزش تفکر کلوژرمحور:
بزرگترین دستاورد حضور کراکفورد در Electric Communities، یادگیری عمیق تفکر مبتنی بر Closures بود. این بکگراند ذهنی به او اجازه داد تا هنگام ورود به دنیای وب و بررسی زبان نوپای جاوااسکریپت، ساختارهای متفاوتی را در آن کشف کند.کشف تصادفی کلوژرها در زبان جاوااسکریپت:
بخش بزرگی از وراثت جاوااسکریپت به زبان Scheme (یک گویش از Lisp) بازمیگشت؛ اما مستندات رسمی آن زمان هیچ اشارهای به وجود مفهوم Closure در زبان نداشتند. کراکفورد به صورت تصادفی وجود کلوژرها را در موتور جاوااسکریپت کشف کرد. این کشف به او ثابت کرد که این زبان که در آن زمان به عنوان یک ابزار تفننی و ساده انگاشته میشد، در واقع یک زبان قدرتمند با قابلیتهای مهندسی بالا است. او تلاشهای خود را برای ترویج این ویژگی و متقاعد کردن جامعه مهندسی نرمافزار به پتانسیلهای پنهان جاوااسکریپت آغاز کرد.
بحران امنیت در وب و وابستگی آسیبرسان به شیء سراسری (The Broken Web Security & Global Object Dependence)
بزرگترین و مهلکترین ضعف معماری جاوااسکریپت، وابستگی مطلق آن به یک شیء سراسری (Global Object) است . این زبان فاقد لینکرهایی است که بتوانند بخشهای مختلف کد را از یکدیگر مجزا کنند؛ همچنین هیچ مکانیزم بومی برای پنهانسازی اطلاعات (Information Hiding) میان واحدهای کامپایل وجود ندارد و تمام قطعات کد پس از بارگذاری، درون یک شیء سراسری مشترک تخلیه میشوند . در این مدل معماری:
- تمامی کامپوننتهای موجود در صفحه به کل ساختار سیستم دسترسی دارند .
- مرز امنیتی میان کدهای توسعهدهنده اصلی و کدهای شخص ثالث وجود ندارد و هر دو به یک اندازه به شبکه و مدل شیءگرای سند (DOM) دسترسی دارند .
- در صورت تزریق حتی یک اسکریپت مخرب به صفحه، آن اسکریپت میتواند خود را به عنوان اسکریپت معتبر به سرور معرفی کند و سرور عملاً هیچ راهی برای تشخیص هویت واقعی فرستنده درخواست ندارد .
- تمامی تدابیر ضد فیشینگ (Anti-phishing) مرورگرها در سطح لایه کاربری (Chrome) در این سناریو بیاثر میشوند؛ زیرا اسکریپت مخرب با همان سطح دسترسی و اختیارات اسکریپت اصلی اجرا میگردد .
این شکنندگی امنیتی در معماری وب به دلیل همزیستی و تداخل چندین زبان ناهمگون (مانند HTTP ،HTML ،CSS، ساختار URLها و زبان اسکریپتنویسی) تشدید شده است . هر یک از این زبانها قواعد متفاوتی برای خنثیسازی کاراکترها (Escaping)، نقلقولها (Quoting) و یادداشتنویسی (Commenting) دارند که به صورت یکپارچه استانداردسازی نشدهاند و در مرورگرهای مختلف رفتارهای متناقضی نشان میدهند . این آشفتگی، بستر را برای حملات Cross-Site Scripting (XSS) به شدت هموار میسازد .
ظهور پدیده Mash-ups (ترکیب کامپوننتهای توزیعشده از پلتفرمهای مختلف مانند گوگل و یاهو در یک صفحه واحد وب) اگرچه به عنوان یک نوآوری در بازاستفاده نرمافزاری شناخته میشود، اما در عمل به صورت پیشفرض و آگاهانه منجر به ایجاد رخنههای XSS میگردد؛ چرا که مدل امنیتی مرورگرهای فعلی اساساً مفهومی به نام «همکاری همراه با سوءظن متقابل» (Cooperation with Mutual Suspicion) را پشتیبانی نمیکند و امنیت وب بر پایهای از تصادفات و اشتباهات تاریخی بنا شده است .
تقلیلگرایی ساختاری: بهینهسازی زبان از طریق کوچکسازی (Subsetting & Language Simplification)
یکی از اصول کلیدی مدیریت پیچیدگی در سیستمهای نرمافزاری، محدود کردن زبان به بخشهای امن و کارآمد آن است . هزینه تغییر در یک زبان برنامهنویسی مستقیماً با میزان موفقیت و فراگیری آن رابطه مستقیم دارد؛ هرچه یک زبان محبوبتر شود، هزینه آموزش مجدد جامعه توسعهدهندگان و ریسک شکست سیستمهای موجود افزایش مییابد و آزادی عمل طراحان برای اعمال تغییرات بنیادی سلب میشود .
جاوااسکریپت به صورت کاملاً تصادفی و غیرمنتظره به محبوبترین زبان برنامهنویسی جهان تبدیل شد ؛ اما ورود شتابزده آن به بازار و استانداردسازی زودهنگام باعث شد بخش زیادی از عیوب ساختاری آن به جای اینکه خطای پیادهسازی باشند، در قالب مشخصات فنی سند استاندارد (Specification) منجمد شوند . علاوه بر این، در بستر وب توسعهدهنده برخلاف سیستمهای دسکتاپ یا سرور، اختیاری در انتخاب کامپایلر یا موتور زمان اجرا (Runtime) ندارد و نرمافزار او باید روی تمام مرورگرهای موجود با تمامی باگهای اصلاحنشده کاربران قدیمی بدون مشکل اجرا شود .
برای برونرفت از این بنبست، رویکردهای زیر پیشنهاد میشود: ۱. ایجاد زیرمجموعههای امن (Safe Subsets): فریمورکهایی مانند ADsafe با حذف دسترسی به اشیاء سراسری و بخشهای خطرناک زبان، یک زیرمجموعه امن اما همچنان قدرتمند بر پایه توانمندی Lambda ایجاد میکنند . ۲. مخالفت با پیچیدگی بیش از حد (ES4 vs. ES3.1): تلاشهای اولیه برای تدوین نسخه ۴ استاندارد ECMAScript به دلیل حجم عظیم امکانات تستنشده و مهندسی بیش از حد، عملاً یک انحراف از مسیر حل مسائل واقعی وب بود . در مقابل، تمرکز بر نسخه ۳.۱ (که بعدها به ES5 تغییر نام داد) به عنوان رویکردی گامبهگام و مهارکننده معرفی شد . ۳. کوچکسازی استانداردها: بهترین راه برای بهبود جاوااسکریپت، CSS ،HTML و پروتکل HTTP، حذف ویژگیهای کمارزش و تمرکز مجدد بر بخشهایی است که کارکرد درخشانی از خود نشان دادهاند، نه انباشتن مکرر ویژگیهای جدید بر روی ساختارهای ناپایدار قبلی .
اشیاء نرم و پارادایم انضباط فردی در محیطهای پویا (Soft Objects & Self-Discipline)
در زبانهای کلاسیک شیءگرا، ساختار و رفتار برنامهها توسط سیستم سختگیرانه کلاسها تعیین میشود ؛ اما جاوااسکریپت از مفهوم «اشیاء نرم» (Soft Objects) بهره میبرد . در این پارادایم، کلاس صلب وجود ندارد و هر شیء دقیقاً همان چیزی است که توسعهدهنده در همان لحظه تعریف میکند . این انعطافپذیری فوقالعاده بالا، فرآیند مهندسی مجدد (Refactoring) را در مقایسه با سلسلهمراتب کلاسهای عمیق و ایستا در زبانهایی مانند جاوا، به شدت ساده و روان میسازد .
با این حال، این ویژگی پویا میتواند به شدت خطرناک باشد و ساختار کد را در زمان اجرا غیرقابلپیشبینی کند . راهکار مقابله با این شکنندگی، تزریق انضباط شخصی شدید از سوی توسعهدهنده به فرآیند برنامهنویسی است :
- در زبانهای ایستا، کامپایلر انضباط ساختاری را به برنامهنویس دیکته میکند؛ اما در جاوااسکریپت، برنامهنویس خود باید این نظم و Rigor را به پایگاه کد وارد سازد .
- استفاده از ابزارهای تحلیل ایستای کد مانند JSLint برای جبران نبود سختگیریهای ذاتی زبان و تضمین پایداری کدهای بزرگ مقیاس کاملاً حیاتی است .
- اتخاذ دیسیپلینهای شخصی (نظیر ممنوعیت استفاده از دستورالعمل
continueیا خودداری از تکیه بر ویژگی درج خودکار سمیکولن مرورگرها از طریق رعایت دقیق استایل K&R) مانع از بروز رفتارهای مبهم در موتور مفسر میشود .
ابداع JSON: غلبه بر پیچیدگی پروتکلهای تبادل داده (JSON: The Victorious Accident)
ابداع فرمت تبادل داده JSON نمونه بارزی از غلبه سادگی بر استانداردهای پیچیده صنعتی است . در دورانی که پروتکل XML به عنوان فرمت استاندارد تبادل داده پیشنهاد شده بود، کراکفورد آن را برای انتقال اطلاعات در بستر شبکه بیش از حد سنگین و پیچیده دانست .
طراحی JSON بر مبنای حذف کامل سربارهای ساختاری و تمرکز بر سادهترین روش ممکن برای نمایش دادهها شکل گرفت . پذیرش همگانی JSON توسط جامعه توسعهدهندگان در برنامههای مبتنی بر Ajax و سایر حوزهها ثابت کرد که جامعه مهندسی نرمافزار در صورت ارائه یک راهکار کارآمد و ساده، پتانسیل توافق بر روی یک ساختار بهینه را دارد .
متدولوژی خواندن و پالایش کد تیمی در یاهو (Code Reading in Yahoo)
کراکفورد بر این باور است که خواندن جمعی کد (Code Reading)، کارآمدترین سنتی است که یک تیم مهندسی نرمافزار میتواند به آن متعهد باشد . متدولوژی او برای برگزاری جلسات بازخوانی تیمی به شرح زیر است:
- مکانیزم اجرا: تیم دور یک میز جمع میشوند، نسخهای از کد روی صفحه بزرگ نمایش داده میشود و به ازای هر نفر یک نسخه کاغذی چاپشده توزیع میگردد . نویسنده کد موظف است خطبهخط کد را با صدای بلند بخواند و منطق و فرضیات پشتیبان آن را برای تیم تشریح کند .
- مزیت معماری و ادغام: این فرآیند به کل تیم کمک میکند تا درک کنند ماژولهای مختلف چگونه قرار است با یکدیگر یکپارچه شوند . همچنین این چالش برطرف میشود که برنامهنویسان به مرور زمان فرضیات و کامنتهای اشتباه یا منسوخ خود را نادیده میگیرند؛ در حالی که خوانندگان جدید فوراً این مغایرتها را کشف میکنند .
- تقویت تخصص تیمی: این جلسات مانع از بروز پدیده «مهندسان ایزوله» میشود که کدهای غیرقابلفهم تولید میکنند، و به توزیع یکنواخت دانش در کل سازمان کمک شایانی میکند .
شبیخون به کدهای بیگانه: پالایش مکانیکی به عنوان ابزار درک معماری (Refactoring through Cleaning)
استراتژی کراکفورد برای مواجهه با کدهای ناآشنا یا به ارثرسیده (Legacy Code)، فرآیندی کاملاً فعال و فیزیکی است:
- پالایش تایپوگرافیکی اول خط: او کدهای بیگانه را فوراً درون ادیتور ریخته و شروع به اصلاح دستی فاصلهها، تورفتگیها و علائم نگارشی میکند تا با استایل ذهنی او همخوانی داشته باشند . او فرآیند بازسازی خودکار توسط ابزارها را رد میکند؛ زیرا پاکسازی دستی برنامهنویس را مجبور میسازد بایتبهبایت با بدنه کد درگیر شود و فرضیات نویسنده اصلی را کشف کند .
- کد کثیف، تفکر کثیف است: کراکفورد معتقد است غیرممکن است بتوان کدی بسیار کارآمد و پایدار را با ظاهری آشفته و شلخته نوشت . از دیدگاه او، خوانایی کد (Readability) اولویت نخست سیستم است؛ زیرا خوانا بودن کد، تنها مسیر مطمئن برای تضمین صحت علمی (Correctness) آن در بلندمدت است .
- حذف بهینهسازیهای زودرس: او با برنامهنویسانی که بدون داشتن دادههای پروفایلینگ دقیق، بخشهایی از سیستم را به بهای کاهش شدید خوانایی بهینهسازی میکنند، به شدت مخالفت میکند . از نظر او، این کار صرفاً نویز و پیچیدگی (Cruft) بیدلیل به سیستم اضافه میکند .
- ساماندهی ترتیبی و حذف ابهام: او کد را بهگونهای بازآرایی میکند که تمام توابع و متغیرها پیش از فراخوانی تعریف شده باشند (حذف کامل ارجاعات رو به جلو یا Forward References) . همچنین، او به شدت با دستور
continueمخالف است و در دیسیپلین شخصی خود هرگز از آن استفاده نمیکند؛ زیرا معتقد است هر ساختاری که حاویcontinueباشد را میتوان با بازنویسی و فاکتورگیری مجدد به ساختاری بسیار تمیزتر تبدیل کرد .
مدیریت ناهمگامی و دفاع از سیستم تکنخی در مرورگر (Concurrency & Single-threaded Browser)
دیدگاه معماری کراکفورد در حوزه همروندی (Concurrency)، مبتنی بر پرهیز حداکثری از پیچیدگی نخها است:
- نخها به مثابه یک کابوس مهندسی: او نخها (Threads) را یک مدل برنامهنویسی به شدت فاجعهبار و ضعیف میداند . پیچیدهترین باگهای دوران کاری او مربوط به مسائل بیدرنگ (Real-time) و تداخل چندنخی در سیستمهای سنتی بوده است .
- مزیت موتور تکنخی مرورگر: یکی از درخشانترین ویژگیهای محیط مرورگر این است که اجرای جاوااسکریپت در آن به صورت تکنخی (Single-threaded) و مبتنی بر رویداد (Event-based) است . این ساختار عملاً کلاس بزرگی از خطارهای همروندی مانند بنبستها (Deadlocks) و شرایط رقابتی (Race Conditions) را در سطح کدنویسی کاربر حذف میکند .
- الگوی فرآیند ایزوله: او الگوی پیادهسازیشده در Google Gears (فرآیندهای کاملاً مجزا و بدون حافظه مشترک که تنها از طریق ارسال پیام و رویداد با یکدیگر ارتباط برقرار میکنند) را برترین مدل برای اجرای پردازشهای سنگین پسزمینه میداند؛ رویکردی که امروزه به عنوان Web Workers شناخته میشود .
معیارهای استخدام فرامدرن: از ترجیح فارغالتحصیلان ادبیات تا آزمون خوانش کد (Hiring Criteria)
روشهای متداول مصاحبه فنی (مانند حل پازلها یا سوالات تئوریک تریویا) از نظر کراکفورد کاملاً بیفایده و ناکارآمد هستند . رویکرد او برای سنجش عیار مهندسان ارشد به این شرح است:
- دفاع از کد بومی: داوطلب باید قطعه کدی را که خودش نوشته و به آن افتخار میکند به جلسه بیاورد و آن را در قالب یک جلسه بازخوانی کد برای مصاحبهکنندگان تشریح و از تصمیمات معماری آن دفاع کند . این کار صحت ادعای مالکیت کد و توانایی بیانی کاندیدا را آشکار میسازد .
- اولویت مهارت نگارش بر ریاضیات: اگرچه او تلاش داشت آشنایی با آثار دونالد کنوت (Donald Knuth) را به عنوان یکی از شروط استخدام قرار دهد، اما به دلیل کمبود نامزدهایی که این آثار را خوانده باشند ناچار به عقبنشینی شد . با این حال، او اصرار دارد که مهندسان نرمافزار باید مهارت فوقالعادهای در نگارش به زبان طبیعی خود (برای نوشتن مستندات، ایمیلها و طرحهای فنی) داشته باشند . کراکفورد صراحتاً اعلام میکند که استخدام فارغالتحصیلان رشتههای ادبیات (مانند English Majors) را به فارغالتحصیلان ریاضی ترجیح میدهد؛ زیرا برنامهنویسی در اصل هنر برقراری ارتباط با انسانها از طریق نثر مکتوب است .
سواد برنامهنویسی (Literate Programming): کد به مثابه یک اثر ادبی مکتوب
کراکفورد ایده Literate Programming (مفهوم ابداعشده توسط دونالد کنوت) را یک شاهکار تئوریک میداند :
- طراحی برای خواننده، نه کامپایلر: در این پارادایم، اولویت اصلی برنامهنویس، چیدمانِ توضیحات و بخشهای کد به ترتیب منطقی و روایی برای درک ذهن خواننده است، نه ترتیبی که کامپایلر دیکته میکند . ابزارهای این حوزه وظیفه توزیع کدهای تکهتکه شده به آدرسهای واقعیشان در لایه کامپایل را بر عهده دارند .
- رهایی از محدودیت ابعاد توابع: در زبانهای سنتی، برنامهنویس ناچار است توابع بزرگی را که انسجام معنایی بالایی دارند، صرفاً برای جا شدن روی صفحه مانیتور، به توابع کوچکتر و بیهویت تقسیم کند که منجر به تولید کدهای مزاحم و بیثمر میشود . در سوادبرنامهنویسی، میتوان کدهای بزرگ را با برچسبهای توصیفی خوانا دستهبندی کرد و ساختار تابع را تمیز نگه داشت .
- کد به عنوان پاسخ، مستندات به عنوان مسئله: او کدهای خام را صرفاً پاسخی برای یک مسئله میداند . بدون وجود مستندات و تشریح فرضیات (که در سوادبرنامهنویسی به صورت موازی با کد نگاشته میشوند)، خواننده ناچار است صورتِ مسئله را از روی پاسخ حدس بزند که این امر منشأ خطاهای بزرگی در نگهداری سیستم است . او به مسیر تاریخی ادزار دیکسترا (Edsger Dijkstra) اشاره میکند که در انتهای فعالیتهای خود، برنامههایی کاملاً ادبی مینوشت که حتی نیازی به اجرا روی ماشین نداشتند .
فصل چهارم: برندن آیک (Brendan Eich)
بخش نخست: تلاقی نظریه و عمل، هک هسته در SGI و پیشزمینه مهندسی مفسرها
۱. خاستگاه آکادمیک و گسست از فیزیک نظری (Academic Origin & Departure from Theoretical Physics)
برندن آیک مسیر علمی خود را به عنوان دانشجوی فیزیک در دانشگاه سانتا کلارا (Santa Clara University) در اواخر دهه ۷۰ و اوایل دهه ۸۰ میلادی آغاز کرد. در آن دوران، دسترسی او به سیستمهای محاسباتی بزرگ از طریق اتصال به سیستمهای اشتراک زمانی DEC TOPS-20 (سیستمهای معروف LOTS-A و LOTS-B در دانشگاه استنفورد و سیستم محلی دانشگاه سانتا کلارا) میسر شد. آیک بر روی این پردازندههای ۳۶ بیتی مجهز به اسمبلر ماکروی قدرتمند، برنامهنویسی را تجربه کرد؛ محیطی که به دلیل وجود قابلیتهای غنی سیستمی مانند نگاشت حافظه برای ورودی/خروجی (Memory-mapped I/O)، پویایی بالایی داشت.
با وجود علاقه اولیه به فیزیک، آیک به دو دلیل عمده به سمت ریاضیات و علوم کامپیوتر متمایل شد:
- رکود در فیزیک نظری: او فیزیک زمان خود را حوزهای رو به افول و متوقفشده میدید که برای اثبات فرضیات بزرگ خود ناچار به خلق مفاهیم ابطالناپذیر (Unfalsifiable) مانند انرژی تاریک شده بود. در مقابل، علوم کامپیوتر و منطق ریاضی بستر پویایی از نظریات استقرایی محکم را ارائه میدادند که مستقیماً به خروجیهای ملموس ترجمه میشدند.
- جذابیت نظریه کامپایلرها: کشف پیوند عمیق میان تئوریهای انتزاعی و رفتارهای عملی (به ویژه در لایه لغتسنجی و تحلیل نحوی در فرآیند ساخت فرانتاند کامپایلرها، نظریه اتوماتا و زبانهای صوری) اشتیاق او را به این رشته دوچندان کرد. در آن سالها رقابت شدیدی برای ساخت بهترین تولیدکنندههای پارسر پایین به بالا (Bottom-up Parser Generators مانند ابزار yacc) در جریان بود و آیک کمال تئوریک این مفاهیم ریاضی را در قالب کدهای فوقالعاده تمیز مهندسی دنبال میکرد.
۲. نخستین تجربههای هک و مهندسی بازیها (First Hack Experiences & Game Engineering)
آیک در دوران تحصیل خود، با دور زدن درسهای سنتی مهندسی، از کار با کارتهای پانچ و زبان Fortran عبور کرد و مستقیماً وارد دنیای Pascal، زبان C و اسمبلی شد. نخستین برنامههای غیردمو و جدی او، پیادهسازی نسخههای کلون بازیهای معروفی چون Pac-Man و Donkey Kong بر روی ترمینالهای گرافیکیِ بسیار ضعیف شرکت DEC (VT100) بود.
این شبیهسازها به زبان Pascal نوشته شده بودند و خروجیهای گرافیکی را با فرستادن کدهای گریز (Escape Sequences) به ترمینال شبیهسازی میکردند. طراحی این بازیها نخستین مأموریت مهندسی جدی آیک برای تفکر عمیق پیرامون اصول ماژولار بودن نرمافزار، مدیریت وضعیت بازی و محافظت از پایداری کد در برابر رفتارهای پیشبینینشده سیستم بود.
۳. دوران تحصیل در UIUC و سرخوردگی از پروژههای شرکتی (The UIUC Era & Corporate Frustration)
آیک برای گذراندن دوره کارشناسی ارشد خود به دانشگاه ایلینوی در اربانا-شمپین (UIUC) رفت. با این حال، تجربه او در دانشگاه با ورود به پروژهای بزرگ که توسط شرکت IBM مصادره شده بود، به سرخوردگی مهندسی انجامید.
در این پروژه، دانشگاه یک سختافزار مبتنی بر پردازنده Motorola 68020 از شرکتی در کنتیکت خریداری کرده بود تا سیستمعامل Xenix را روی آن اجرا کند. این سیستم به قدری ناپایدار و پر از باگ بود که کل تیم تحقیقاتی دانشگاه عملاً به یک گروه تضمین کیفیت (QA Group) برای عیبیابی کدهای ضعیف تبدیل شد. این رویکرد غیرعلمی و بوروکراسی شرکتی، آیک را متقاعد کرد که مسیر آکادمیک دکترا را رها کند. پس از شنیدن سخنرانی جیم کلارک (Jim Clark، بنیانگذار SGI) در دانشگاه، آیک تصمیم گرفت مستقیماً وارد صنعت شود و به شرکت Silicon Graphics (SGI) بپیوندد.
۴. سالهای حضور در SGI و مهار چالشهای سطح پایین سیستم (SGI Years & Kernel Hacking)
آیک از سال ۱۹۸۵ تا ۱۹۹۲ به مدت هفت سال در SGI مشغول به کار شد و تمرکز خود را بر توسعه هسته سیستمعامل (Kernel) و پیادهسازی لایههای شبکه متمرکز ساخت:
- کدنویسی چابک در لایه تولید: آیک هسته سیستمعامل را مأمن «برنامهنویسان واقعی» میدانست؛ محیطی سختگیرانه که به دلیل استفاده از جدولهای تخصیص حافظه با اندازه ثابت (Fixed-size Tables) و لزوم پایداری مطلق، مجالی برای مهندسی بیش از حد و کدهای ضعیف باقی نمیگذاشت. او به شدت با لایههای انتزاعی مکرر و بیهوده اواخر دهه ۹۰ (مانند معماریهای CORBA و COM که برای چاپ یک “Hello World” ساده صدها هزار فراخوانی متد صادر میکردند) مرزبندی داشت و صیانت از کارایی حافظه را اصل نخست مهندسی میدانست.
- توسعه مفسرهای کارآمد در لایه شبکه: او در SGI یک سیستم مدیریت شبکه و لایه شنود بسته (Packet-sniffing) توسعه داد. در این پروژه، او یک زبان عبارات سفارشی برای تطبیق فیلدها در بستههای شبکه نوشت و کامپایلری طراحی کرد که این عبارات را به فیلترهای بهینهشده ماسکگذاری و انطباق بر روی ۳۶ بایت نخست بسته تبدیل میکرد. او همچنین کامپایلر دیگری نوشت که توصیفات پروتکلهای پیچیده (نظیر ساختارهای متغیر و آرایههای تودرتو در پروتکل AppleTalk) را دریافت کرده و مستقیماً کدهای C متناظر را تولید میکرد.
- پرش به MicroUnity و مواجهه با کامپایلر GCC: در سال ۱۹۹۲، آیک به دلیل حجیم شدن شرکت SGI و نفوذ تصمیمگیران اداری، شرکت را به مقصد استارتآپ فناوری پردازندههای رسانهای MicroUnity ترک کرد. در این شرکت نوپا، او مستقیماً با پایگاه کد کامپایلر GCC درگیر شد و مهارتهای خود را در خط فرمان کامپایلرها ارتقا داد. او همچنین یک زبان شبهمشخصات اختصاصی برای تولید خودکار جریانهای بیتی ویدئویی استاندارد MPEG2 نوشت تا کارکرد درست سختافزارها را بررسی کند.
زایش شتابزده جاوااسکریپت و تصمیمات بنیادین طراحی (The 10-Day Genesis & Core Design Decisions)
۱. فشار تجاری و تله همزیستی با جاوا (Java’s Dumb Brother)
ایده اولیه برندن آیک برای نتاسکیپ، پیادهسازی زبان Scheme درون مرورگر بود . با این حال، به دلیل رقابت شدید تجاری و توافق نتاسکیپ با شرکت Sun Microsystems، مدیریت ارشد اصرار داشت که زبان جدید باید از نظر ظاهری شباهت کاملی به Java داشته باشد . این فشار مدیریتی مانع از آن شد که آیک بتواند یک هسته Scheme استاندارد را برداشته و صرفاً یک پوسته نحوی (Syntax) شبیه به C روی آن بکشد؛ در نتیجه، او مجبور شد کل مفسر و ساختار زبان را ظرف مدت ۱۰ روز به صورت مستقل از نو بنویسد .
در تفکر سنتی مدیریت نتاسکیپ، کارهای مهندسی و محاسباتی سنگین باید توسط جاوا انجام میشد و زبان جدید (که ابتدا Mocha، سپس LiveScript و در نهایت JavaScript نام گرفت) صرفاً به عنوان «برادر کوچک و خنگِ جاوا» برای سناریوهای ساده طراحی رابط کاربری و اعتبارسنجیهای فرمی سبک در نظر گرفته شده بود . این نگرش تقلیلگرایانه، آزادی عمل آیک را به شدت محدود کرد .
۲. تلفیق Scheme و Self با پوسته C (The Language Synthesis)
آیک برای دور زدن محدودیتهای اعمالشده و در عین حال حفظ سادگی و سرعت توسعه، مفاهیم دو زبان مدرن آن دوران را استخراج کرده و آنها را در کالبد نحوی C قرار داد :
- ارثبری نمونهپایه (Prototype-based Delegation) از زبان Self: آیک به شدت تحت تأثیر مقالات دیو اونگار (Dave Ungar) درباره سادگی مفرط زبان Self قرار داشت . او از ساختارهای پیچیده و سنگین کلاسمحور جاوا فرار کرد و به سمت نمونهها رفت . این تصمیم به او اجازه داد بدون نیاز به پیادهسازی سیستمهای تحلیل کلاس و ساختارهای سلسلهمراتب پیچیده در زمان کوتاه، مدل شیءگرایی پویا و کارآمدی خلق کند .
- توابع درجه اول (First-class Functions) از زبان Scheme: او مکانیزم حوزه واژگانی (Lexical Scope) و توابع مرتبه بالا را مستقیماً از Scheme وارد کرد که شالوده اصلی قدرت پردازشی و تابعی جاوااسکریپت را تشکیل داد .
- پرهیز از تفکیک انواع داده در Java: بر خلاف جاوا که مرز سختگیرانهای میان انواع داده اولیه (Primitive Types مانند
intیاchar) و اشیاء (Objects) قائل بود، آیک تلاش کرد تا جای ممکن این تفکیک بیهوده را در جاوااسکریپت حذف کند تا همهچیز رفتاری یکپارچه داشته باشد .
۳. بزرگترین لغزش طراحی: ادغام شیء سراسری با Window (The Global Object Blunder)
شتابزدگی بیسابقه در توسعه نسخه اولیه، منجر به بروز خطاهای مهندسی بزرگی در سطح زبان شد :
- ادغام شیء سراسری با Window Object: آیک برای کاهش تعداد اشیاء مورد نیاز در حافظه مرورگر و صرفهجویی در لایه اختصاص داده، تصمیم گرفت شیء سراسری (Global Object) را مستقیماً با Window Object مرورگر یکی کند .
- تبعات مهندسی: این تصمیم باعث شد تمام متغیرهای تعریفشده در لایه بالایی (Top-level Variables) به ویژگیهای تغییرپذیر (Mutable Properties) یک شیء مشترک تبدیل شوند که هر بخش از برنامه میتواند آنها را دستکاری کند . این امر عملاً ارزیابی ایستای متغیرهای آزاد (Free Variables) را توسط کامپایلر غیرممکن ساخت و رخنههای امنیتی مفرطی ایجاد کرد .
- الگوی دور زدن (Namespace Isolation): برای جبران این نشت امنیتی، توسعهدهندگان ناچار شدند از الگوی تعریف یک تابع سراسری و اجرای آنی آن (IIFE) استفاده کنند تا یک حوزه واژگانی محلی و امن برای متغیرهای خصوصی خود ایجاد نمایند .
۴. سایه سنگین سنت یونیکس و ابداع کلمه کلیدی function (The Awk & HyperTalk Heritage)
بسیاری از جزئیات نحوی جاوااسکریپت ناشی از تجارب قبلی آیک به عنوان هکر سیستمهای یونیکس و ابزارهای رسانهای بود :
- میراث زبان awk: آیک سالها از ابزار awk برای کارهای سیستمی خود استفاده میکرد . جالب است که او نام کلمه کلیدی تعریف تابع را صرفاً به دلیل عادت ذهنی به نحو awk، کلمه ۸ کاراکتری و سنگین
functionانتخاب کرد . او با شوخی اشاره میکند که خوشحال است نام آن راlambdaنگذاشته است، چرا که در این صورت زبان احتمالاً در همان ابتدا توسط جامعه تجاری پس زده میشد . - میراث HyperTalk و HyperCard: سبک تعریف رویدادها در مدل شیءگرای سند (مانند ویژگیهای
onClickیاonLoadدر HTML) مستقیماً از سیستم مدیریت رویداد زبان HyperTalk (متعلق به ابزار پیشگام HyperCard شرکت اپل) الگوبرداری شد .
درامای استانداردسازی جاوااسکریپت و قطببندی فلسفی کمیته (The ECMAScript 4 Drama & Committee Schism)
پیشزمینه و ریشههای تکامل بیش از حد (ActionScript 3 & Netscape 2/ES4): تلاش برای تدوین استاندارد ECMAScript 4 (ES4) در حقیقت یک برنامه بلندپروازانه برای مجهز کردن جاوااسکریپت به قابلیتهای ساختاریافتهی توسعه در مقیاس بزرگ (Programming-in-the-Large) بود . این جنبش به شدت تحت تأثیر کار پیشین والدما هوروات (Waldemar Horwat) در اواخر دهه ۹۰ میلادی بر روی نسخه اولیه جاوااسکریپت ۲ قرار داشت که پس از تعدیل نیروهای نتاسکیپ در سال ۲۰۰۳ و تأسیس بنیاد موزیلا به حالت تعلیق درآمده بود . شرکت ادوبی (Adobe) با تکیه بر این دستاوردها، زبان ActionScript 3 را توسعه داد که بعداً به عنوان کاتالیزور اصلی، هدایتِ جهتگیریهای فنی کمیته ES4 را بر عهده گرفت . هوروات (که برنده مسابقه ریاضی معتبر Putnam در سال ۱۹۸۷ و فارغالتحصیل دکتری از MIT بود) تلاش فراوانی کرد تا ماهیت پویای زبان را حفظ کرده و در عین حال مفاهیمی چون فضاهای نام (Namespaces) و کلاسها را به هسته زبان تزریق کند .
رویارویی دو مکتب فکری: تقلیلگرایان در برابر عملگرایان (The Minimalist vs. Pragmatic Feud): کمیته فنی استانداردسازی با یک انشقاق عمیق فلسفی روبرو شد : ۱. مکتب تقلیلگرایان (Reductionist School): با محوریت داگلاس کراکفورد، معتقد بودند که زبان باید به مجموعهای بسیار کوچک از ساختارهای اولیه تقلیل یابد و همهچیز (حتی الگوهای پیچیده شیءگرایی) از نو با ساختار لامبدا (Lambda Coding) توسعه یابد . ۲. مکتب عملگرایان (Pragmatic/Feature School): برندن آیک استدلال میکرد که رویکرد تقلیلگرایانه و تکیه صرف بر قدرت محاسباتی لامبدا، اگرچه از نظر ریاضیاتی زیباست (همانطور که آلونزو چرچ ثابت کرد)، اما برای دنیای واقعی ناکارآمد است . از نظر آیک، بخش بزرگی از برنامهنویسان فعال در صنعت، در مدارس سنتی جاوا آموزش دیدهاند (mistrained in these Java schools) و بدون برخورداری از قندهای ساختاری (Syntactic Sugar) برای کپسولهسازی و تعریف صریح اشیاء، پایگاههای کد آنها به سرعت به کانون تجمع باگهای سخت تبدیل خواهد شد . او پافشاری میکرد که زبان باید به تکامل خود ادامه دهد تا به ابزارهای حیاتی نظیر خوانندهها و نویسندهها (Getters & Setters) مجهز شود؛ در غیر این صورت، نوشتن انتزاعهای کتابخانهای تمیز که رفتاری شبیه به اشیاء بومی سیستم داشته باشند، عملاً غیرممکن خواهد بود .
کارشکنی ژئوپلیتیک مایکروسافت و انفجار درونکمیتهای (Microsoft’s Pivot & Committee Revolt): روند توافقات فنی در کمیته به دلیل رفتارهای ناپایدار و تصمیمات اداری شرکت مایکروسافت با بنبست مواجه شد . پس از سالها بیتوجهی، نماینده فنی مایکروسافت به کمیته آمد و با اشتیاق فراوان وعده داد که مایکروسافت بستر اجرای مشترک زبانها (CLR) را درون مرورگر اینترنت اکسپلورر ۸ (IE8) تعبیه خواهد کرد و JScript.net را به عنوان پیادهسازی رسمی جاوااسکریپت وب معرفی خواهد کرد . با این حال، این اشتیاق فنی بعداً توسط لایههای مدیریت ارشد مایکروسافت سرکوب شد و دستور توقف پروژه صادر گردید . این نوسان ناگهانی و کارشکنی تجاری، منجر به وقوع یک طغیان بزرگ و انشعب کامل در کمیته استانداردهای وب شد .
تعویق تاکتیکی ماکروها به نفع قندهای نحوی (Macro Postponement): کراکفورد در جریان یکی از جلسات یاهو به آیک پیشنهاد داد که به جای اضافه کردن قندهای نحوی متعدد، ابتدا یک سیستم ماکروی بهداشتی (Hygienic Macro System) طراحی و پیادهسازی کنند تا کاربران خودشان نحو زبان را توسعه دهند . آیک با تحلیل ریسکهای زمانی، این پیشنهاد را رد کرد؛ زیرا معتقد بود طراحی و استانداردسازی یک سیستم ماکروی امن به دلیل پیچیدگیهای تحلیل درخت نحو انتزاعی (AST) در گرامرهای شبیه به C و حل مسائل مربوط به اثبات درستی بهداشت ماکروها (موضوع پایاننامه دکتری دیو هرمن) حداقل ۹ سال زمان خواهد برد . از منظر تاکتیکی، آیک تصمیم گرفت قندهای نحوی را مستقیماً تزریق کند تا در شرایط رکود مرورگرها، فشار رقابتی بر روی مایکروسافت حفظ شود .
مرگ ECMAScript 4 و زایش طرح Harmony (The Collapse of ES4 & Birth of Harmony): آیک در بازنگری تاریخی اقرار میکند که نسخه پیشنهادی ES4 در عمل بیش از حد حجیم و بزرگ شده بود . داگلاس کراکفورد که خود را در جایگاه گندالف در نبرد پل خزد-دوم در برابر هیولای ES4 میدید، مرگ این پروژه را جشن گرفت . با این حال، آیک تأکید میکند که ES4 یک هیولا نبود . در نهایت، با درک خطرات ناشی از ناسازگاری و انحلال استانداردهای وب، کمیته تصمیم گرفت نسخه حداقلی ES3.1 (که بعداً به ES5 تغییر نام یافت) را با ایدههای کلیدی و بهینهسازیشدهی ES4 ادغام کرده و نقشه راه جدیدی به نام Harmony (که شالوده جاوااسکریپت مدرن شد) ترسیم کند .
چالشهای پیادهسازی: فاجعه تفسیرگر SML و خطایابی در TraceMonkey
شکست تفسیرگر مرجع مبتنی بر SML New Jersey: تیم توسعه موزیلا تلاش کرد تا نسخه مرجع استاندارد ES4 را با استفاده از زبان کاملاً تایپشدهی SML New Jersey به عنوان یک تفسیرگر تعریفی (Definitional Interpreter) پیادهسازی کند . این تلاش به دلیل مواجهه با محدودیتهای شدید سیستم تایپچک شکست خورد . الگوریتم انطباق انواع (Type Unification) در SML به گونهای بود که در زمان شکست روند یکپارچهسازی، پیامهای خطای به شدت مبهم و غیرقابلفهمی صادر میکرد که آدرسدهی و دیباگ را ناممکن میساخت . این پروژه در نهایت به حالت تعلیق درآمد .
محدودیتهای سیستمهای کامپایل درجا (Trace-based JIT VM - TraceMonkey): فرآیند بهینهسازی جاوااسکریپت در مرورگر فایرفاکس با توسعه موتور TraceMonkey و تکنولوژی JIT مبتنی بر ردگیری (Tracing JIT) وارد فاز جدیدی شد . در این سیستم، کامپایلر به جای کامپایل کل برنامه، مسیرهای تکرارشونده و داغ پشته (Hot Loops) را در زمان اجرا شناسایی کرده و آنها را مستقیماً به کدهای ماشین بسیار بهینه تبدیل میکرد . با این حال، این تکنیک پیچیدگیهای ساختاری مفرطی را به همراه داشت؛ زیرا فرضیات کامپایلر در مورد پایداری انواع داده در متغیرهای پویا میتوانست در میانه مسیر نقض شود که این امر نیاز به فرآیندهای سنگین بازگشت به عقب (Deoptimization Bailouts) داشت.
همروندی در وب: مدل «اشتراکهیچ» در برابر کابوس نخها (Concurrency & Shared-Nothing)
رویکرد بدون وضعیت مشترک (Shared-Nothing Concurrency): برندن آیک به شدت با مدلهای همروندی مبتنی بر قفلها (Locks)، سمافورها (Mutexes) و متغیرهای اشتراکی در سطح حافظه مخالفت میکند . او سیستمهای چندنخی سنتی را مولد خطاهای مهلکی چون شرایط رقابتی ناپایدار میداند . در مقابل، او از مدل اشتراکهیچ (Shared-Nothing) که در زبان Erlang توسط جو آرمسترانگ پیادهسازی شده، دفاع میکند . در این مدل، فرآیندها یا ماشینهای مجازی کاملاً ایزوله هستند و هیچ وضعیت مشترکی در حافظه ندارند و تعامل میان آنها منحصراً از طریق ارسال پیامهای تغییرناپذیر صورت میگیرد؛ رویکردی که در سیستمعامل مرورگر کروم و همچنین لایه Web Workers در فایرفاکس پیادهسازی شد .
نردبان برنامهنویسی و مرزهای انتزاع (The Programming Ziggurat): آیک معتقد است برنامهنویسی مانند یک نردبان یا زیگورات تاریخی است که مهندسان همواره در حال صعود از آن به سمت لایههای انتزاعی بالاتر برای حل مسائل بزرگتر هستند . با این حال، او نسبت به اضافه کردن مفاهیم فوقالعاده پیچیده تئوریک مانند
call/cc(دنباله با حق فراخوانی) به جاوااسکریپت هشدار میدهد . اگرچه این ابزارها قدرت بیان بینظیری به برنامهنویسان ارشد میدهند، اما برای بدنه بزرگ جامعه توسعهدهندگان صنعتی گمراهکننده خواهند بود و پیامدهای امنیتی تخریبکنندهای به سیستمهای تجاری وارد خواهند کرد .
مسئله بازنویسی بزرگ و مرگ کلاف سردرگم کدهای دانشجویی (The Big Rewrite & The Death of Student Code)
افسانه نتاسکیپ به عنوان نماد خطرات بازنویسی کامل:
بر اساس تحلیلهای مشهور (مانند مقاله معروف جول اسپولسکی)، تصمیم نتاسکیپ برای بازنویسی کامل مرورگر از نو، به عنوان یکی از بزرگترین خطاهای استراتژیک صنعت نرمافزار شناخته میشود . با این حال، برندن آیک ابعاد مهندسی این ماجرا را به گونهای دیگر تشریح میکند : ۱. فشار ناشی از خریدهای جدید شرکت (Acquisitions): پس از ادغام تیمهای جدید، فشاری از سوی مدیریت نتاسکیپ وجود داشت تا موتور رندرینگ جدیدی که توسط تیم تازه خریداریشده توسعه یافته بود، مورد استفاده قرار گیرد . کدهای این موتور جدید با تکیه شدید بر الگوهای کتاب معروف Design Patterns و با زبانی شیءگرا (C++) نوشته شده بود؛ کدی که آیک با لحنی کنایهآمیز آن را «اولین موتور رندر شیءگرای من» (My First Object-Oriented Rendering Engine) مینامد و تأکید میکند که در عمل با باگها و افت کارایی شدیدی مواجه بود . ۲. نیاز مبرم به فضایی برای توسعه مستقل (Homesteading Space): علت دوم و مهندسیتر تصمیم آیک برای بازنویسی، نیاز به باز کردن فضا برای مشارکتکنندگان جدید در پروژه نوپای mozilla.org بود . توسعهدهندگان متنباز خارج از شرکت نمیتوانستند بر روی پایگاه کد قدیمی نتاسکیپ کار کنند؛ کدی که آیک آن را «کلاف سردرگم کدهای دانشجویی سال ۱۹۹۴» (Old Hairball of Student Code from 1994) و تفاسیر شخصی خود به سبک هکرهای هسته یونیکس توصیف میکند . پروژه برای بقا به بستری مدرن، خوانا و عاری از پیچیدگیهای فرسوده گذشته نیاز داشت .رویکرد آیک به مطالعه کدهای بیرونی:
آیک به عنوان بخشی از وظایف مهندسی خود، زمان زیادی را صرف بازبینی کدهای دیگران (Code Review) میکند تا ضعفهای استخدامی نتاسکیپ را جبران کند . او فراتر از دنیای موزیلا، کدهای پیادهسازی فریمورکهای سرور و زبانهایی مانند Python و Ruby را مطالعه میکند . او همچنین از تماشای خلاقیت توسعهدهندگان وب در کتابخانههای Ajax شگفتزده میشود؛ کدهایی که نشان میدهند چگونه میتوان از ترکیب سه ابزار ساده یعنی توابع کلوژر (Closures)، نمونهها (Prototypes) و اشیاء (Objects)، انتزاعهای فوقالعاده کارآمد و کاربردی پدید آورد .
سهمگینترین باگهای تاریخ کاری: کابوس چندنخی در هسته سیستمعامل SGI
کابوس قفلها و شرایط رقابتی در کدهای چندنخی:
آیک سهمگینترین و فرسایندهترین باگهای دوران کاری خود را باگهای ناشی از سیستمهای چندنخی (Multithreaded Bugs) میداند . در زمان حضور او در شرکت Silicon Graphics (SGI)، هسته سیستمعامل یونیکس این شرکت در ابتدا یک مانیتور یکپارچه و تکنخی (Monolithic Monitor) بود که به صورت تضمینشده تا زمان اتمام درخواست اجرا میشد و نیازی به هیچگونه قفلگذاری روی ساختارهای داده نداشت .ورود سیستمهای چندپردازندهای و سفر اضطراری به اقیانوسیه:
با ورود مهندسان جوان شرکت HP به SGI و معرفی معماری پردازش متقارن چندگانه (SMP)، ساختار تکنخی هسته فرو ریخت . تیم جدید شروع به بازنویسی دستی کدها و تزریق سمافورها، قفلهای چرخشی (Spinlocks) و متغیرهای شرطی به پایگاه کد یونیکس کرد که در عمل زنجیرهای بیپایان از رخنههای امنیتی و باگهای همروندی تولید نمود .
آیک برای حل یکی از همین باگهای همروندی بسیار مهلک که ناشی از انتقال ناامن کدهای تکنخی قدیمی به محیط چندنخی SMP بود، مجبور به سفری اضطراری به استرالیا و نیوزیلند شد . او تحت فشار شدید کارفرما که خواهان اصلاح فوری سیستم در محل دیتاسنتر بود، پس از چندین روز تحلیل فرساینده رفتار وضعیت پردازندهها، موفق به بازتولید شرایط مسابقه (Race Condition) و رفع باگ شد .
مکانیزم شناسایی استعدادهای برتر و مخالفت با سوالات پازلی در مصاحبه (Recognizing Talent)
ردپای نبوغ در هکرهای انفرادی:
روش آیک برای شناسایی برنامهنویسان نابغه، فرار از سوالات کلیشهای و پازلهای بیهوده است؛ سوالاتی که او استخدام بر پایه آنها را نگرانکننده میداند . رویکرد او، هدایت گفتگو به سمت پروژههای شخصی داوطلب و به چالش کشیدن الگوریتمها و تصمیمات فنی است که او برای آنها «خون دل خورده است» (Spent Blood) . او معتقد است هر برنامهنویس واقعی که با تمام وجود روی یک پروژه کار کرده باشد، با اشتیاق فراوان از معماری آن دفاع خواهد کرد .داستان استخدام هکر برجسته OCaml:
آیک به عنوان نمونه، به استخدام یک برنامهنویس فوقالعاده جوان اشاره میکند که تحصیلات دانشگاهیاش را حتی به پایان نرسانده بود اما به صورت انفرادی کدهای کامپایلر و سیستمعامل بومی زبان OCaml را هک میکرد . این برنامهنویس پس از استخدام، ابزارهای تحلیل ایستای کدهای امنیتی موزیلا (بر پایه فریمورک بومی Oink برکلی) و پلاگینهای کامپایلر GCC را توسعه داد و با استفاده از متد سادهی چاپ برچسبهای زمانی (Printf Timestamps)، گلوگاههای کارایی مرورگر را شناسایی و برطرف کرد . اصل استخدام آیک بر این فرض استوار است: «افراد باهوش تمایل دارند با افراد باهوش کار کنند» .
لذت اعتیادآور هک و فلسفه ۹۰/۱۰ نیوجرسی (The Addiction of Hacking)
برنامهنویسی به مثابه یک اعتیاد ذهنی:
آیک اقرار میکند که برنامهنویسی برای او همچنان رفتاری شبیه به اعتیاد دارد که گاهی اوقات شبها مانع از خوابیدن او میشود . با این حال، لذت واقعی برنامهنویسی برای او در دوران بلوغ حرفهایاش، پیدا کردن نقطهی تلاقی میان نظریه زیبا و پیادهسازی عملگرا است؛ رویکردی که او آن را «فلسفه ۹۰/۱۰ نیوجرسی» (New Jersey 90/10 Philosophy) مینامد . بر اساس این تفکر، سیستم باید دارای یک هسته تئوریک بسیار شیرین و ساده باشد که شاید تمام مسائل جهان را حل نکند (۹۰ درصد کارایی)، اما زمانی که با ۱۰ درصدِ باقیمانده و سناریوهای شکست مواجه میشوید، کل سیستم شما نابود نشده و به جهنم مهندسی سقوط نکنید .مواجهه با زشتیهای نوزاد ۱۰ روزه:
او در پاسخ به انتقادات و تمسخرهای مکرر سالهای اولیه عرضه جاوااسکریپت، به ایمیلی اشاره میکند که جیمی زاوینسکی در سالهای نخست با موضوع «آنها نوزاد تو را زشت مینامند!» (They’re calling your baby ugly) برای او فرستاد . آیک با خنده اشاره میکند که در آن دوران به دلیل عجله و شتاب تجاری، فرار از باگهای اولیه غیرممکن بود؛ اما امروز با داشتن فرزندان واقعی، دیگر نگران این توهینهای مجازی نسبت به فرزند نرمافزاری خود (جاوااسکریپت) نیست .
فصل پنجم: جوشوا بلاک (Joshua Bloch)
بخش نخست: خاستگاه، برنامهنویسی به عنوان میراث خانوادگی و پروژههای دوران نوجوانی
جوشوا بلاک، معمار ارشد جاوا در گوگل، طراح کلیدی فریمورک Collections جاوا در شرکت Sun Microsystems، و نویسنده کتابهای مرجعی چون Effective Java و Java Puzzlers است . او دکتری خود را از دانشگاه کارنگی ملون (CMU) دریافت کرده و سالها در حوزه سیستمهای توزیعشده فعالیت داشته است .
۱. نخستین گامها و یادگیری تجربی در محیط اشتراک زمانی (First Steps & Timesharing)
بلاک برنامهنویسی را به نوعی موروثی میداند . پدر او شیمیدان برجسته در آزمایشگاه ملی بروکهاون (Brookhaven National Laboratory) بود . در سال ۱۹۷۱، زمانی که بلاک در کلاس چهارم ابتدایی تحصیل میکرد، پدرش دورهای آموزشی در زمینه برنامهنویسی گذراند . بلاک با دیدن تصاویر کامپیوترهای بزرگ (Mainframes) که پشت دیوارهای شیشهای ایزوله شده بودند و کاربران دستههای کارت پانچ خود را به اپراتور تحویل میدادند، شیفته این ماشینها شد و اصول اولیه Fortran را از روی جزوههای پدرش آموخت .
اما اشتیاق واقعی او در سال ۱۹۷۳ و با ظهور پدیده اشتراک زمانی (Timesharing) شعلهور شد . ایالت نیویورک کلاستری از سیستمهای DECsystem-10 را میان تمام مدارس منطقه توزیع کرده بود . این تعامل دوطرفه و بلادرنگ (Interactivity)، او را به هکری مشتاق تبدیل کرد . بلاک در سالهای ۱۹۷۳ تا ۱۹۷۶ کدهای زیادی به زبان BASIC نوشت . او همچنان برخی از این برنامهها را روی کاغذهای تلهتایپ کهنه (Teletype paper) نگهداری میکند و معتقد است که ریشهها و اصول استایل برنامهنویسی او (به ویژه تلاش مفرط برای خوانایی) از همان دوران تا به امروز بدون تغییر باقی ماندهاند .
۲. نخستین برنامههای خلاقانه: از بازی خودآموز تا شبیهساز چتروم سیستمی
بزرگترین و جالبترین پروژههای نوجوانی او بر دو محور استوار بود:
- برنامه خودآموزِ جانوران (Animals - 1977): در ۴ ژوئیه ۱۹۷۷، او یک بازی کلاسیک ۲۰ سوالی به نام Animals نوشت . معماری برنامه مبتنی بر یک درخت باینری (Binary Tree) بود که گرههای داخلی آن حاوی سوالات بله/خیر و برگهای آن حاوی نام جانوران بود . ویژگی درخشان برنامه این بود که در مواجهه با جانوری جدید، با پرسیدن یک سوال متمایزکننده از کاربر، درخت باینری خود را روی دیسک بازنویسی و بهروزرسانی میکرد . بلاک با هیجان میگوید: «برای من مثل معجزه بود؛ این که میدیدم برنامه واقعاً یاد میگیرد و با گذشت زمان باهوشتر میشود» .
- پروتکل ارتباطی بین پردازشی (Inter-job Communication): در کلاس دهم، اجرای برنامههای پیامرسان فوری (Instant Messaging) روی کامپیوتر مدرسه به دلیل مصرف بالای منابع سیستمی ممنوع بود . بلاک با شیطنت نوجوانی، پروژهای تحقیقاتی درباره برنامههای ارتباط همزمان میان پردازشها به نمایشگاه ریاضی لانگآیلند ارسال کرد و برنده جایزه شد . دوستش تامی برنامهای مبتنی بر فایل در BASIC نوشت؛ اما بلاک دو برنامه چت (یکی خطمحور و دیگری کاراکترمحور) به زبان اسمبلی MACRO-10 برای پردازنده PDP-10 نوشت . این برنامهها از یک بخش از حافظه اشتراکی موسوم به High Segment برای تبادل سریع بایتها استفاده میکردند . به دلیل عدم آشنایی بلاک با مفاهیم کنترل همروندی و قفلهای انحصاری متقابل (Mutexes) در آن سن، سیستم در زمان اجرا با شرایط رقابتی (Race Conditions) مواجه میشد و گاهی بایتها مفقود میشدند؛ مشکلی که حل آن در آن دوران فراتر از دانش او بود .
۳. گسست از پیشفرضهای صلب شیءگرایی و مخالفت با ادعای دیکسترا (Dijkstra BASIC Critique)
بلاک برخلاف ادعای تند ادسگر دیکسترا (Edsger Dijkstra) مبنی بر اینکه «آموزش بیسیک ذهن دانشآموزان را برای همیشه مخدوش میکند»، معتقد است بیسیک نقطه آغاز بسیار مناسبی برای برنامهنویسان بزرگ بوده است . او در دوران دانشگاه (کلمبیا و کارنگی ملون) زبانهای متعددی را تجربه کرد: فرترن برای محاسبات عددی، Pascal و Simula برای ساختارهای داده، و Lisp برای هوش مصنوعی .
جالب اینجاست که او تا پیش از پیوستن به شرکت Sun Microsystems در سال ۱۹۹۶، هرگز وارد دنیای برنامهنویسی شیءگرا نشده بود؛ زیرا تمایلی به استفاده از C++ نداشت . تحلیل او از شیءگرایی (OO) مبتنی بر تفکیک دو مفهوم بنیادین است : ۱. پیمانهای بودن (Modularity): کپسولهسازی و پنهانسازی اطلاعات (Information Hiding) که مفهوم جدیدی نیست و دههها پیش توسط دیوید پارناس (David Parnas) فرموله شده بود . ۲. ارثبری (Inheritance): مفهومی که بلاک آن را مانند بسیاری از تحلیلگران مدرن، یک شمشیر دو لبه (Mixed Blessing) و منشأ ایجاد وابستگیهای ناخواسته در سیستمهای بزرگ میداند .
۴. نبردِ کارایی در گوگل:Glorified Assembly در برابر زبانهای امن (Glorified Assembly vs. Java)
امروزه حجم بسیار عظیمی از کدهای گوگل به زبان جاوا نوشته شده است . با این حال، بلاک مرز مهندسی کارایی را در کلاسترهای بزرگ اینگونه تبیین میکند:
- برای بخشهای مرکزی سیستم (مانند حلقههای داخلی سرورهای نمایه و جستجو)، افزایش حتی یک یا دو درصدی کارایی کدهای ماشین به دلیل مقیاس میلیونی سرورها، صرفهجویی مالی و زیستمحیطی هنگفتی به همراه دارد .
- نوشتن این بخشهای بحرانی با جاوا کاری بیهوده است . در این لایهها، زبان C عملاً یک اسمبلی ارتقایافته (Glorified Assembly) است که به توسعهدهنده اجازه میدهد کنترل کاملی بر ثباتها و چیدمان فیزیکی بایتها روی سختافزار داشته باشد .
- در استارتآپهای نوین، رویکرد منطقی این است که ۹۰ درصد کدها را با زبانی امن مانند جاوا توسعه داده و تنها در لایههایی که بیشترین چرخه پردازنده (CPU Cycles) را مصرف میکنند، به زبان C یا اسمبلی گریز بزنند .
فلسفه طراحی API: تفکر مشتریمحور و مذهبِ «اگر شک داری، حذفش کن» (API Design Philosophy: Client-First and “When in doubt, leave it out”)
جوشوا بلاک یکی از مبلغان سرسخت این ایده است که «برنامهنویسی در حقیقت همان طراحی API است»؛ زیرا در سیستمهای بزرگ، مهندسی نرمافزار به معنای شکستن سیستم به ماژولهای مجزا و طراحی اینترفیسهای بینماژولی (Intermodular Interfaces) است . متدولوژی عملیاتی او برای طراحی یک API مستحکم به شرح زیر است:
- تلهی مستندات ۲۵۰ صفحهای زودهنگام: بلاک بدترین خطا در شروع یک پروژه را جمع کردن مهندسان در یک اتاق به مدت شش ماه برای نوشتن یک سند مشخصات فنی (Specification) قطور و صلب پیش از درک واقعی نیازها میداند . این فرآیند فرساینده معمولاً منجر به ساخت سیستمهای بیمصرف و غولپیکری میشود که برای انجام سادهترین کارها (مانند چاپ یک سند XML) نیاز به صفحات متعددی از کدهای تکراری (Boilerplate) دارند .
- طراحی سناریوهای کاربردی (Use Cases) به عنوان سنگ محک: نخستین گام حیاتی، استخراج دقیق نیازمندیها و نوشتن سناریوهای واقعی استفاده از سیستم است تا به عنوان معیاری برای سنجش کیفیت هر طرح فنی عمل کنند .
- خلق ساختار اسکلتی تکصفحهای (Skeletal API): گام بعدی، نوشتن یک طرح کلی بسیار کوتاه (حداکثر در یک صفحه) شامل تعریف پکیجها، کلاسها، متدها و در صورت نیاز یک جمله توضیح برای هر کدام است . هدف این مرحله، حفظ چابکی (Agility) حداکثری برای اعمال تغییرات است .
- قانون طلایی: ابتدا کدی را بنویسید که از API استفاده میکند (Write the client code first): پیش از آنکه حتی یک خط از کدهای پیادهسازی (Implementation) یا جزئیات دقیق مشخصات فنی را بنویسید، باید سناریوهای کاربردی خود را با استفاده از این API اسکلتی کدنویسی کنید . این رویکرد به شما نشان میدهد که آیا کار با این اینترفیس راحت و منطقی است یا به شدت فرساینده و اشتباه است . بلاک این روش را «برنامهنویسی تستاولیه و فاکتورگیری مجدد در سطح API» مینامد .
- قضیه بنیادی طراحی: «اگر شک داری، حذفش کن»: یک API باید سادهترین و کوچکترین ساختار ممکن برای پوشش سناریوهای مورد نظر را داشته باشد . اضافه کردن ویژگیها صرفاً به این دلیل که «جذاب» یا از نظر مهندسی «تمیز» به نظر میرسند، یک گناه بزرگ مهندسی است . بلاک به قانون جیمز گاسلینگ اشاره میکند: «پیش از اضافه کردن هر ویژگی به زبان یا کتابخانه، باید حداقل ۳ سناریوی واقعی و ملموس برای استفاده از آن داشته باشید» .
- ژنِ همدلی (The Empathy Gene) در طراحی: بلاک معتقد است هوش بالا برای طراحی سیستمهای خوب کافی نیست؛ زیرا هوش یک کمیت برداری (Vector Quantity) است و اگر طراح فاقد همدلی (Empathy) یا هوش عاطفی باشد، هرگز نمیتواند خود را جای برنامهنویس عادی بگذارد که قرار است از ابزار او استفاده کند . بدون همدلی، خروجی کار ابزارهایی به شدت پیچیده و غیرقابلاستفاده خواهد بود .
نبرد با باگهای موهوم سیستمهای توزیعشده: فاجعه جابهجایی قفلها در Transarc (The Transarc Mutex Blunder)
یکی از هولناکترین و در عین حال آموزندهترین باگهای دوران کاری بلاک، به اوایل دهه ۹۰ میلادی و زمان حضور او در شرکت Transarc (سازنده سیستمهای توزیعشده) مربوط میشود . او در این پروژه متعهد شده بود یک سیستم مدیریت حافظه اشتراکی تراکنشی (Transactional Shared-Memory Implementation) را در ضربالاجلی بسیار فشرده توسعه دهد .
- مذهبِ تستِ مخرب (The Basher): بلاک برای اطمینان از صحت کدهای خود، تحت تأثیر توصیه دونالد کنوت مبنی بر «قرار دادن خود در بدبینانهترین حالت ذهنی ممکن در زمان تست»، یک برنامهی تست مخرب و غولپیکر به نام Basher نوشت . این ابزار تعداد زیادی تراکنش توزیعشده همروند تودرتو را اجرا میکرد که بر روی یک آرایه اشتراکی قفل میگذاشتند، مقادیر آن را تغییر میدادند و برخی را متعهد (Commit) و برخی را سقط (Abort) میکردند . چندین فرآیند مالتیتِردِ Basher به صورت همزمان به این ساختار حمله میکردند تا پایداری لایه حافظه را بسنجند .
- وقوع خطای نامنظم و مفقود شدن فرضیات: در شرایط همروندی بالا، سیستم گاهی اوقات در بررسیهای صحت ساختار داده شکست میخورد . باگ کاملاً غیرقابلبازسازی بود و به صورت تصادفی رخ میداد . بلاک که به مدیر قفلها (Lock Manager) نوشتهشده توسط خودش شک کرده بود، یک هفته تمام روی نوشتن تستهای واحد برای آن وقت گذاشت، اما مدیر قفلها بدون مشکل کار میکرد .
- کشف حقیقت: فروپاشی سنگ بستر (Broken Bedrock): پس از تحلیلهای عمیق و فرساینده، بلاک متوجه شد که مشکل از کدهای او نیست، بلکه سنگ بستر سیستم یعنی پیادهسازی Mutex در سیستمعامل خراب است! در آن دوران، سیستمعاملها به صورت بومی از تِردها پشتیبانی نمیکردند و شرکتها ناچار بودند پکیجهای تِرد اختصاصی خود را بنویسند . بررسی کدهای اسمبلی پکیج ترد شرکت Solaris نشان داد که مهندس مسئول، به اشتباه برچسبهای متدهای
lockوtry-lockرا در کد اسمبلی با یکدیگر جابهجا کرده بود! - تبعات فاجعه: این جابهجایی به این معنی بود که وقتی برنامهنویس گمان میکرد متد مسدودکننده و ایمن
lockرا صدا میزند، در حقیقت متد غیرمسدودکنندهtry-lockاجرا میشد . در نتیجه، به محض بروز تداخل فیزیکی، تِرد دوم بدون اعتنا به قفل تِرد اول، مستقیماً وارد ناحیه بحرانی (Critical Section) میشد و حافظه را خراب میکرد . خندهدارترین نکته مهندسی این بود که به دلیل کم بودن تداخلهای واقعی در آن دوران، کل شرکت Transarc به مدت دو هفته بدون وجود هیچ قفل انحصاری واقعی در حال اجرای کدهای خود بود و هیچکس متوجه این فاجعه نشده بود!
پشتههای غولپیکر و بحران جعل هویت نخها (The Stack-jumping Thread Impersonation Bug)
باگ هولناک دیگری که بلاک در دوران کار بر روی سیستم تراکنشی Camelot در دانشگاه CMU شاهد آن بود، نمونه بارز نیاز مبرم صنعت به زبانهای مجهز به مدیریت ایمن حافظه (Safe Languages) است .
- نقص مبهم در بسته ردگیری (Trace Package): تیم متوجه شد که در فایلهای گزارش (Logs)، گاهی اوقات رویدادها به شناسههای تِرد (Thread IDs) اشتباهی منتسب میشوند . از آنجا که این خطا بیخطر به نظر میرسید، تیم برای مدتی آن را نادیده گرفت .
- مکانیزم کشف شناسه تِرد در پکیجهای قدیمی: سیستم برای کشف شناسه تِرد فعلی، از یک ترفند متداول و سریع در آن دوران استفاده میکرد: از آنجا که هر تِرد دارای یک پشته (Stack) با اندازه ثابت و توانی از عدد ۲ بود، پکیج ترد آدرس یک متغیر محلی روی پشته را میگرفت، بیتهای مرتبه پایین آن را با عملگر شیفت راست حذف میکرد و عدد باقیمانده مستقیماً به عنوان شناسه تِرد در نظر گرفته میشد .
- وقوع فاجعه پرش از منطقه قرمز پشته (Stack Red Zone): مشکل زمانی رخ داد که برخی برنامهنویسان ناآگاه، اشیاء و آرایههای بسیار بزرگی را مستقیماً درون پشته (توابع محلی) تعریف کردند؛ به عنوان نمونه، تعریف یک آرایه ۱۰۰ المانی که هر کدام ۴ کیلوبایت حجم داشتند، ناگهان ۴۰۰ کیلوبایت داده را به پشته تحمیل میکرد . این بارگذاری سنگین باعث میشد که پشته تِرد فعلی مستقیماً از روی «منطقه قرمز محافظتی» (Red Zone) عبور کرده و وارد پشته تِرد مجاور در حافظه شود .
- جعل هویت و دسترسی غیرمجاز: به دلیل این پرش فیزیکی، آدرس متغیرهای محلی این تِرد در محدوده پشته تِرد کناری قرار میگرفت . در نتیجه، متد کشف شناسه تِرد، این نخ را به اشتباه به جای نخ اصلی (مثلاً تِرد ۴۲) به عنوان نخ مجاور (تِرد ۴۳) شناسایی میکرد . فاجعه زمانی عمیقتر میشد که این تِرد برای دسترسی به متغیرهای محلی نخ خود (Thread-Local Variables) اقدام میکرد؛ سیستم به دلیل جعل هویت ناخواسته، دادههای خصوصی تِرد مجاور را در اختیار او قرار میداد که پیامدهای امنیتی و محاسباتی ویرانگری به همراه داشت . بلاک با تکیه بر این تجربه استدلال میکند که دانشجویان هرگز نباید در اولین مواجهههای خود با دنیای برنامهنویسی، ناچار به دستوپنجه نرم کردن با خطاهای مدیریت دستی حافظه و سرریز بافرها در زبان C باشند .
۱. داستان جنریکهای جاوا ۵ و کابوس پیچیدگی (Java 5 Generics, Wildcards, and Complexity)
افزایش ناخواسته پیچیدگی زبان:
جوشوا بلاک اقرار میکند تغییراتی که در نسخه جاوا ۵ اعمال شد، بسیار بیشتر از آنچه تیم طراحی پیشبینی میکرد به زبان پیچیدگی تحمیل کرد . او صراحتاً بیان میکند که در آن دوران، درک کاملی از میزان پیچیدگی که جنریکها (Generics) و بهویژه Wildcardها به زبان اضافه میکنند نداشته است . بلاک اعتبار این آیندهنگری را به گراهام همیلتون (Graham Hamilton) میدهد که سالها با افزودن جنریکها به جاوا مبارزه کرده بود .تداخل ذاتی زیرگونهسازی و جنریکها (Impedance Mismatch):
تداخل و ناسازگاری عمیقی میان مفهوم زیرگونهسازی (Subtyping) و جنریکها وجود دارد که Wildcardها تلاش کردند این عدم تطابق را برطرف کنند، اما این کار به بهای سنگین افزایش کارایی فکری مورد نیاز برای فهم زبان تمام شد . بلاک اشاره میکند برخی زبانها مانند اسکالا و سیشارپ ۴.۰ مدل دیگری موسوم به «واریانس در محل تعریف» (Declaration-site variance) را برگزیدهاند، اما معتقد است که هنوز برای قضاوت نهایی در مورد بهترین رویکرد زود است .سندرمِ «افزودن ویژگی به خاطر زیبایی» (The Sin of Neatness):
مدل ذهنی اولیه بلاک برای جنریکها این بود که چون مجموعهها (Collections) در ۹۹٪ موارد همگن هستند (مثلاً نقشهای از رشتهها به اعداد صحیح)، اجبار برنامهنویس به کست کردن (Casting) مداومِ دادهها در زمان خروجی کار درستی نیست و بهتر است سیستم خود کار کست را انجام داده و خطاها را در زمان کامپایل بگیرد . اما او بعدها متوجه شد که مهندسان واقعی در صنعت هرگز بابت نبودِ جنریکها شکایت نمیکردند . بلاک اقرار میکند که تیم طراحی مرتکب این گناه مهندسی شد که ویژگی را صرفاً به خاطر اینکه «زیبا و تمیز» به نظر میرسید اضافه کرد، نه برای حل یک مسئله واقعیِ کاربران . این در حالی است که جیمز گاسلینگ در سخنرانی معروف خود با عنوان «حس جاوا»، قانونِ داشتن حداقل سه کاربرد واقعی پیش از افزودن هر ویژگی جدید را فرموله کرده بود .سردرگمی کاربران عادی و شکنندگی ساختار زبان:
پیچیدگی زبان با افزایش ویژگیها به صورت درجه دو (Quadratic) رشد میکند و زمانی که زبان به مرز توانایی درک برنامهنویسان نزدیک میشود، افزودن هر پیچیدگی جدید کل ساختار را شکننده میسازد . نتیجه طراحی نابالغ جنریکها در جاوا، پدید آمدن ساختارهای غریب و سختی مانندclass Enum<E extends Enum<E>>و پیامهای خطای فوقالعاده پیچیده کامپایلر بود که برنامهنویسان عادی را به شدت سردرگم میساخت .
۲. باگ تاریخی و ۹ ساله جستجوی دودویی در جاوا (The 9-Year Binary Search Overflow Bug)
توهم درستی کدهای کوچک:
بلاک در مطلبی با عنوان «تقریباً تمام جستجوهای دودویی و مرتبسازیهای ادغامی خراب هستند» به این حقیقت پرداخت که نوشتنِ کدهای به ظاهر ساده به شکل کاملاً درست، چقدر کار دشواری است و برنامهنویسان همواره خود را با این فرض که برنامههایشان بدون باگ است فریب میدهند .- کالبدشکافی ریاضی باگ سرریز:
پیادهسازی کلاسیک الگوریتم جستجوی دودویی (Binary Search) در کتابخانه استاندارد جاوا به مدت ۹ سال حاوی یک باگ کشنده و مخفی بود . در این الگوریتم، برای یافتن ایندکس میانی، مقدار کمینه و بیشینه با هم جمع و بر ۲ تقسیم میشدند :1
int mid = (low + high) / 2;
باگ زمانی رخ میداد که مجموع
lowوhighاز سقف مجاز اعداد صحیح ۳۲ بیتی علامتدار (\(2^{31} - 1\) یا همانInteger.MAX_VALUE) فراتر میرفت . در این حالت، جمع ریاضی دچار سرریز (Overflow) شده و حاصل آن به یک عدد منفی تبدیل میشد که تقسیم آن بر ۲ نیز عددی منفی تولید میکرد و بلافاصله منجر به خطای خروج از مرز آرایه (ArrayIndexOutOfBoundsException) در زمان اجرا میشد . - راهکار اصلاحی و ضرورت تحلیل ایستا:
بلاک این باگ را با تغییر نحو به صورتlow + ((high - low) / 2)یا استفاده از عملگر شیفت راست بدون علامت جاوا به صورت(low + high) >>> 1برطرف کرد. این چالش، باور او را به سیستمهای تایپ ایستا (Static Typing) و ابزارهای تحلیل ایستای کد (Static Analysis) که میتوانند رسته مشخصی از خطاها را به صورت خودکار مهار کنند، دوچندان کرد . جالب اینجاست که دونالد کنوت نیز در کلاسهای دانشگاهی خود متوجه شده بود که کمتر از ۱۰ درصد دانشجویان در نخستین تلاش خود جستجوی دودویی بدون باگ مینویسند، هرچند حتی در کلاسهای او نیز هیچکس متوجه نشده بود که جمع دو ایندکس میتواند منجر به فاجعه سرریز اعداد صحیح شود .
۳. پکیج همروندی جاوا و مدل همکاری با داگ لی (Java Concurrency & Buddy Programming with Doug Lea)
جاوا به عنوان پیشتاز دنیای چندهستهای:
بر خلاف موجهای رسانهای که جاوا را زبانی مرده میخوانند، بلاک معتقد است جاوا بهترین و پیشرفتهترین ابزارهای همروندی (Concurrency Building Blocks) را در میان تمام زبانهای تجاری موجود (از جمله C++ و C#) داراست . او این پکیج را به سه لایه تقسیم میکند: ابزارهای سطح پایین (مانندAtomicInteger)، سطح متوسط (مانندCyclicBarrier) و لایههای سطح بالای فوقالعاده کارآمد (مانندConcurrentHashMapوThreadPoolExecutor) .متدولوژی همبرنامهنویسی از راه دور (Buddy Programming):
بلاک سالها به روش Buddy Programming با Doug Lea (طراح کلیدی زیرساخت همروندی جاوا) همکاری نزدیک داشته است . روش کار آنها به این صورت بود که حتی بدون حضور در یک نیمکره فیزیکی، تکههای کد و تعاریف اینترفیسها را مدام برای یکدیگر ارسال کرده و ایدههای هم را نقد و اصلاح میکردند . پس از نهایی شدن واسط برنامهنویسی (API)، بلاک نسخه سنتی و تکنخی آن را پیاده میکرد و داگ لی نسخه همروند و چندنخی آن را توسعه میداد . بلاک با ستایش از توانمندی فنی داگ لی میگوید: «داگ مهارت بینظیری در ارتقای سرعت سیستم دارد؛ او به شکلی غریبی با ماشین مجازی همکلام و همنوا است (communes with the VM) و به سرعت گلوگاههای کارایی را برطرف میسازد» .
فصل ششم: جو آرمسترانگ (Joe Armstrong)
بخش نخست: فیزیکدان شلخته، سیستمهای زمانواقعی و زایش غیرمنتظره ارلنگ
جو آرمسترانگ (متولد ۱۹۵۰) بیش از هر چیز به عنوان خالق زبان برنامهنویسی Erlang و فریمورک OTP (Open Telecom Platform) شناخته میشود . ارلنگ در دنیای زبانهای برنامهنویسی جایگاه منحصربهفردی دارد؛ ریشه در زبان منطقی Prolog دارد (نه خانواده Algol) و برای ساخت سیستمهای مخابراتی با قابلیت اطمینان و دسترسی فوقالعاده بالا طراحی شده است . با این حال، ویژگیهای مدیریت همروندی آن، ارلنگ را به بستری ایدهآل برای دنیای مدرن پردازندههای چندهستهای تبدیل کرده است .
۱. خاستگاه آکادمیک و گسست از فیزیک تجربی (From Physics PhD to Computer Science)
مسیر علمی آرمسترانگ با یکی از سختترین و کندترین فرآیندهای بازخورد در تاریخ محاسبات آغاز شد :
- دوران کارتهای پانچ در ۱۷ سالگی (۱۹۶۷): آرمسترانگ برنامهنویسی را در سال آخر دبیرستان با زبان Fortran روی یک کامپیوتر بزرگ (احتمالاً ساخت IBM) متعلق به شورای محلی آغاز کرد . فرآیند توسعه در آن زمان فرساینده بود: برنامهها روی کاغذ نوشته میشد، برای پانچ ارسال میشد، یک هفته بعد کارتهای پانچ بازمیگشت تا تایید شوند و سپس به مرکز محاسبات فرستاده میشد . از همه بدتر، کامپایلر فرترن با دیدن نخستین خطای نحوی (Syntax Error) متوقف میشد و باقی برنامه را پردازش نمیکرد؛ در نتیجه، اجرای موفقیتآمیز اولین برنامه نزدیک به سه ماه زمان میبرد . آیک برای غلبه بر این تاخیر، یاد گرفت که تمام زیربرنامهها (Subroutines) را به صورت موازی توسعه داده و تستهای واحد اختصاصی برای تکتک آنها بنویسد تا در زمان ادغام نهایی خطاها به حداقل برسند .
- گذار به فیزیک و کشف رایانههای انفرادی: او در رشته فیزیک دانشگاه لندن (UCL) تحصیل کرد و در آنجا نیز با چرخه بازخورد ۳ ساعته روبرو بود . تحول واقعی زمانی رخ داد که او دوره دکتری فیزیک انرژیهای بالا را آغاز کرد و به گروه اتاقک حباب (Bubble Chamber Group) پیوست . در آنجا یک مینیکامپیوتر Honeywell DDP-516 در اختیار او قرار گرفت که میتوانست به طور انحصاری از آن استفاده کند، کارتها را شخصاً وارد دستگاه کرده، دکمه اجرا را بفشارد و بلافاصله خروجی را دریافت کند . او روی این ماشین یک برنامه بازی شطرنج نوشت و شیفته سرعت بازخورد تعاملی آن شد .
- خروج از دکتری و هجرت به دنیای هوش مصنوعی: سرپرست علمی آرمسترانگ با دیدن اشتیاق او گفت: «تو نباید دکتری فیزیک بگیری؛ فیزیک را رها کن و وارد دنیای کامپیوتر شو» . آرمسترانگ به دلیل اتمام بودجه، دکتری فیزیک را نیمهکاره رها کرد . او که در کتابخانه فیزیک مخفیانه کتابهای هوش مصنوعی بخش پژوهشی ادینبورگ (مجموعه کتابهای Machine Intelligence) را مطالعه میکرد، نامهای به Donald Michie (از بنیانگذاران هوش مصنوعی در بریتانیا) نوشت و به عنوان پژوهشگر به آزمایشگاه او پیوست . او در آنجا به تحقیقات رباتیک و بینایی ماشین پرداخت .
- پروژههای فضایی و ساخت سیستمعاملهای اختصاصی: با قطع بودجه تحقیقات هوش مصنوعی در بریتانیا، او دوباره به عنوان برنامهنویس حوزه فیزیک به انجمن علمی EISCAT پیوست و سپس در شرکت فضایی سوئد (Swedish Space Corporation) مشغول به کار شد . در این دوره، او یک سیستمعامل کاربردی (Application Operating System) برای کنترل نخستین ماهواره سوئد به نام Viking توسعه داد؛ سیستمی که با سختترین محدودیتها (مانند ویرایشگرهای خطی ساده و لزوم قرارگیری تمام فایلها در یک دایرکتوری واحد با نامهای ۱۰ حرفی) ساخته شد . در نهایت، او در سال ۱۹۸۴ به آزمایشگاه کامپیوتر شرکت Ericsson پیوست؛ جایی که ارلنگ متولد شد .
۲. فلسفه کشف سادگی و مهارت خطایابی در دوران جوانی (Debugging as an Interval-Halving Science)
آرمسترانگ از همان سالهای نخست فعالیت، نگرشی بسیار ساختاریافته و منحصربهفرد نسبت به خطایابی و بهینهسازی کد داشت:
- کسب درآمد از طریق دیباگ (The Beer-scale Debugging): او در دوران دانشجویی به دلیل توانایی بالا در حل سریع باگها شهرت داشت و کدهای دیگران را در ازای دریافت آبجو دیباگ میکرد . قیمتگذاری او بر اساس سختی مسئله بود: «باگهای یکلیوانی، دولیوانی و سهلیوانی» .
- متدولوژی نصف کردن فاصله (Interval Halving): متدولوژی او برای حل باگهای بازتولیدپذیر (Reproducible Bugs) کاملاً سیستماتیک بود . او با قرار دادن دستورات چاپ (Print Statements) در میانه مسیر اجرای برنامه، وضعیت متغیرها را میسنجید؛ اگر مقدار درست بود، خطا در نیمه دوم برنامه بود و اگر نادرست بود، خطا در نیمه اول قرار داشت . او با تقسیم مداوم پهنای جستجو به نصف، به سرعت به منبع دقیق خطا میرسید . آرمسترانگ معتقد بود برنامهنویسان به این دلیل در دیباگ ناموفق هستند که خیلی زود تسلیم میشوند و سیستم را به صورت روشمند کند و متوقف نمیکنند .
- قانون قانونِ دیباگ جو (Joe’s Law of Debugging): او قانونی تجربی برای خطایابی دارد: «تمامی خطاها در محدوده مثبت/منفی ۳ خط از آخرین خطوطی قرار دارند که در برنامه تغییر دادهاید» . او این قانون را نه تنها در نرمافزار، بلکه در سختافزارها و حتی تعمیر خودرو نیز صادق میداند؛ زیرا خراب شدن یک سیستم پایدار معمولاً ناشی از آخرین مداخله فیزیکی یا منطقی در آن است .
- کاهش خطوط کد از طریق سادهسازی: آرمسترانگ همواره تعجب میکرد که چرا برنامهنویسان مسائل ساده را به شکلی به شدت پیچیده کدنویسی میکنند . او کدهای طولانی دیگران را برمیداشت و با بازنویسی مجدد، آنها را به چند خط ساده خلاصه میکرد تا منطق کار شفاف و عاری از پیچیدگیهای بیهوده شود .
طراحی همکارانه و سنت پاسکاریهای خلاقانه با رابرت ویردینگ (Collaborative Design & The Code-Swapping Tradition)
پیدایش ارگانیک از بستر Prolog: زبان ارلنگ به صورت کاملاً تدریجی در آزمایشگاه کامپیوتر شرکت اریکسون و ابتدا به عنوان یک گویش افزونه بر روی زبان منطقی Prolog متولد شد . با ورود رابرت ویردینگ (Robert Virding)، فرآیند بازنویسی و تکامل مداوم زبان در قالب یک پاسکاری سنتی و پیدرپی میان او و جو آرمسترانگ شکل گرفت . روش کار آنها به صورت همبرنامهنویسی سریال (Serial Pair Programming) بود؛ به طوری که یکی از آنها دو تا سه هفته روی کدی کار میکرد و سپس آن را برای دیگری میفرستاد .
- تضاد فلسفی سازنده (سادگی در برابر عمومیت): روند توسعه ارلنگ در این دوره، مبتنی بر یک تضاد فلسفی عمیق اما به شدت سازنده میان جو و رابرت بود :
- فلسفه یونیکس جو (The Unix Philosophy): آرمسترانگ هر بار که کد را دریافت میکرد، تلاش میکرد تمام بخشهای غیرضروری را هرس کند و برنامه را کوتاهتر، فشردهتر و برای حل مسئلهی فعلی، خاصتر (Specific) سازد . از نظر او، یک برنامه باید فقط و فقط کار محوله را انجام دهد و نه هیچ چیز دیگر .
- فلسفه تعمیم رابرت (Generality): ویردینگ کدهای جو را میگرفت و تلاش میکرد آنها را به ساختارهای عمومیتر (General) تبدیل کند . او معتقد بود برنامه باید ابتدا کلی پیادهسازی شود و سپس مسئله فعلی به عنوان یک حالت خاص از آن ساختار عمومی اجرا گردد . این تداخل دیدگاهها و چرخش مداوم پایگاه کد بین این دو نهایت، در هر چرخه کیفیت مهندسی زبان را به شکلی استثنایی ارتقا داد .
تأثیرپذیری از نیازهای لایه مخابراتی (Telephony Requirements): تیم توسعه هر هفته با مهندسان مخابرات و تلفن اریکسون جلسه برگزار میکردند تا مسائل دنیای واقعی این صنعت را بفهمند . ارزیابیهای اولیه نشان داد که توسعه پروتکلهای تلفن با ترکیب پرولوگ و کدهای تفننی آنها به شدت کند است و سیستم برای ورود به لایه تولید باید ۷۰ برابر سریعتر شود .
- خلق مفسر و ماشین مجازی بومی: آرمسترانگ کامپایلر ارلنگ را با پرولوگ نوشت که کدهای بایتکد تولید میکرد . او تلاش کرد ماشین مجازی ارلنگ را با زبان C بنویسد؛ اما مایک ویلیامز (Mike Williams) با دیدن آن گفت: «این کثیفترین و فاجعهبارترین کدهای C است که در کل زندگیام دیدهام!» . در نهایت، ویلیامز ماشین مجازی را با کدهای C دقیق توسعه داد و جو کامپایلر را روی پرولوگ نگه داشت . با خودمیزبانی کامپایلر ارلنگ و مستقل شدن آن از پرولوگ، ارلنگ رسماً به عنوان یک زبان برنامهنویسی مستقل و بومی متولد شد .
تفکر پیاممحور: حذف وضعیت مشترک و شگفتیِ کپی کردن دادهها (Shared-Nothing over Shared Memory)
- شگفتی کارایی کپیسازی دادهها (Data Copying): بزرگترین انتقاد جامعه مهندسی نرمافزار به معماری ارلنگ در ابتدا این بود که کپی کردن کامل دادهها در زمان ارسال پیام (به جای فرستادن آدرس اشارهگرها در حافظه مشترک) ترافیک شدیدی ایجاد کرده و سیستم را به شدت ناکارآمد میسازد . آرمسترانگ استدلال میکرد که این رویکرد اگرچه ممکن است هزینهبر باشد، اما برای تحقق پایداری مطلق و تحمل خطا (Fault Tolerance) غیرقابلاجتناب است . با این حال، با ظهور ریزپردازندههای چندهستهای مدرن، فیزیک سیستمها حقیقت دیگری را آشکار ساخت: در همروندیهای بالا، کپی کردن دادهها به مراتب سریعتر و کارآمدتر از بهاشتراکگذاری حافظه است! دلیل فنی این بود که در لایه حافظه اشتراکی، سربار ناشی از قفلها (Locks) کارایی را نابود میکرد . روی یک پردازنده هزار هستهای، اگر کدی یک قفل سراسری (Global Lock) ایجاد کند، کل هزار هسته ناچار به توقف میشوند؛ در حالی که در مدل ارلنگ، فرآیندها بدون وضعیت مشترک (Shared-nothing) و کاملاً ایزوله موازی پیش میروند .
باز کردن جعبههای سیاه: ضدیت با کلاسهای شیءگرا و لایههای انتزاعی مکرر (Opening Black Boxes & The Gorilla-Jungle Trap)
تلهی گوریل و جنگل در زبانهای شیءگرا: آرمسترانگ بازاستفاده از کد در زبانهای شیءگرا را یک ادعای واهی و شکستخورده میداند . او برای توصیف وابستگیهای شدید، ضمنی و پنهانی که شیءگرایی به برنامهنویس تحمیل میکند، از تمثیل معروفی استفاده میکند: «شما یک موز میخواهید؛ اما آنچه در عمل دریافت میکنید، یک گوریل تنومند است که موز را در دست دارد و پشت سر او کل جنگل است!» . بر خلاف این مدل، کدهای تابعی خالص (Referentially Transparent) به دلیل نداشتن وضعیتِ تغییرپذیر پنهان، به راحتی کپی و در هر جایی بازاستفاده میشوند.
- آزادی مهندسی با صحبت مستقیم با پروتکلها: اشتباه استراتژیک مهندسان نوین از نظر آرمسترانگ، ترس از لایههای زیرین انتزاع و ایمان کورکورانه به کتابخانهها و APIهای سنگینِ واسط است . او ثابت کرد که با کنار گذاشتن این جعبههای سیاه و صحبت مستقیم با لایه پروتکل از طریق سوکتها، مسائل پیچیده بسیار تمیزتر حل میشوند :
- پروتکل X Windows: به جای کار با کتابخانههای پیچیده فراخوانی بازگشتی (Callbacks)، او مستقیماً سوکت را باز کرد و بایتهای بومی ارلنگ را به این لایه فرستاد؛ او دریافت پروتکل X Windows از حدود ۱۰۰ پیام تشکیل شده که تنها ۲۰ پیام برای انجام تمام کارهای گرافیکی و پنجرهایِ مورد نیاز کافی است .
- پروتکل Postscript: او مرز انتزاع سیستم حروفچینی خود را روی Postscript قرار داد . او به جای کار با ابزارهای گرافیکی خستهکننده که تراز کردن فلشها در آنها دستآزار است، برنامهای نوشت که مستقیماً کدهای دقیق Postscript تولید میکرد .
- عقبگرد تاریخی با زبان C: آرمسترانگ سازوکار لولهها (Pipes) در یونیکس را سادهترین و عالیترین روش برای متصل کردن نرمافزارها میداند . او معتقد است مجبور کردن برنامهها به همزیستی در یک فضای حافظه مشترک و تکیه بر لایههای پیچیده API، کارهای اساساً ساده را به کابوسهای مهندسی با کارایی فکری بالا تبدیل کرده است .
مهارتهای فرامتنی: توانایی نگارش و رد آزمونهای پازلی در استخدام (Rigor, Writing, & Recruitment)
اولویت ادبیات و نگارش بر ریاضیات: به باور آرمسترانگ، توانایی بیان دقیق اندیشه و استدلال استوار به زبان طبیعی، مهمترین مهارت پیشنیاز برای ساخت برنامهنویسان بزرگ است . او تأکید میکند که دانشگاهها باید فارغالتحصیلانی تربیت کنند که توانایی نگارش و استدلال بالایی داشته باشند؛ زیرا برنامهنویسی در حقیقت برگردان همین تفکر کلامی دقیق به کدهای ماشین است .
ارزیابی در مصاحبه بر پایه کدهای شخصی و دفاع از آن: او سوالات پازلی و معماهای ذهنی سریع را در فرآیند استخدام به شدت رد میکند ؛ چرا که مهندسان برجستهای (مانند یکی از هکرهای ارشد ارلنگ با دکتری ریاضی که مانند مته الماسه روی سنگ خارا در عمق سیستم نفوذ میکرد اما کدهای منبع را به شدت آرام مطالعه میکرد) ممکن است در این آزمونهای سریع شکست بخورند . رویکرد استخدامی او، درخواست کدهای شخصی داوطلب و بررسی نحوه مواجهه و اشتیاق او برای حل مسائل واقعی است .
فصل هفتم: سایمون پیتون جونز (Simon Peyton Jones)
بخش نخست: از کد ماشینِ دهدهی تا جادوی انتزاعی ترکیبکنندههای S-K
سایمون پیتون جونز یکی از بنیانگذاران زبان برنامهنویسی Haskell (در سال ۱۹۸۷)، ویراستار گزارش تجدیدنظرشدهی استاندارد Haskell 98، و معمار و توسعهدهنده اصلی کامپایلر GHC (Glasgow Haskell Compiler) است . او شعار معروف و غیررسمی هسکل یعنی «دوری از موفقیت به هر قیمتی» (Avoid success at all costs) را به این زبان داد تا بتواند بدون فشار تجاری زودهنگام، ساختار آن را به کمال برساند . پیتون جونز که همواره میان کارایی عملی و زیبایی تئوریک تعادل برقرار ساخته، مسیر متفاوتی را در تاریخ مهندسی نرمافزار پیموده است .
۱. خاستگاه و یادگیری زودهنگام: کامپیوترهای ۱۰۰ خانهای و سحرگاه ریزپردازندهها (The Decimal Machine Code)
پیتون جونز در دورانی برنامهنویسی را آغاز کرد که شرکت اینتل به تازگی نخستین ریزپردازنده جهان (4004) را عرضه کرده بود . در آن زمان، مدرسهاش به یک کامپیوتر آزمایشی شرکت IBM (که از قطعات مازاد مِینفریمها ساخته شده بود) دسترسی پیدا کرد . شرایط فنی کار با این ماشین فوقالعاده چالشبرانگیز بود:
- فقدان کامل حافظه دائمی (No Permanent Storage): سیستم فاقد هرگونه دیسک یا رسانه ذخیرهسازی بود؛ در نتیجه برنامهنویس ناچار بود با هر بار روشن کردن دستگاه، کل برنامه را به صورت دستی وارد کند .
- حافظه محدود ۱۰۰ کلمهای: کل ظرفیت حافظه سیستم به ۱۰۰ خانه حافظه محدود میشد که هر خانه میتوانست یک عدد دهدهی ۸ رقمی را در خود جای دهد (این فضا هم برای نگهداری کد و هم دادهها مشترک بود) .
- کد ماشینِ دهدهی بدون اسمبلر: هیچ واسط متنی یا نویسه ASCII وجود نداشت . ورودی از طریق یک صفحه لمسی خازنی ۲۰ دکمهای انجام میشد و خروجی تنها روی یک صفحه تلویزیون کوچک به صورت مقادیر عددی ثباتها و خانههای حافظه به نمایش درمیآمد . کدهای ماشین مستقیماً به صورت عددی (مثلاً عدد ۶۵ برای دستور بارگذاری مجدد) وارد میشدند .
نخستین برنامه جدی و خلاقانهای که پیتون جونز روی این سختافزار نوشت، ابزاری برای محاسبه ریشه دوم اعداد ۲۴ رقمی با استفاده از الگوریتم تقریب نیوتن-رافسون بود . او با افتخار به یاد میآورد که این برنامه دقیقاً ۹۹ خانه حافظه را اشغال کرد و تنها یک خانه حافظه خالی در کل سیستم باقی گذاشت . این محدودیت فیزیکی شدید، ذهن او را برای صیانت دقیق از منابع سیستم و بهینهسازی دقیق الگوریتمها از همان سنین ۱۵ سالگی آموزش داد .
۲. کشف آکادمیک در کمبریج و هک سختافزار در دوران دانشجویی (Hardware Hacking & Elaborate BCPL Compiler)
پیتون جونز برای تحصیل در رشته ریاضیات وارد دانشگاه کمبریج شد . با این حال، او فضای ریاضیاتی آنجا را به دلیل حضور ریاضیدانان فوقالعاده نابغه بسیار دشوار دید و مسیر خود را به سمت علوم الکترونیک (معادل مهندسی برق) کج کرد .
- ساخت رایانههای دستساز با آیسیهای TTL: او و دوست صمیمیاش توماس کلارک، با خرید پردازندهها و تراشههای سری 7400 TTL، اقدام به سیمکشی و ساخت دستی کامپیوترها کردند . در آن دوران، بزرگترین گلوگاه آنها هزینه سرسامآور چاپگرها و مانیتورها بود که فراتر از توان مالی دانشجویی بود؛ به همین دلیل کامپیوترهای آنها معمولاً فاقد مانیتور یا پرینتر بومی بودند و از مکانیسم نوار کاست بسیار ساده برای ذخیرهسازی نیمهپایدار استفاده میکردند .
- پروژه ناکام کامپایلر BCPL و درس بزرگ مقیاس: در همان سالها، پیتون جونز با زبان BCPL روی سیستم مِینفریم کمبریج (سیستم Phoenix) برنامهنویسی میکرد . او و دوستش تصمیم گرفتند یک کامپایلر بسیار پیچیده و فرامدرن برای یک زبان خودساخته به زبان BCPL بنویسند . از آنجا که BCPL فاقد سیستم تایپ بود، آنها یک سیستم تایپ دستی روی کاغذهای چاپی بسیار بزرگ با ترسیم دهها جعبه و فلشهای اتصالی میان آنها اختراع کردند . این پروژه به دلیل جاهطلبی بیش از حد هرگز به پایان نرسید، اما اولین رویارویی پیتون جونز با مسئله مقیاس (Problems of Scale) در نرمافزار بود؛ جایی که فهم کل پایگاه کد فراتر از گنجایش ذهن برنامهنویس میرفت و نیاز مبرم به مستندسازی بلندمدت احساس میشد .
۳. گذر از صنعت ابزار دقیق و ورود نامتعارف به کادر علمی دانشگاه (Transition to Academia)
پس از فارغالتحصیلی و گذراندن دوره یکساله دیپلم عالی علوم کامپیوتر در کمبریج (که تنها تحصیلات رسمی او در این رشته بود)، او وارد صنعت شد و در یک شرکت بسیار کوچک ابزار دقیق و مانیتورینگ صنعتی مشغول به کار گردید :
- توسعه سیستمعامل بیدرنگ در لایه سختافزار: در این شرکت، او یک سیستمعامل کنترل بیدرنگ (Real-time OS) برای سنجش وزن زغالسنگ روی تسمهنقاله توسعه داد . او این سیستمعامل را به زبان PL/Z (زبانی شبیه به Algol) روی یک ریزپردازنده Z80 و تحت سیستمعامل Chromix (یک نسخه تقلیلیافته از Unix) نوشت .
- ورود بدون مدرک دکترا به دانشگاه: پیتون جونز در سال ۱۹۸۲/۱۹۸۳ به شکل عجیبی و بدون داشتن مدرک دکترا (PhD) یا حتی کوچکترین سابقه آموزش پژوهشی، به عنوان مدرس در دانشگاه UCL (دانشگاه لندن) استخدام شد . علت این استخدام، کمبود شدید مهندسان کامپیوتر با سابقه صنعتی در آن سالها بود . او با طنز از روزهای آغازین تحقیق خود یاد میکند: «هیچ ایدهای نداشتم که چطور باید تحقیق کنم؛ در اتاقم مینشستم و با یک مداد تراشیدهشده و کاغذ سفید، ساعتها به دیوار زل میزدم تا یک ایده بزرگ به ذهنم خطور کند، اما هیچ اتفاقی نمیافتاد!» .
۴. تولد تفکر تابعی: افسون کلوژرهای بدون نشت و معجزه ترکیبکنندههای S-K (The S-K Combinators Inspiration)
دو رویداد تئوریک بزرگ در سالهای پایانی حضور در کمبریج، مسیر ذهنی پیتون جونز را برای همیشه به سمت برنامهنویسی تابعی خالص (Pure Functional Programming) تغییر داد:
- ساخت لیست دوطرفه بدون عوارض جانبی (Pure Linked Lists): در آخرین سال تحصیل، او در یک دوره کوتاه آموزشی با تدریس آرتور نورمن شرکت کرد . نورمن در این کلاس اثبات کرد که میتوان یک لیست پیوندی دوطرفه (Doubly Linked List) را در یک زبان تابعی خالص و بدون نیاز به ایجاد هیچگونه عارضه جانبی (Mutation/Side-effects) یا تغییر مستقیم آدرسهای حافظه پیادهسازی کرد . این موضوع ذهن پیتون جونز را تکان داد و او را متقاعد ساخت که برنامهنویسی تابعی یک تفکر تفننی برای مسائل کوچک نیست، بلکه یک حمله همهجانبه و انقلابی به کل فرآیند نوشتن نرمافزار است .
- شکوه ریاضی ترکیبکنندههای S-K: رویداد دوم، خواندن مقالات دیوید ترنر درباره S-K Combinators بود . این ترکیبکنندهها نشان میدادند که چطور میتوان محاسبات فوقالعاده پیچیده لامبدا (Lambda Calculus) را تنها به سه عملگر بنیادی ریاضی یعنی S و K و I ترجمه و اجرا کرد . این کشف که میتوان ریاضیات محض را مستقیماً به دستورالعملهای سختافزاری ترجمه کرد، به شدت او را به وجد آورد؛ به طوری که دوستان صمیمی او در کمبریج بلافاصله سختافزاری به نام SKIM (SKI Machine) را برای اجرای مستقیم این دستورات در لایه پردازنده ساختند . مقاله کلاسیک جان بکوس با عنوان «آیا برنامهنویسی میتواند از سبک فون نویمان رها شود؟» نیز کاتالیزور نهایی او برای تعهد کامل به این پارادایم نوین شد .
تکامل زبان هسکل، معجزه ارزیابی تنبل و پارادایم خلوص (The Evolution of Haskell & The Purity of Laziness)
ارزیابی تنبل به عنوان ضامن پاکدستی سیستم (Lazy Evaluation as a Catalyst for Purity): سایمون پیتون جونز معتقد است که بزرگترین موهبت ویژگی ارزیابی تنبل (Lazy Evaluation)، بیش از آنکه یک ابزار محاسباتی جالب باشد، این بود که کل تیم طراحی را مجبور کرد تا زبان هسکل را به صورت کاملاً خالص (Pure) و عاری از هرگونه عوارض جانبی (Side-effects) نگه دارند . در یک زبان مشتاق (Eager/Call-by-value)، به راحتی میتوان توابعی با عوارض جانبی پنهان (مانند نوشتن روی صفحه یا دستکاری متغیر سراسری) نوشت، زیرا ترتیب اجرا کاملاً شفاف و مشخص است . اما در یک زبان تنبل، زمان دقیق ارزیابی یک عبارت غیرقابلپیشبینی است و به نحوه مصرف داده توسط کدهای دیگر بستگی دارد . اگر توابع هسکل اجازه داشتند عوارض جانبی داشته باشند، چاپ یک عبارت ساده روی صفحه یا خواندن از دیسک دچار آشفتگی و رفتارهای کاملاً تصادفی و غیرقابلاعتماد میشد . در نتیجه، تنبلی آنها را به سمت خلوص مطلق سوق داد .
مزیت ماژولار بودن در جداسازی تولیدکننده از مصرفکننده: با تکیه بر مقاله معروف جان هیوز با عنوان «چرا برنامهنویسی تابعی اهمیت دارد»، پیتون جونز توضیح میدهد که ارزیابی تنبل قویترین ابزار برای ساخت کدهای پیمانهای (Modular) است . این ویژگی به برنامهنویس اجازه میدهد که فرآیند تولید داده (Generator) را کاملاً از فرآیند مصرف آن (Consumer) جدا کند . برای مثال، در بازی شطرنج، میتوان تابعی نوشت که تمام حرکتهای ممکن را به صورت یک درخت بینهایت تولید کند، و تابع دیگری به صورت مجزا تنها بخشهای مورد نیاز را برای الگوریتم مینیماکس فیلتر و مصرف کند، بدون آنکه نگران سرریز حافظه یا اتلاف چرخههای پردازنده برای تولید شاخههای استفادهنشده باشیم . همچنین در سطح محلی، تعریف ساختارهای شرطی و محلی پیچیده (در بندهای
where) بسیار سادهتر میشود، زیرا کدهای بلااستفاده هرگز ارزیابی نخواهند شد .
مهار معضل ورودی/خروجی و ظهور منجی مونادها (Monads & The I/O Breakthrough)
بحران ورودی/خروجی در سالهای نخست: در سالهای اولیه، عدم امکان استفاده از عوارض جانبی در هسکل منجر به بروز یک بنبست جدی در برقراری ارتباط با دنیای واقعی شده بود . برای سالها، کل برنامه هسکل صرفاً به عنوان تابعی تعریف میشد که یک رشته ورودی (Input String) را میگرفت و یک رشته خروجی (Output String) تولید میکرد . برای انجام کارهای پویا، توسعهدهندگان ناچار بودند فرمانهای خود را درون رشته خروجی کدگذاری کنند تا توسط یک مفسر خارجیِ ناخالص (که پیتون جونز آن را «مفسر شیطانی» یا Evil Interpreter مینامد) اجرا شوند و پاسخ دوباره به پشته ورودی هسکل بازگردد . این مدل چرخشی بسیار شکننده بود و مصرف زودهنگام پاسخها به سرعت به بنبستهای سیستمی (Deadlocks) منجر میشد .
کشف مونادها؛ ادغام خلوص و امپراتوری رفتارهای دستوری: ظهور مفهوم ریاضیاتی مونادها (Monads) در اوایل دهه ۹۰ میلادی، این بنبست تاریخی را شکست . مونادها به هسکل اجازه دادند تا کدهای امپراتوری و دستوری (Imperative) را به شکلی کاملاً کنترلشده و ایمن درون یک کالبد تابعی خالص کپسولهسازی کند . پیتون جونز به طنز به توصیف شوالیه سفید در داستان آلیس در سرزمین عجایب اشاره میکند که طرحی برای رنگ کردن ریشها به رنگ سبز و استفاده از بادبزنی بزرگ برای پنهان کردن آنها داشت؛ او مونادها را به مثابه همان بادبزن بزرگ میداند که عوارض جانبی و کارهای ورودی/خروجی را در پشت خود پنهان میکنند تا خلوص ریاضیاتی زبان آسیب نبیند . امروزه مونادها نه تنها مسئله ورودی/خروجی را حل کردهاند، بلکه به عنوان هماهنگکنندههای اصلی در مدیریت خطاها، ناهمگامی و همروندی ایفای نقش میکنند .
انقلاب حافظه تراکنشی نرمافزاری (Software Transactional Memory - STM)
برتری مطلق بر مدل سنتی قفلها و متغیرهای شرطی: پیتون جونز معتقد است که برای برنامهنویسی همروند چندنخی روی دیتاسنترهای چندهستهای، حافظه تراکنشی نرمافزاری (STM) به طور کامل مدلهای قدیمی مبتنی بر قفلها (Locks) و سمافورها را مغلوب میسازد و برنامهنویسان باید قفلها را برای همیشه فراموش کنند . پیچیدگی قفلگذاریهای چندگانه در دنیای واقعی به قدری بالاست که حتی سادهترین ساختارهای داده (مانند پیادهسازی همروند یک صف دوطرفه با قفل مجزا برای هر گره) فراتر از ذهن مهندسان عادی بوده و در سطح مسائل تحقیقاتی دانشگاهی قرار میگیرد . اما با استفاده از STM، این مسئله دوباره به یک تمرین ساده دانشجویی تبدیل میشود؛ زیرا برنامهنویس صرفاً عملیات درج و حذف خود را پیاده کرده و آن را درون یک بلوک اتمیک (
atomic) قرار میدهد .ترکیبپذیری (Compositionality)؛ برگ برنده STM: بر خلاف سیستمهای سنتی که ترکیب دو قطعه کدِ قفلگذاریشدهی صحیح به سرعت منجر به بروز بنبست (Deadlock) میشود، تراکنشهای STM کاملاً ترکیبپذیر هستند . پیتون جونز ابداع دو متد بنیادی را در هسکل تشریح میکند : ۱.
retryبرای انسداد درون تراکنش: اگر شرطی (مثلاً موجودی کافی در حساب بانکی مبدأ) برقرار نباشد، تراکنش بدون مسدود کردن ترد، موقتاً کنار رفته و به محض تغییر در خانههای حافظه مورد نظر، دوباره به صورت خودکار تلاش میکند . ۲.orElseبرای انتخاب میان تراکنشها: به توسعهدهنده اجازه میدهد بگوید: «این تراکنش را انجام بده، و اگر مسدود شد یا با خطا مواجه شد، آن تراکنش دیگر را امتحان کن» . نکته جالب این است که این متدها برای اولین بار در بستر پاک و بدون مزاحمت هسکل کشف و پیادهسازی شدند و سپس مهندسان جاوا تلاش کردند آنها را به دنیای امپراتوری خود منتقل کنند .انزوا و اصول استدلال ترتیبی (Transactional Isolation): بزرگترین هدیه فکری STM به مهندسی نرمافزار، امکان استدلال ترتیبی (Sequential Reasoning) درباره کدهای همروند است . به دلیل تضمین انزوای تراکنشها (Isolation)، برنامهنویس در زمان نوشتن یک تراکنش، فرض را بر این میگذارد که هیچ ترد دیگری به صورت همزمان دادهها را دستکاری نمیکند . او انحصاری بودن شرایط را بررسی کرده، فرضیات (Invariants) را حفظ میکند و در صورت بروز هرگونه خطا یا استثنا، کل تراکنش بدون به جا گذاشتن هیچ اثری سقط (Abort/Rollback) میشود که این امر پایداری دادهها را در شرایط بحرانی تضمین میکند .
پایداری کدهای بزرگ مقیاس و سیستم تایپ intermediate در GHC
نقش سیستم تایپ ایستا در نگهداری بلندمدت (Maintenance): پیتون جونز در بحثهای داغ پیرامون زبانهای پویا و ایستا، از سیستمهای تایپ غنی دفاع میکند . او معتقد است سیستم تایپ بیش از آنکه در زمان نوشتن کدهای اولیه به کار بیاید، در زمان نگهداری (Maintenance) و بازآرایی (Refactoring) سیستمهای بزرگی که سالها از عمر آنها میگذرد حیاتی است . در کامپایلر GHC، او بارها تغییرات بنیادی در ساختارهای داده پرکاربرد اعمال کرده و با تکیه بر خطاهای کامپایلر، تمام آدرسها و کدهای آسیبدیده را در سراسر برنامه شناسایی و اصلاح نموده است؛ فرآیندی که در زبانهای پویا بدون ایجاد کوه بزرگی از تستهای شکننده عملاً غیرممکن است .
زبان میانی تایپدار (Typed Intermediate Representation) در GHC: یکی از ویژگیهای متمایز معماری کامپایلر GHC این است که زبان میانی آن (Intermediate Language) بر خلاف زبان مبدأ، فاقد سیستم استنتاج تایپ (Type Inference) است . در این لایه، همهچیز به صورت صریح با تایپهایشان تزیین شدهاند . این تصمیم معماری به آنها اجازه میدهد تا پس از هر فاز بهینهسازی و بازنویسی کد توسط کامپایلر، کل درخت نحو را دوباره تایپچک کنند تا مطمئن شوند بهینهسازهای کامپایلر، معنای منطقی کد کاربر را خراب نکرده و هیچ باگی به کدهای نهایی ماشین تزریق نشده است .
فصل هشتم: پیتر نورویگ (Peter Norvig)
بخش نخست: از اصلاح الگوریتم معلم تا گریز از «مهندسیِ آیبیام»
پیتر نورویگ مدیر تحقیقات گوگل (و پیش از آن مدیر کیفیت جستجوی گوگل)، رئیس سابق بخش علوم محاسباتی در مرکز تحقیقاتی ناسا (NASA Ames)، نویسنده کتابهای مرجعی چون Artificial Intelligence: A Modern Approach، و یکی از برجستهترین متفکران و هکرهای دنیای هوش مصنوعی و زبان لیسپ است . برخلاف ساختارهای آکادمیک خشک، نورویگ نگاهی به شدت عملگرا، تجربی و متمایل به «هنرِ ظریفِ هک صمیمانه» دارد .
۱. خاستگاه و کشف زودهنگام اشتباهات مراجع (Early Shuffling & Christopher Strachey’s Bug)
ورود پیتر نورویگ به دنیای برنامهنویسی در سال ۱۹۷۲ یا ۱۹۷۳ روی یک ماشین PDP-8 در دبیرستان رخ داد . نخستین جرقه نبوغ الگوریتمی او در زمان به چالش کشیدن روش تدریس معلمش نمایان شد :
- اصلاح الگوریتم بُر زدن ورقها: معلم دبیرستان الگوریتمی برای بر زدن کارتها ارائه داد که در آن، دو کارت به صورت تصادفی انتخاب و جابهجا میشدند و یک بیتوکتور مشخص میکرد کدام جابهجا شده است تا زمانی که همه جابهجا شوند . نورویگ بلافاصله متوجه شد این روش به دلیل احتمال انتخاب مکررِ کارتهای قبلی ممکن است هرگز متوقف نشود (پیچیدگی زمانی بیپایان یا نامنظم) . او به طور مستقل الگوریتم خطی و مرتبه \(O(n)\) (معروف به الگوریتم کِـنوت یا فیشر-یتس) را برای جابهجایی ترتیبی کارتها ارائه کرد و با وجود دفاع معلم از روش فرسایندهی خود، نورویگ دریافت که مراجع علمی و معلمان نیز همواره عاری از خطا نیستند .
- کشف باگ در مقاله کریستوفر استرچی: او در همان سنین نوجوانی در مجله Scientific American مقالهای کلاسیک از کریستوفر استرچی (یکی از بنیانگذاران مهندسی نرمافزار) درباره نوشتن برنامهی دوز/شطرنج با یک زبان فرضی کاغذی خواند . نورویگ در بازخوانی مدرن آن مقاله متوجه باگی در امضای تابع
make-moveشد؛ جایی که در متن توضیح داده شده بود تابع یک پارامتر (وضعیت صفحه) میگیرد اما در کد پیادهسازی، پارامتر دومی به نام عمق جستجو (depth) اضافه شده بود بدون اینکه متن مستندات اصلاح شود؛ درسی تاریخی برای نورویگ که نشان داد ناهماهنگی مستندات و کدهای واقعی حتی در عالیترین سطوح آکادمیک رخ میدهد .
۲. فرار از مهندسی آیبیام در دانشگاه کمبریج و برکلی (Majoring in Math, Not IBM)
نورویگ ریاضیات کاربردی را در دانشگاه به عنوان رشته اصلی برگزید و از انتخاب مهندسی کامپیوتر امتناع کرد :
- مخالفت با تحصیل بر پایه معماری سختافزار شرکتها: در آن دوران (دهه ۷۰)، گذراندن الزامات رشته کامپیوتر شبیه به «تحصیل در رشته آیبیام» بود . دانشجویان ناچار بودند معماری پردازندههای IBM 360، سیستمعاملهای اختصاصی آنها و زبان اسمبلی انحصاری آیبیام را یاد بگیرند که از نظر نورویگ کاری کسالتبار و فاقد خلاقیت مهندسی بود . او ترجیح داد در دپارتمان ریاضی بماند و تنها درسهای کامپیوتر مورد علاقه خود را انتخاب کند .
- چارهاندیشی در زمان کمبود حافظه (Game of Life): نخستین برنامه خلاقانه او، پیادهسازی بازی زندگی کانوی (Game of Life) روی تلهتایپ با کاغذ زرد بود . به دلیل محدودیت شدید حافظه و عدم امکان تعریف آرایههای چندبعدی در بیسیکِ آن ماشین، او مجبور شد با بررسی مستقیم رجیسترها و دستکاری اعداد در مبنای دهدهی، وضعیت چندین نسل از سلولها را به صورت فشرده در یک متغیر ذخیره کند تا بتواند ۵ نسل را به صورت همزمان در کنار هم چاپ کند؛ تجربهای که او را با بهینهسازیهای فیزیکی در ابعاد کوچک آشنا کرد .
۳. گذار به مهندسی صنعتی و درک اهمیت پدیدهای به نام «تیم» (The Transition to Industrial Settings)
پس از فارغالتحصیلی، نورویگ دو سال در شرکتی در کمبریج کار کرد که توسط مهندسان پروژه آپولو در Draper Labs تأسیس شده بود . او پس از خستگی از فرآیندهای اداری، مجدداً به دانشگاه برکلی برگشت تا دکتری خود را دریافت کند . بزرگترین درسهای او در انتقال از محیط دانشجویی به صنعت شامل موارد زیر بود:
- شکستن مرز برنامهنویسی انفرادی: در دانشگاه، کار تیمی به عنوان «تقلب» شناخته میشد؛ اما در صنعت، نورویگ متوجه شد که هیچ برنامهنویسی نمیتواند کل پشته سیستم را به تنهایی در ذهن داشته باشد . برنامهنویس صنعتی باید یاد بگیرد به انتزاعهای نوشتهشده توسط دیگران اعتماد کند و ارتباطات اجتماعی قوی با همکاران، مشتریان و مدیران برقرار سازد .
- هکِ گرامر در محیط مرده (The Parser Hack): در یک پروژه، آنها پارسری نوشتند که گرامر مشخصی را پردازش میکرد . پس از تحویل سیستم به مشتری، گرامر تغییر کرد در حالی که آنها دیگر به ماشینهای یونیکسِ فرانتاند دسترسی نداشتند . نورویگ مجبور شد مستقیماً جداول باینری پارسر کامپایلشده را مهندسی معکوس کرده و با تغییر دستی کدهای پرش (Jump States) در سورس کامپایلشده، گرامر جدید را بدون نیاز به کامپایل مجدد روی سیستم مشتری اعمال کند .
۴. متدولوژی ترکیبِ قطعات در برابر نوشتن از صفر (Assembling vs. Writing from Scratch)
نورویگ معتقد است ماهیت مهندسی نرمافزار برای نسل جدید به شدت تغییر کرده است :
- برنامهنویسی به مثابه چسباندن لولهها (Glue Code): امروزه دانشجویان برای ساخت یک سایت، نیازی به نوشتن موتور وب ندارند؛ آنها قطعات ارائهشده توسط Ruby on Rails، ابزارهای مدیریت محتوای Drupal، اسکریپتهای پایتون و ابزارهای آماری آماده را به هم متصل میکنند . در این پارادایم، درک عمیق اینترفیسها (واسطها) و شیوه ارتباط ماژولها بسیار حیاتیتر از دانستن تمام زوایای پیادهسازی داخلیِ یک بسته نرمافزاری است .
- خطر شجاعت بدون درک عمیق (The Bravery vs. Security Trap): او از «ترسزدایی» نسل جدید ستایش میکند که بدون درک کل سیستم، سورسهای گوناگون را دانلود و اجرا میکنند؛ اما هشدار میدهد که یک برنامهنویس عالی نمیتواند در این سطح سطحی بماند . او باید فراتر از سناریوهای موفق، موارد شکست (Failure Cases)، پایداری لایه شبکه، و سناریوهای تست مخرب را به طور دقیق فرموله کند .
نقد متدولوژیهای صلب، مهندسی ناسا در برابر هک گوگل و هنر بازنویسی بمبافکن
۱. نقد صراحت تفکر TDD و تلهی حل جدول سودوکو (The Sudoku TDD Trap)
پیتر نورویگ معتقد است که نقش اصلی تستنویسی، اصلاح و کشف خطاهای سیستم (Error Correction) است، نه هدایت فرآیند طراحی و معماری نرمافزار (Driving Design) . او رویکرد افراطی توسعه تستمحور (TDD) را که در آن برنامهنویس پیش از درک مسئله، ابتدا یک تست کلی برای خروجی نهایی مینویسد و سپس گامبهگام سیستم را جلو میبرد، رد میکند؛ زیرا این روش تنها برای مسائل سادهای کاربرد دارد که پاسخ نهایی آنها از پیش تعیینشده و بدیهی است .
او برای اثبات ادعای خود به داستان جالب یکی از مبلغان سرشناس TDD اشاره میکند که تلاش داشت یک حلکننده سودوکو (Sudoku Solver) بنویسد :
- این استادِ TDD کار خود را با تعریف کلاسها و نوشتن زنجیرهای از تستهای واحد آغاز کرد و پنج مطلب متوالی در وبلاگ خود منتشر ساخت که در آنها کدهای تست به درستی پاس میشدند . اما او در نهایت نتوانست برنامه را کامل کند و شکست خورد؛ زیرا ایده و الگوریتمی برای حل مسئله اصلی نداشت .
- در مقابل، نورویگ با اتکا به دانش هوش مصنوعی خود میدانست که حل این مسئله نیازمند ترکیب دو الگوریتم کلاسیک «انتشار محدودیت» (Constraint Propagation) و «جستجوی بازگشتی» (Recursive Search/Backtracking) است . او با ترکیب این دو مفهوم، به سرعت برنامه را بدون نیاز به Blundering (کورمالکورمال رفتن در تاریکی) نوشت .
- نورویگ نتیجه میگیرد که تستنویسی بسیار عالی است و او امروزه بیش از گذشته تست مینویسد ؛ اما واقعیت این است که اگر توسعهدهنده متدولوژی و الگوریتم حل مسئله را نداند، نوشتن هزاران تست نیز او را به پاسخ نهایی نخواهد رساند . فرآیند طراحی ابتدا به تفکر عمیق درباره ساختار قطعات نیاز دارد و پس از مشخص شدن قطعات، تفکر تستنویسی برای بررسی حالتهای مرزی و تعاملات آنها آغاز میشود .
۲. ضعفهای ذاتی UML و سطح انتزاع سیستمها در گوگل (UML & System-level Description)
نورویگ از ابزارهای طراحی نموداری مانند UML بیزار است . استدلال فنی او بر این فرض استوار است که اگر برنامهنویس نتواند طرح خود را درون خودِ زبان برنامهنویسی توصیف کند، این نشاندهنده ضعف بزرگ آن زبان است .
از نظر او، سطح توصیف معماری در پروژههای عظیمی مانند گوگل کاملاً با پروژههای سنتی متفاوت است:
- در گوگل، طراحان به جای درگیر شدن با جزئیات توابع و تعاملات کلاسها، در سطح ماشینها و رَکهای سرور (Machines & Racks) فکر میکنند . مسئله اصلی، چگونگی شکستن و موازیسازی کارهای عظیم روی هزاران سرور و استفاده از ابزارهایی مانند جدولهای هش توزیعشده است .
- در این سطح از مهندسی، معماری سیستم عموماً در قالب نثرهای ساده (Prose) یا کشیدن نقشه سرورها روی وایتبورد توصیف و ارزیابی میشود . این مستندات سپس به بازبینی مهندسان باسابقه میرسد تا گلوگاههای کارایی (مانند نیاز به نصب یک لایه کش با اندازه مشخص برای کاهش ترافیک تکراری) پیش از شروع فرآیند بیلد شناسایی شوند .
۳. قانون منحنی S و مهار کمالگرایی کاذب (The S-Curve & Diminishing Returns)
یکی از چالشهای مکرر در مهندسی نرمافزار، وسوسه حل مسائلی است که هنوز وجود ندارند . برنامهنویسان به دلیل اشتیاق به ابراز خلاقیت یا تمایل به بستن و نهایی کردن کار، تمایل دارند راهحلهای به شدت فرامدرن و همهجانبه ارائه دهند .
نورویگ این چالش را با منحنی S (شکل S) توضیح میدهد :
- در فرآیند تکامل یک محصول، زمانی که پروژه به ۸۰ یا ۹۰ درصد پیشرفت میرسد، نرخ بازگشت سرمایه (ROI) به شدت افت میکند و سیستم وارد فاز بازدهی نزولی (Diminishing Returns) میشود .
- در این مرحله، رفتن از ۹۵ درصد به ۱۰۰ درصد کمال روی یک ویژگی، هزینه پردازشی و فکری عظیمی میطلبد؛ در حالی که ۱۰۰ کار زمینمانده دیگر در پایین منحنی (با پیشرفت صفر درصد) وجود دارند که تشنهی منابع هستند و بازگشت سرمایه بسیار بالاتری برای مشتری یا سازمان به همراه خواهند داشت .
- یک مهندس عملگرا باید کمالگرایی کاذب را مهار کند و متوجه باشد که «بهترین، دشمنِ خوب است» ؛ او باید آگاهانه تصمیم بگیرد که چه زمانی توسعه یک ویژگی را متوقف کرده و منابع را به سمت بخشهای حیاتیتر هدایت کند .
۴. تقابل فرهنگ مهندسی ناسا و هک چابک گوگل (NASA Engineering vs. Google Hacking)
تجربه مدیریت نورویگ در هر دو قطب صنعت (ناسا به عنوان نماد سازمانهای حیاتی و گوگل به عنوان نماد شرکتهای وبمحور) تفاوتهای ساختاری عمیقی را آشکار میسازد :
- فرموله کردن ترس در ناسا (Fatal Failures): در ناسا، اولین شکست معمولاً آخرین شکست است و منجر به نابودی فضاپیما یا از دست رفتن جان انسانها میشود . در نتیجه، مهندسان ناسا (که عمدتاً مهندسان هوافضا و سیستمهای کنترل هستند و نه مهندسان نرمافزار) به شدت نسبت به نوآوریهای نرمافزاری بیاعتماد هستند . آنها کدهای خطی ساده را درک میکنند اما با دیدن یک حلقه تکرار تعجب کرده و با دیدن یک دستور شرطی (Branch) درون آن حلقه به وحشت میافتند؛ زیرا تحلیل این ساختارها با استفاده از معادلات دیفرانسیل سیستمهای کنترل غیرممکن است .
- فلسفه انتشار زودهنگام در گوگل (Launch Early and Often): در گوگل، هزینه شکست ناچیز است؛ اگر باگی وجود داشته باشد، سیستم به راحتی به دیتاسنترهای دیگر منتقل میشود و کاربران قدیمی آسیب چندانی نمیبینند . این ویژگی به گوگل اجازه میدهد تا فرهنگ چابکِ «لانچ سریع و متوالی» را پیاده کند
- مذهبِ کدریویو در گوگل: با وجود این چابکی، انضباط شدیدی در لایه ثبت کد در گوگل حاکم است . هیچ برنامهنویسی (حتی افرادی مانند گیدو ون راسوم یا کن تامپسون) اجازه ندارد بدون بازبینی صریح کد توسط یک همکار ارشد و دریافت گواهی تأیید استایل، کدی را به مخزن اصلی تزریق کند . جالب اینجاست که گیدو ون راسوم در اولین پروژههای خود در گوگل، ابزار توزیعشده و پیشرفتهای را برای بهینهسازی و رنگآمیزی این فرآیند بازبینی کدهای جدید توسعه داد .
- پارادوکس «نرمافزار ارزان اما باگی» در هوافضا: نورویگ ادعای گرانقیمت بودن کدهای شاتل فضایی (مانند هزینه ۱۵۰۰ دلاری به ازای هر خط کد بدون باگ) را تایید میکند، اما معتقد است ناسا ممکن است با کدهای ارزانتر اما باگیتر در کنار واسطهای کاربری بهتر عملکرد بهتری داشته باشد . دلیل فنی او این است که ناسا به دلیل ترس از دستکاری کدهای پرواز، هرگز رابط کاربری مانیتورهای فضانوردان را تغییر نمیدهد . در نتیجه، در زمان بروز خطاهای الکتریکی آبشاری، صدها پیام خطا روی مانیتور فضانورد سرازیر میشود بدون اینکه سیستم خلاصه یا منشأ اصلی را نشان دهد . فضانوردان باید ماهها در شبیهسازها آموزش ببینند تا این آبشار پیامها را به صورت دستی دیباگ کنند؛ در حالی که نرمافزار به راحتی میتواند این کار را انجام دهد اما ناسا برای جلوگیری از بروز باگهای جدید، ترجیح میدهد بار پردازش را به ذهن فضانوردان منتقل کند .
۵. کالبدشکافی ناکامیهای مأموریتهای مریخ ۹۸ (Analysis of Mars ‘98 Failures)
نورویگ به عنوان تنها دانشمند کامپیوتر در پنل تحقیقاتی بررسی علل سقوط فضاپیماهای مریخ در سال ۱۹۹۸ حضور داشت . او ریشههای این فاجعه تاریخی (از جمله اشتباه فاحش محاسباتی تبدیل واحد نیوتن به پوند-نیرو در فضاپیمای Mars Climate Orbiter) را ترکیبی از خطاهای سازمانی و نادیده گرفتن فرآیندهای مهندسی میداند :
- شکاف ارتباطی ناشی از برونسپاری: پروژه به صورت مشترک بین آزمایشگاه JPL در پاسادنا و شرکت لاکهید مارتین در کلرادو توسعه مییافت . مهندسان این دو تیم به دلیل فواصل فیزیکی هرگز با یکدیگر ناهار نمیخوردند و ارتباط صمیمانهای نداشتند .
- تلهی ایمیلهای غیررسمی در برابر سیستم باگتراک: در طول پرواز، مهندسان متوجه ناهماهنگی در دادههای ناوبری شدند و یک مهندس جوان در ایمیلی غیررسمی به تیم دیگر هشدار داد که محاسبات اندکی انحراف دارند . اما به دلیل نفوذ بوروکراسی، این گزارش هرگز وارد سیستم رسمی ثبت باگ (Bug-tracking System) نشد . در نتیجه، JPL تصور کرد لاکهید مارتین مشکل را حل کرده و لاکهید نیز گمان کرد چون JPL دیگر پیگیری نمیکند، حتماً موضوع بیاهمیت بوده است؛ تا اینکه فضاپیما به دلیل انحراف محاسباتی در اتمسفر مریخ سوخت .
۶. تکنیک دیباگ بمبافکنی: هنر دور ریختن و بازنویسی (The Bomb-the-House Debugging Technique)
در جعبه ابزار خطایابی نورویگ، در کنار ابزارهای ردیابی (Tracing) و دیباگرهای تعاملی، یک رویکرد تخریبی بسیار کارآمد وجود دارد که او آن را «انداختن بمب روی خانه برای نابودی سوسکها» مینامد :
- هرگاه او با باگی به شدت مبهم مواجه شود که ریشههای آن به کدهای کثیف و پیچیده گره خورده است، به جای وقتگذرانی برای خطایابی گامبهگام، کل آن چند صد خط کد را پاک کرده و از نو بازنویسی میکند .
- او اقرار میکند که گاهی بابت این رفتار احساس گناه میکند؛ چرا که بدون درک علت دقیق باگ، آن را از بین برده است . اما از نظر مهندسی و مدیریت زمان، این کار نه تنها باگ را نابود میسازد، بلکه منجر به تولید کدهایی به مراتب تمیزتر، سادهتر و بدون وصلههای پچ زشت گذشته میشود .
۷. پیشبینیکننده عجیب استخدامی گوگل (The Paradoxical Interview Predictor)
گوگل همواره دادههای استخدامی خود را با روشهای آماری دقیق بررسی میکند تا رابطه میان عملکرد افراد در مصاحبهها را با کارایی واقعی آنها در شرکت پس از دو سال بسنجد . نورویگ به یکی از عجیبترین و متناقضترین یافتههای این تحقیق اشاره میکند :
- امتیاز ۱ به عنوان پیشبینیکننده موفقیت: در مقیاس نمرهدهی مصاحبهها (از ۱ تا ۴)، کاندیداهایی که در حداقل یکی از جلسات مصاحبه خود بدترین نمره ممکن یعنی ۱ را دریافت کرده بودند، در درازمدت کارایی و موفقیت به مراتب بالاتری نسبت به بقیه در گوگل نشان دادند !
- تفسیر مهندسی پارادوکس: دریافت نمره ۱ به معنای رد شدن قطعی ۹۹ درصد کاندیداها است . اما اگر کاندیدایی با وجود داشتن نمره ۱ در نهایت استخدام شده باشد، به این معنی است که مصاحبهکننده دیگری در مجمع استخدامی چنان شیفته نبوغ و مهارت خاص او شده که با تمام وجود روی میز کوبیده، از اعتبار خود مایه گذاشته و اصرار داشته که شرکت نباید این فرد خلاق را به خاطر ضعف در یک بخش از دست بدهد . این شور و اشتیاق حامیِ او و نبوغ ناهمگونِ کاندیدا، قویترین رابطه مستقیم را با موفقیتهای چشمگیر بعدی او در گوگل داشت .
فصل نهم: گای استیل (Guy Steele)
بخش نخست: چندزبانگیِ مطلق، طراحی Scheme و فلسفه تکامل زبانها
۱. چندزبانگی بیرقیب و خاستگاه رسوبکرده در زیرزمین مدرسه (The Programming Polyglot)
گای استیل نمونه بارز یک چندزبانه واقعی (Polyglot) در دنیای برنامهنویسی است؛ او تجربه توسعه جدی با بیش از ۲۰ زبان برنامهنویسی مختلف از جمله COBOL، Fortran، اسمبلی IBM 1130، زبان ماشین PDP-10، لیسپ (در گویشهای گوناگون نظیر Maclisp, Common Lisp, Scheme)، بیسیک، تا زبانهای مدرنی چون Java، C++، هسکل و زبان نوپای Fortress را در کارنامه خود دارد .
ورود او به دنیای رایانهها به شکلی کاملاً تصادفی در دوران تحصیل در دبیرستان Boston Latin School در سال ۱۹۶۸ رخ داد :
- کامپیوتر مخفی در زیرزمین: یکی از همکلاسیهایش به او خبر داد که یک مینیکامپیوتر IBM 1130 در زیرزمین مدرسه نصب شده است (اهدایی از سوی Vincent Learson، یکی از فارغالتحصیلان بخش مدیریتی IBM) . استیل با دیدن یک برنامه ۵ خطی فرترن فوراً مجذوب این ماشین شد .
- یادگیری سهگانه زودهنگام: او در پاییز ۱۹۶۸ زبان Fortran و در زمستان همان سال اسمبلی IBM 1130 را آموخت . سپس در بهار ۱۹۶۹، با دریافت یک بروشور تبلیغاتی و کاغذ تلهتایپ Selectric از کنفرانس کامپیوتر بوستون، به صورت خودآموز زبان APL را فراگرفت .
۲. گسست از ریاضی محض و آزمون استخدامی دو ساعته در امآیتی (The Great Escape to Lisp)
استیل برای تحصیل در دانشگاه میان گزینههای MIT، هاروارد و پرینستون مردد بود و تمایل قلبیاش به MIT بود . اما مدیر مدرسه با این استدلال کلاسیک که «پذیرفته شدن در هاروارد را نباید فدای رفتن به انستیتوهای فنی (Tech) کرد»، خانواده او را تحت فشار گذاشت تا استیل را به هاروارد بفرستند .
مسیر علمی او در هاروارد دستخوش تحولات بزرگی شد:
- تسلیم در برابر فضاهای باناخ: او ابتدا با هدف ریاضیات محض وارد دانشگاه شد، اما به قول خودش با رسیدن به مبحث فضاهای نامتناهیِ باناخ (Infinite-dimensional Banach spaces) دریافت که فاقد شهود ریاضی لازم در این سطح است و رشته خود را به ریاضیات کاربردی (که علوم کامپیوتر در آن زمان بخشی از آن در دانشکده مهندسی بود) تغییر داد .
- آزمون استخدامی بیل مارتین: او در زمان تحصیل در هاروارد، به عنوان برنامهنویس پارتتایم به امآیتی رفت . استیل در دفتر بیل مارتین (مدیر پروژه Macsyma) حاضر شد و اعلام کرد که مایل به کدنویسی لیسپ است . مارتین یک برگه امتحان لیسپ دو ساعته به او داد . استیل پس از دو ساعت پاسخها را تحویل داد و مارتین پس از ده دقیقه بررسی گفت: «استخدامی!» .
- نگهداری مفسر Maclisp: او تمام دوران تحصیل خود را به عنوان کارمند تماموقت (در تابستانها) و پارتتایم (در طول ترم) در امآیتی گذراند و به عنوان همکار نزدیک JonL White، مسئولیت نگهداری و توسعه مفسر زبان Maclisp را بر عهده گرفت . او بعدها در MIT دکتری خود را دریافت کرد و در آنجا به همراه جرالد ساسمن، در قالب مجموعه مقالات مشهور به The Lambda Papers، زبان Scheme را اختراع و تعریف نمود .
متدولوژی کالبدشکافی کدهای بیگانه و خوانش CACM (Reading Code & The CACM Journey)
۱. مذهبِ خواندن خطبهخطِ مراجع کلاسیک و مجله CACM
از نظر استیل، بزرگترین مرجع آموزشی او در دوران نوجوانی، کتاب هنر برنامهنویسی رایانه اثر دونالد کنوت بود که آن را تقریباً خطبهخط خوانده و تمرینهایش را حل کرده بود .
فرآیند مطالعاتی منحصربهفرد او در کتابخانه Lamont دانشگاه هاروارد شکل گرفت :
- او در ساعتهای بیکاری صبحگاهی خود، مجله Scientific American را از انتها به ابتدا (برای خواندن ستون بازیهای ریاضی مارتین گاردنر) و مجله معتبر Communications of the ACM (CACM) را از اولین شماره منتشرشده در سال ۱۹۵۷ به سمت جلو مطالعه میکرد .
- در سال ۱۹۷۲، کل تاریخچه این مجله تنها ۱۵ سال بود و استیل توانست کل مقالات فنی آن را (که شامل ایدههای درخشان و کوتاهی مانند تکنیکهای نوین هشینگ در قالب کدهای اسمبلی ۷۰۹۰ بودند) به طور کامل پلو کند . او معتقد بود در آن دوران، یک برنامهنویس کنجکاو میتوانست امیدوار باشد که کل پشته و ابعاد علوم کامپیوتر جهان را در ذهن خود داشته باشد؛ امری که امروزه غیرممکن است .
۲. مهارت خواندن کدهای بزرگ بر پایه فرضیه «مسیر اجرای دستورات» (Desk-checking)
هنگامی که استیل با یک پایگاه کد عظیم و ناآشنا (مانند ویرایشگر Emacs) مواجه میشود، به جای استفاده از دیباگرهای پویا، رویکرد بررسی دفتری (Desk-checking) یا خواندن ذهنی و استنتاجی کد را ترجیح میدهد .
پروتکل او برای درک کدهای غریب به این شرح است:
- یافتن یک نقطه تعامل ملموس: او یک فرآیند یا دستور ساده و کاربردی را که کارکرد آن را در عمل میشناسد انتخاب میکند؛ مثلاً دستور «حرکت مکاننما به اندازه یک کاراکتر به جلو» در ویرایشگر .
- ردگیری مسیر فیزیکی اجرا (Execution Path): او این دستور را در سورسکد پیدا کرده و خطبهخط دنبال میکند تا با نحوه بازنمایی دادهها و ساختارهای درونی حافظه (مانند نحوه نگهداری بافر متنی) آشنا شود .
- توسعه پهنای باند ذهنی: پس از درک این بخش، او سناریوهای پیچیدهتر مانند «حرکت کاراکتر به عقب» یا «حذف یک خط» را دنبال کرده و لایههای انتزاعی را گامبهگام در ذهن خود بازسازی میکند .
- مخالفت با محیطهای IDE غیرخطی: استیل خواندن خطی کدها را ترجیح میدهد و معتقد است ابزارهای IDE به دلیل ماهیت پیوندی و گرافیکی خود (Jump around in a graph)، این اطمینان را از برنامهنویس سلب میکنند که آیا او واقعاً تمام بخشهای سیستم را دیده و خوانده است یا خیر . کد خوب باید مانند یک رمان از فالکنر یا همینگوی، یک داستان منسجم از ساختار خود را به خواننده ارائه دهد .
فلسفه طراحی واسطها، فاجعه هانک و مقاله نمادین Growing a Language (Interface Design & Growing a Language)
۱. مذهبِ طراحی واسط بر پایه تحلیل حالتهای مرزی (Interface-First Design)
استیل معتقد است طراحی نرمافزار در حقیقت همان طراحی اینترفیسهاست . او جمله مشهور فرد بروکس را بازنویسی کرده و میگوید: «اینترفیسهای سیستم خود را به من نشان دهید؛ من نیازی به دیدن کدهای شما نخواهم داشت زیرا کدهای واقعی چیزی جز افزونگی (Redundancy) نیستند» .
روش او برای ارزیابی قدرت یک اینترفیس بر دو اصل استوار است :
- تعمیم و عمود بودن (Generality & Orthogonality): اجزای اینترفیس باید با الگوهای مرسوم ریاضیاتی و استانداردهای تاریخی مطابقت داشته باشند؛ مثلاً در توابع تقسیم ریاضی، نباید جای مقسوم و مقسومعلیه را بر خلاف عادت دیرینه بشر تغییر داد .
- حل مسئله از روی حالتهای مرزی (Edge Cases): استیل با اتکا به نظریه آرایه Trenchard More در زبان APL استدلال میکند که «اگر در زمان طراحی واسط، فکری به حال حالتهای مرزی (مانند آرایههای تهی، مقادیر صفر یا حداقلی) بکنید، بخش میانی و بدنه اصلی سیستم معمولاً خودبهخود درست کار خواهد کرد» .
۲. فاجعه طراحی به نام «هانک» در مکلیسپ (The Hunk Disaster)
یکی از بزرگترین حسرتهای طراحی استیل، معرفی نوع داده جدیدی به نام هانک (Hunk) در سیستم Maclisp بود . در دهه ۷۰، پردازندههای PDP-10 تنها از یک فضای آدرسدهی بسیار کوچک ۱۸ بیتی پشتیبانی میکردند . در ساختار لیستهای پیوندی سنتی لیسپ، نزدیک به ۵۰ درصد از فضا صرفاً برای نگهداری ساختار اشارهگرهای لیست (اشارهگرهای کاراکتر و ارجاع بعدی) تلف میشد .
استیل برای صرفهجویی در حافظه، ساختار داده Hunk را طراحی کرد که مانند یک سلول Cons اما با داشتن بیش از دو اشارهگر مستقیم عمل میکرد و سربار نگهداری لیست را به شدت کاهش میداد . با این حال، او این کار را بزرگترین فاجعه طراحی عمر خود میداند؛ زیرا این تصمیم شتابزده، پیچیدگی شدیدی به مفسر و کامپایلر تحمیل کرد و یکپارچگی سهگانه و تمیز لیسپ را برای همیشه مخدوش ساخت .
۳. تکامل زبانها و زایش مفهوم Growing a Language
استیل در سخنرانی تاریخی خود در OOPSLA 1998 (با عنوان Growing a Language که آن را منحصراً با کلمات تکسیلابی نوشت تا سادگی رشد را در خود زبان اثبات کند)، تز جدیدی برای طراحی زبانهای برنامهنویسی ارائه داد :
- زبانهای بزرگ امروزی دیگر نمیتوانند توسط یک تیم کوچک و به صورت یکپارچه و یکباره طراحی شوند . جاوا در ابتدا به عنوان یک زبان کوچک برای جعبههای گیرنده دیجیتال تلویزیون (Set-top boxes) طراحی شد اما به دلیل عدم پیشبینی مکانیزمهای رشد اجتماعی، فرآیند تکامل آن در مواجهه با نیازهای وب با چالشهای شدیدی روبرو شد .
- لیسپ به دلیل برخورداری از سیستم ماکروهای قدرتمند و فرهنگ اجتماعی مبتنی بر رأی اکثریت، به راحتی به کاربران اجازه داد تا زبان را خودشان رشد دهند . در مقابل، Scheme به دلیل حاکمیت فرهنگ «وتوی تکنفره» (Blackball culture) که در آن همه باید با یک تغییر موافقت میکردند، مسیر رشد بسیار فرساینده و کندی را طی کرد . استیل در طراحی زبان جدید خود، Fortress، تلاش کرد فرآیندهای رشد اجتماعی را به اندازه ویژگیهای فنی در هسته زبان استانداردسازی کند .
بخش دوم: شهودهای شبانه، رمزگشایی از باگهای چهار میلیارد تایی و اثبات صوری همروندی (Guy Steele - Part 2)
۱. رویای نیمهشب و باگِ ناپیدای سیستم دکامپایلر IBM 1130 (The Sleep-Debugging Epiphany)
در دوران نوجوانی گای استیل، یک بار راهکار حل یک باگ فرساینده در هنگام خواب و در لحظه بیدار شدن به ذهن او الهام شد . او در حال نوشتن یک برنامه دکامپایلر (Decompiler) برای مطالعه سیستمعامل دیسک IBM بود تا بتواند دادههای باینری روی دیسک را به فرمتهای متنی، عددی و دستورالعملهای ماشین ترجمه کند .
- منشأ فنی خطا: او برای تبدیل کاراکترها، دادهها را به یک سری توابع بومی تبدیل کاراکتر تغذیه میکرد که یکی از آنها برای استفاده پس از خواندن کدهای فیزیکی از یک کارتخوان (Card Reader) طراحی شده بود . استیل یک پانویس بسیار کوچک و حیاتی را در سند مشخصات فنی (Specification) نادیده گرفته بود: «فرض بر این است که پیش از فراخوانی این پروسجر، بایتهای مرتبه پایینِ بافری که دادههای کارت در آن خوانده میشوند، همگی پاک (Clear) شده باشند» .
- کشف شهودی: از آنجا که این بیتهای مرتبه پایین پاک نشده بودند، سیستم به اشتباه اینگونه تفسیر میکرد که دادهها هنوز از کارتخوان فیزیکی واصل نشدهاند . استیل پس از چند روز تلاش بیثمر، در میانه شب ناگهان از خواب برخاست و متوجه شد که دقیقاً همین فرضیه پنهان در لایه اینترفیس را نادیده گرفته است . این واقعه اهمیت صیانت از مشخصات دقیق واسطها را برای همیشه در ذهن او حک کرد .
۲. کالبدشکافی ریاضی باگ تقسیم بزرگعدد (Bignum) بیل گاسپر (The Bignum Division Bug & Knuth’s Rare Paths)
یکی از درخشانترین تجربیات دیباگ استیل به زمان نگهداری سیستم Maclisp و مواجهه با گزارش خطای مهندس نابغه، بیل گاسپر (Bill Gosper) بازمیگردد . مکلیسپ از اعداد صحیح با دقت بینهایت (Bignums) پشتیبانی میکرد که سالها بدون مشکل در پروژههای سنگین ریاضی Macsyma استفاده شده و کاملاً پایدار فرض میشدند . با این حال، گاسپر گزارش داد که خارجقسمت تقسیم دو عدد بزرگِ تقریباً ۱۰۰ رقمی اشتباه است . او متوجه این خطا شده بود، زیرا میدانست خارجقسمت این دو عدد باید عددی بسیار نزدیک به مضرب اعشاری عدد پی (\(\pi\)) باشد .
- استراتژی ردیابی بر پایه تحلیل احتمالات کنوت: استیل متوجه شد که ردیابی گامبهگام این فرآیند بر روی اعداد ۱۰۰ رقمی به صورت دستی غیرممکن است . او کد اسمبلی بخش تقسیم را باز کرد و آن را با کتاب مرجع دونالد کنوت (Donald Knuth) تطبیق داد . در تشریح مراحل این الگوریتم در کتاب کنوت، پانویسی وجود داشت که اشاره میکرد: «این گام به ندرت و تنها با احتمال تقریبی ۱ در ۲ به توان اندازه کلمه ماشین (تقریباً یک بار در هر ۴ میلیارد بار اجرا) رخ میدهد» .
- تمرکز بر مسیرهای کمتکرار (Rarely Executed Paths): استیل با خود استدلال کرد که چون کتابخانه در طول سالها به خوبی تست شده است، پس باگ حتماً باید در همین مسیر بسیار کمتکرار پنهان شده باشد . این فرضیه درست از آب درآمد؛ او متوجه شد که در این مسیر فرعی، یک ساختار داده به درستی کپی نمیشد و عارضه جانبی (Side-effect) ناشی از آن، حافظه را خراب میکرد .
- تله باگهای چندگانه: استیل باگ را اصلاح کرد و کد را تحویل داد . اما یک هفته بعد، گاسپر با دو عدد بزرگتر برگشت و گفت تقسیم اینها نیز خراب است ! استیل با بازگشت به همان قطعه کد ۱۰ خطی متوجه شد که باگ دومی دقیقاً از همان جنس کپی نشدن دادهها در همان بخش وجود دارد . او با پاکسازی کامل آن بخش، سیستم را برای همیشه در برابر این باگ بیمه کرد و این درس بزرگ را گرفت که کدهای کمتکرار بهترین مأمن برای باگهای مخفی هستند و وجود یک باگ معمولاً نشانهای از وجود باگهای بعدی در همان ساختار است .
۳. نبرد ۲۵ ساعته برای اثبات صوری یک الگوریتم همروند به روش Owicki-Gries
استیل یکی از عمیقترین تحلیلهای خود را در زمان داوری و بازبینی یک مقاله علمی برای مجله معتبر Communications of the ACM (CACM) تجربه کرد . نویسنده مقاله، ریاضیدان برجسته دیوید گریس (David Gries) بود که تلاش داشت با استفاده از متدولوژی توسعهیافته توسط دانشجویش (سوزان اوویکی)، درستیِ ریاضیاتی یک الگوریتم زبالهروب موازی (Parallel Garbage Collector) را که ابتدا توسط ادسگر دیکسترا طراحی شده بود، به صورت صوری اثبات کند .
- پیچیدگی هولناک تداخلهای موازی: کل کد الگوریتم تنها در نصف صفحه جا میشد، اما باقی مقاله تماماً به اثبات ریاضی درستی آن اختصاص داشت . در یک برنامه موازی، هر دستورالعمل در زمان اجرا پتانسیل نقض انباشتهی فرضیات بقیه بخشها را دارد . روش Owicki-Gries برای مهار این مسئله، نیازمند متقاطعسازی و بررسی صوری (Cross-checking) تمام فرضیات در تکتک نقاط تعامل سیستم است .
- کشف باگ در اثبات ریاضی (Q.E.D. with Bugs): استیل بیش از ۲۵ ساعت زمان صرف کرد تا به صورت دستی تکتک فرمولها و مراحل اثبات ریاضی را گامبهگام Grinding و محاسبه کند . در جریان این کار، او به مراحلی برخورد که از نظر ریاضی غیرقابلحل بودند و از همین طریق متوجه شد که الگوریتم موازی حاوی یک باگ بسیار ظریف و نادر تعاملی است که اثبات صوری گریس آن را نادیده گرفته بود . گریس مقاله را پس از اصلاح کد و پس و پیش کردن دو دستورالعمل دوباره فرستاد و استیل ۲۵ ساعت دیگر را صرف تایید نسخه دوم اثبات صوری کرد تا سرانجام از درستی آن مطمئن شود . استیل تأکید میکند که هیچ تستی در جهان قادر به کشف این باگ موازی مبهم نبود و تنها با روش اثبات صوری و بررسی ریاضی متقاطع امکان شکار آن وجود داشت .
۴. کوتاه کردن کدهای بیل گاسپر پس از ۲۰ سال (The 20-Year Code Compression Victory)
لذتبخشترین موفقیت شخصی گای استیل در بهینهسازی، مربوط به یک قطعه کد بسیار ظریف از بیل گاسپر بود . گاسپر یک برنامه شگفتانگیز و بازگشتی ۱۱ کلمهای (کد ماشین) برای محاسبه همزمان سینوس و کسینوس بر روی یک معماری خاص نوشته بود که بر پایه فرمول ریاضی زاویه سهبرابر کار میکرد .
- استفاده دوگانه از دستور ماشین به عنوان ثابت ریاضی: استیل به مدت ۲۰ سال هر از گاهی به این برنامه ۱۱ کلمهای فکر میکرد . سرانجام پس از دو دهه، او به یک شهود فنی بینظیر دست یافت: او متوجه شد که با تغییر یکی از اپکدهای دستورات ماشین (Op-codes)، آن دستور بایتکد در لایه سختافزاری مقداری تولید میکند که از نظر ریاضی دقیقاً معادل با مقدار عدد ثابت ممیز شناور (Floating-point constant) مورد نیاز برای فرمول سینوس است . با این ترفند جادویی، او توانست آن کلمه را همزمان هم به عنوان دستورالعمل پردازنده و هم به عنوان ثابت ریاضی استفاده کند و برنامه ۱۱ کلمهای گاسپر را به ۱۰ کلمه کاهش دهد؛ دستاوردی مینیاتوری که او آن را یکی از زیباترین پیروزیهای مهندسی خود میداند .
فصل دهم: دن اینگالز (Dan Ingalls)
اگر آلن کی (Alan Kay) را پدر معنوی زبان اسمالتاک (Smalltalk) بدانیم، دن اینگالز بدون شک مادر این زبان است . آلن کی ایدهها و رؤیاهای بزرگ را در سر میپروراند، اما اینگالز کسی بود که آستینها را بالا زد و با نوشتن نخستین پیادهسازی اسمالتاک روی کاغذ و اجرای آن، این رؤیا را به یک واقعیت ملموس تبدیل کرد . او در طول مسیر حرفهای خود، پیادهسازی و توسعه هفت نسل مختلف از اسمالتاک (از اولین نمونههای اولیه تا سیستم مدرن و متنباز Squeak) را رهبری کرده است .
۱. خاستگاه علمی: از فیزیک محض تا رایانههای آنالوگ در هاروارد (Academic Origin & Analog Computers)
مسیر علمی دن اینگالز با روحیه یک «مخترع زیرزمینی» آغاز شد . او که دوران نوجوانی را به ساخت ابزارهای مختلف در زیرزمین خانهاش سپری کرده بود، فیزیک را به عنوان نزدیکترین رشته به روحیه اکتشافی خود برگزید و در سال ۱۹۶۲ وارد دانشگاه هاروارد شد . در هاروارد، دو تجربه محاسباتی، نگاه او را به جهان نرمافزار برای همیشه تغییر داد :
- جادوی فورترن: او در یک دوره آموزشی با زبان Fortran آشنا شد و از همان ابتدا شیفته این شد که چطور میتواند برنامهها را تا حد ممکن کوتاهتر و بهینهتر بنویسد .
- رایانههای آنالوگ و سیمکشی مستقیم تفکر: تجربه هیجانانگیزتر او در آزمایشگاه زیرزمین دانشکده و کار با رایانههای آنالوگ رقم خورد . این سیستمها فاقد نمایشگر یا کدهای متنی بودند و برنامهنویس باید با استفاده از یک پنل بزرگ سیمکشی (Patch Panel)، مدارها، انتگرالگیرها و مشتقگیرها را مستقیماً به یکدیگر متصل میکرد تا مسائل فیزیکی را به صورت زمانواقعی (Real-time) حل کند . این تعامل فیزیکی و بدون واسطه با جریان محاسبات، نخستین بذر تفکر تعاملی را در ذهن او کاشت .
۲. سمینار دونالد کنوت در استنفورد و ماجراجویی تجاری با پروفایلر کوبول (The COBOL Hash Table Adventure)
اینگالز برای ادامه تحصیل در رشته مهندسی برق وارد دانشگاه استنفورد شد، اما به سرعت به سمت علوم کامپیوتر متمایل گردید . نقطه عطف دوران تحصیل او در استنفورد، شرکت در کلاس دکتری دونالد کنوت با موضوع «اندازهگیری و تحلیل رفتار پویای برنامهها» بود :
- ابداع یک پروفایلر توزیعشده: اینگالز در جریان این سمینار، برنامهای توسعه داد که کدهای Fortran را دریافت کرده و شمارندههایی را در تمام نقاط انشعاب (Branch Points) کد تزریق میکرد . او این سیستم را ارتقا داد تا با استفاده از وقفه زمانسنج (Timer Interrupt)، میزان دقیق زمان واقعی صرفشده در هر بخش از کد منبع را به صورت آماری و بصری به کاربر نشان دهد . او با درک پتانسیل تجاری این ابزار، دکتری خود را در استنفورد نیمهکاره رها کرد تا شرکتی برای فروش این ابزار تأسیس کند .
- تفاوت رفتار مشتریان فورترن و کوبول: او برای بازاریابی ابزار خود به سراغ کاربران بزرگ فورترن رفت که عمدتاً پیمانکاران پروژههای علمی دولت بودند . با این حال، او با یک حقیقت تلخ مواجه شد: این شرکتها اساساً اهمیتی به کارایی برنامههای خود نمیدادند! هدف آنها برعکس، اثبات این بود که سیستمهای فعلیشان بیش از حد بارگذاری شدهاند تا بتوانند بودجه بیشتری برای خرید ابررایانههای گرانقیمت دریافت کنند . در مقابل، شرکتهای تجاری که از زبان COBOL استفاده میکردند، به شدت نیازمند بهینهسازی بودند .
- تنها جدول هش نوشتهشده با کوبول: اینگالز تصمیم گرفت همین سیستم پروفایلر را برای زبان کوبول بازنویسی کند . چالش فنی بزرگ این بود که روال جمعآوری آمار نهایی باید با همان زبانی نوشته میشد که برنامه اصلی با آن کامپایل شده بود تا بتواند در کنار آن بارگذاری شود . اینگالز با خنده به یاد میآورد: «برای نوشتن بخش تحلیل آمار نهایی، مجبور شدم یک جدول هش (Hash Table) را به طور کامل درون زبان کوبول پیادهسازی کنم؛ احتمالاً من تنها احمق در تاریخ کامپیوتر هستم که چنین کاری کرده است!» . این ابزار به موفقیت تجاری بزرگی دست یافت و اینگالز در دموهای خود به شرکتها نشان میداد که چطور در چند دقیقه اول استفاده، هزینهای بیش از قیمت خرید نرمافزار را در مصرف سرورها صرفهجویی میکنند .
۳. مهندسی محیط تعاملی روی مینیکامپیوتر Sigma 3 و کشف دنیای زیراکس پارک (The Path to Xerox PARC)
پس از موفقیت تجاری پروفایلر کوبول، اینگالز به صورت پارتتایم کار روی پروژههای مهندسی مختلف را آغاز کرد . او با مهندسی به نام جورج وایت آشنا شد که در پارک صنعتی استنفورد روی پروژه تشخیص گفتار (Speech Recognition) کار میکرد و به شدت نیازمند یک برنامهنویس بود .
- ساخت محیط سیستمعامل تعاملی شخصی: اینگالز کار با وایت را روی یک مینیکامپیوتر Sigma 3 آغاز کرد که محیطی به شدت محدود و مبتنی بر کارتهای پانچ داشت . او برای تسهیل کار خود، یک محیط محاسباتی کاملاً تعاملی و بومی روی این ماشین توسعه داد؛ او یک ویرایشگر متنی تعاملی با فورترن نوشت و سیستمی طراحی کرد که کاربران بتوانند کارهای خود را به صورت از راه دور از طریق ترمینال ثبت و اجرا کنند .
- تلاقی فیزیکی با آلن کی: جورج وایت مدتی بعد توسط مرکز تحقیقاتی معروف Xerox PARC استخدام شد تا پروژه تشخیص گفتار را در آنجا دنبال کند و از اینگالز خواست به عنوان مشاور با او همکاری کند . دفتر جدید آنها در زیراکس پارک دقیقاً در مقابل دفتر آلن کی (رئیس گروه تحقیقات یادگیری یا LRG) قرار داشت . اینگالز در زمان کار، مدام صداها و بحثهای هیجانانگیزی را که از اتاق آلن کی درباره مفاهیم انقلابی اسمالتاک و رایانههای شخصی آینده به گوش میرسید میشنید؛ این کشش ذهنی به قدری قوی بود که او به سرعت پروژه تشخیص گفتار را رها کرد و به تیم آلن کی پیوست .
۴. فلسفه رضایت آنی (Immediate Gratification) و موهبت بینظیرِ بیخبر بودن از لیسپ (The Missed Lisp Blessing)
یکی از اصول پایدار مهندسی دن اینگالز، تعهد مطلق او به ایجاد محیطهای برنامهنویسی پویا و مبتنی بر «رضایت و بازخورد آنی» (Immediate Gratification) است . او ریشه این نیاز ذهنی را به تجربههای زودهنگام کار با زبانهای مفسری مانند PL/I تعاملی و به ویژه زبان APL مرتبط میداند .
- برتری تفکر عبارتی بر تفکر دستوری (Expression-oriented vs. Statement-oriented): کار با APL اینگالز را با قدرت ارزیابی عبارات تعاملی آشنا کرد . او اشاره میکند که کل سنت زبانهای C ،C++ و جاوا، با وجود ادعای شیءگرایی، همچنان در بندِ تفکر صلب و قدیمی برنامهنویسی دستوری (Statement-oriented) هستند؛ در حالی که در محیطهای تعاملی، همهچیز باید در قالب ارزیابی پویا و زنده عبارات ریاضی معنا یابد .
- تلهی بلعیده شدن فرزندان لیسپ: آلن کی زمانی جمله معروفی را مطرح کرده بود: «لیسپ و اسمالتاک هر دو به قدری سیستمهای قدرتمند و کاملی هستند که فرزندان خود را میبلعند (They eat their children)» . اینگالز این تئوری را کاملاً تایید میکند :
- او اقرار میکند که در زمان ورود به زیراکس پارک، خوشبختانه هیچ آشنایی عمیقی با زبان لیسپ نداشت .
- اگر او لیسپ را به خوبی میشناخت، احتمالاً هرگز نیازی به ابداع اسمالتاک حس نمیکرد؛ او صرفاً تلاش میکرد تا با نوشتن ماکروها و ابزارهای فرعی، لایهای از اشیاء را به زور روی لیسپ سوار کند (همان کاری که بعدها در سیستمهای لیسپ رخ داد) .
- بیخبر بودن او از لیسپ، فضایی بکر و بیمانع برای خلاقیت خالص مهندسی در ذهن او ایجاد کرد تا سیستم اسمالتاک را از همان ابتدا و به صورت بومی بر پایه دو مفهوم خالص «اشیاء» (Objects) و «ارسال پیام» (Message Passing) طراحی کند .
- دفاع از تنوع اجتماعی در برابر کمالگرایی: اینگالز در پاسخ به منتقدانی که از اختراع مجدد چرخها در صنعت نرمافزار به دلیل جهل برنامهنویسان شکایت دارند، رویکردی بسیار آزادمنشانه (Embrace-diversity) دارد . او معتقد است اگرچه نادانی هزینههای مکرری به همراه دارد، اما مکانیسم تکامل طبیعی (Natural Selection) در نهایت ساختارهای ضعیف را هرس خواهد کرد؛ در حالی که تلاش برای تحمیل یک استاندارد واحد آکادمیک، جلوی جهشهای ژنتیکی و پدید آمدن نوآوریهای انقلابیِ پیشبینینشده را در آینده خواهد گرفت .
زایش اسمالتاک در تاروپود بـیسیک و ماجراجویی شش فاکتوریل (The BASIC Prototype & The Factorial Breadboard)
نخستین پیادهسازی زبان اسمالتاک (که نسخه پیشنمونه و آغازینِ محیط انقلابی Smalltalk-72 به شمار میرفت) در بستری توسعه یافت که امروزه به عنوان ضدِالگوی مطلق پویایی شناخته میشود: زبان BASIC . آلن کی سندی حاوی یک صفحه یادداشت کوتاه پیرامون فرضیات تئوریک این زبان تعاملی جدید به دن اینگالز داد و از او خواست صحت این مدل اجرایی را ارزیابی کند .
اینگالز بدون فوت وقت، فرآیند پیادهسازی را به سبک هکرهای عملگرا (یا به تعبیر خود او، به شیوه ساخت کیتهای الکترونیکی روی «برد بورد» یا Breadboarding) مستقیماً درون مفسر بـیسیک آغاز کرد :
- شبیهسازی ساختار حافظه: او برای شبیهسازی لایه آدرسدهی و تخصیص حافظه پویا، یک آرایه یکپارچه و بزرگ در بـیسیک تعریف کرد تا به عنوان بستر ذخیرهسازی دادهها و گرههای آدرس عمل کند .
- شبیهسازی پشته قاب فراخوانی: او ساختار دادهایِ معادل با قاب پشته (Stack Frame) را برای ردیابی زنجیره فراخوانی متدها درون همان آرایه از پیشتعریفشده مدلسازی کرد .
- فتح نخستین قلّه محاسباتی: هدف این نسخه نمایشی، محاسبات سنگین نبود؛ بلکه اینگالز تلاش داشت پویایی سیستم را بسنجد . اولین برنامهای که به صورت تعاملی و موفقیتآمیز روی این نمونه اولیه بـیسیک به اجرا درآمد، محاسبهی سادهی شش فاکتوریل (!6) بود . این پیروزی اگرچه کوچک به نظر میرسید، اما صحت فنی مکانیزم تعاملی جستجوی متغیرها در زمان اجرا (Dynamic Lookup) و خلق خودکار قابهای پشته را برای اولین بار در عمل اثبات نمود .
به محض تایید کارکرد این مدلِ پایهای، اینگالز یک نسخه به مراتب کاملتر را با اسمبلی پردازنده Data General Nova نوشت و با استفاده از آن به خطایابی و تثبیت ساختارهای پویای زبان پرداخت . با آغاز فرآیند ساخت سختافزار افسانهای Xerox Alto در زیراکس پارک، پایگاه کد اسمبلی Nova بلافاصله به معماری Alto منتقل شد و بدین ترتیب، پلتفرم رسمی Smalltalk-72 متولد گردید . نسخه اولیه Smalltalk-72 به دلیل ناپختگی و سربارهای رندرینگ به شدت کند اجرا میشد، اما بازنگریهای مداوم مهندسی به ویژه در لایه مفسر توانست کارایی آن را در نسخه دوم نزدیک به ۲۰ تا ۲۵ برابر سریعتر سازد .
کالبدشکافی چرخ دندههای BitBlt: معجزه به تصویر کشیدن پیکسلها در زیراکس پارک (The BitBlt Innovation)
بزرگترین گلوگاه گرافیکی مانیتورهای زیراکس آلتو، تضاد ذاتی میان ابعاد فیزیکی صفحه و ساختار فیزیکی حافظه رم بود :
- محدودیت تضاد پیکسل-کلمه: مهندسان مایل بودند صفحه نمایش را به عنوان یک ماتریس پیوسته از پیکسلها (مثلاً یک صفحه ۱۰۰۰ در ۱۰۰۰ پیکسلی) تصور کنند ؛ اما حافظه رم سیستم به صورت کلمات صلب ۱۶ بیتی سازماندهی شده بود .
- بحران انتقال مرزها: اگر برنامهنویس مایل بود یک بلوک گرافیکی کوچک ۴ پیکسلی را روی صفحه جابهجا کند، این پیکسلها در مقصد جدید ممکن بود با موقعیت قبلی کلمهی حافظه انطباق نداشته باشند (به طوری که بخشی از بلوک در کلمه اول حافظه و بخشی دیگر در کلمه دوم قرار گیرد) . رندر این جابهجایی نیازمند فرآیندهای فرساینده و دستی ماسکگذاری (Masking)، شیفتهای بیتی مکرر (Shifting) و بازنویسی کلمات حافظه بود که در عمل کارایی پردازنده را نابود میکرد .
اینگالز برای مهار این فاجعه رندرینگ، دو شب متوالی به تفکر عمیق و طراحی پرداخت و در نهایت ساختار جادویی BitBlt (Bit Block Transfer) را ابداع کرد .
1
2
3
4
5
6
آدرس منبع (Source Word) آدرس مقصد (Destination Word)
[ بایت ۱ ][ بایت ۲ ] [ بایت ۱ ][ بایت ۲ ]
\ / ^ /
\ / | /
V V | V
[ چرخدنده لغزان شیفتدهنده (Long Shifter) ]---> [ماسکگذاری]
تصویر ذهنی اینگالز برای حل این مسئله، یک مدل مکانیکی فیزیکی مانند چرخدندهها بود : او سیستم را مانند چرخدندهای متحرک تصور کرد که کلمات کامل را از منبع در حافظه برمیداشت، آنها را روی یک محور لغزانِ شیفتدهنده (Long Shifter) به اندازه تفاوت موقعیت مکانی شیفت میداد و بدون فوت وقت در مقصد تخلیه میکرد ؛ به طوری که در کل این فرآیند تنها یک بار عمل شیفت بیتی به صورت فیزیکی رخ میداد .
اینگالز فرضیات خود را ابتدا با زبان اسمالتاک پیادهسازی و تست کرد، سپس آن را به اسمبلی آلتو ترجمه نمود و در نهایت کدهای نهایی را مستقیماً به کدهای ماشین بسیار سریع در سطح میکروکد (Microcode) برای پردازنده Alto تبدیل کرد . با تکیه بر این راهکار سختافزاری، فرآیند ماسکگذاری بیتی و انتقال بایتها در میانه چرخههای طبیعی آدرسدهی حافظه پنهان شد و کارهای پیچیدهای چون اسکرول پنجرهها، تراز قلمهای نگارشی و نمایش منوهای پاپآپ با سرعت کامل گذرگاه حافظه (Full speed of memory) محقق شد .
از پارسر زمانِ اجرا تا ماشین بایتکدِ اسمالتاک-۷۶ (Smalltalk-76 Bytecode Engine)
بزرگترین گام تکاملی اسمالتاک، عبور از مفسر ساختارشکن Smalltalk-72 به سمت بستر مدرن Smalltalk-76 بود . در نسخه ۷۲، کل سورسکد سیستم به صورت زمانواقعی و پویا در حین اجرا پارس میشد (On-the-fly Parsing) که سربار پردازشی هنگفتی به سیستم تحمیل میکرد .
اینگالز برای غلبه بر این محدودیت، موتور بایتکدِ (Byte-code Engine) اسمالتاک-۷۶ را با مشخصات فنی زیر پایهگذاری کرد : ۱. سیستم مستقل کامپایل و نحو کلمات کلیدی (Keyword Syntax): او ساختار نحوی اسمالتاک را به یک فرمت از پیشکامپایلشونده مجهز کرد تا متدها پیش از اجرا به کدهای میانی عددی ترجمه شوند . ۲. محیط کاملاً بازتابی (Reflective Architecture): او سیستم را به بلوغ خود توصیفی رساند؛ به طوری که کلاسها و حتی قابهای پشته روی سیستم، به اشیاء بومی اسمالتاک (First-class Objects) تبدیل شدند . ۳. حل چالش ارزیابی از راه دور (Remote Evaluation): او ساختاری برای متغیرهای تعریفشده در لایههای بالا که باید در لایههای زیرین ارزیابی میشدند ابداع کرد که منجر به پدید آمدن بلوکها (Blocks) در اسمالتاک شد؛ این ساختار معادل با مفهوم Closure در سایر زبانهای برنامهنویسی است .
علت اصلی انتخاب مفسر بایتکد به جای کامپایل مستقیم به کدهای ماشین بومی، محدودیت شدید فضا در حافظه رم بود . مینیکامپیوترهای آلتو در آن دوران تنها از ۹۶ کیلوبایت حافظه رم پشتیبانی میکردند (که بعدها به سختی به ۱۲۸ کیلوبایت ارتقا یافت) . کدهای بایتکدِ اسمالتاک به دلیل غنای بالای معنایی در مقایسه با دستورات بومی ماشین بسیار فشردهتر و کوچکتر بودند که صیانت از حافظه را در آن شرایط سخت تضمین میکرد .
در این مسیر، اینگالز به شدت تحت تأثیر و الهامگرفته از مفسر بایتکدِ لیسپ نوشتهشده توسط پیتر دویچ (Peter Deutsch) قرار داشت . از آنجا که کدهای میکروکد Alto درون حافظه رم ویژه پردازنده بارگذاری میشدند، سیستم این قابلیت فرامدرن را داشت که با تغییر میکروکد به صورت پویا، مفسر بایتکدِ اسمالتاک را تخلیه کرده و مفسر لیسپ پیتر دویچ را جایگزین سازد .
حماسه خودمیزبانی در Squeak: ماشین مجازی که خود را به C ترجمه میکند (The Self-Hosting Miracle of Squeak)
در تمام نسخههای اسمالتاک (از نسخه ۷۲ تا عرضه تجاری نسخه ۸۰)، با وجود اینکه کامپایلر به زبان اسمالتاک نوشته شده بود، اما هسته اصلی ماشین مجازی (VM) برای اهدافِ کارایی همواره با زبانهای صلب خارجی مانند اسمبلی یا C نوشته میشد .
رویای دیرینه یعنی «اسمالتاکِ پیادهسازیشده در خودِ اسمالتاک» سرانجام با ابداع پروژه متنباز Squeak محقق شد :
- شبیهسازی و مهندسی ماشین مجازی زنده: اینگالز و همکارانش کل رفتار مفسر بایتکد را ابتدا به صورت یک کلاس و شبیهساز بومی درون محیط زنده اسمالتاک نوشتند . این رویکرد به آنها اجازه داد هر زمان که مایل به اعمال تغییری در موتور ماشین مجازی بودند، تغییرات را به صورت بلادرنگ در همان محیط اسمالتاک اِعمال، تست و دیباگ کنند .
- ترجمه مکانیکی به زبان C (The Transpilation Trick): چالش کارایی با یک شهود مهندسی حل شد: آنها یک کامپایلر ویژه نوشتند که پارسدرختهای (Parse Trees) کدهای اسمالتاکِ شبیهساز را مستقیماً به کدهای معادل به زبان C ترجمه کند . این کار از طریق یک کامپایلر فرعیِ محدود که پارسدرختها را در قالب نحو C چاپ میکرد، صورت پذیرفت .
- میراث تِـد کِـیلر: این تکنیک مینیاتوری مسبوق به سابقه بود؛ پیش از آن تِـد کِـیلر (Ted Kaehler) لایه مدیریت حافظه مجازی اسمالتاک را در این محیط نوشته و آن را به صورت خودکار به زبان BCPL ترجمه کرده بود . در نهایت، جان مالونی (John Maloney) این مبدل پویا را به ثمر رساند تا Squeak به سیستم پیشتاز خودمیزبانی بدل گردد که با فشردن یک دکمه، مفسر تعاملیاش را برای لایه تولید صنعتی به کدهای بومی کامپایل میکند .
فصل یازدهم: ال. پیتر دویچ (L. Peter Deutsch)
ال. پیتر دویچ (متولد ۱۹۴۶) یکی از اعجوبههای دنیای برنامهنویسی است که هک کد را از اواخر دهه ۵۰ میلادی و در سن ۱۱ سالگی آغاز کرد . او در دوران دبیرستان کدهای لیسپ را روی پردازنده PDP-1 در دانشگاه MIT پیادهسازی کرد و سیستمهای نوشتهشده توسط هکرهای باسابقه را بهبود بخشید . او بعدها در طول تحصیل در دانشگاه برکلی وارد پروژه انقلابی Project Genie (یکی از نخستین سیستمهای سیستمعامل زماناشتراکی) شد و پس از آن در زیراکس پارک (Xerox PARC)، بر روی سیستمهای Interlisp و ماشین مجازی اسمالتاک فعالیت کرد و تکنیک انقلابی کامپایل درجا (JIT Compilation) را توسعه داد . دویچ همچنین خالق نمایشگر بومی فایلهای پستاسکریپت یعنی Ghostscript است .
بخش نخست: نابغه نوجوان، هک لیسپ روی PDP-1 و خلق هسته زماناشتراکی برکلی (Project Genie)
۱. آغاز به کار از ۱۱ سالگی و جادوی سیستم نشانهها (Symbolic Language Appeal)
ورود پیتر دویچ به دنیای برنامهنویسی کاملاً تصادفی و در سن ۱۱ سالگی رقم خورد :
- یادداشت سرگردان شتابدهنده: پدر او که فیزیکدان بود، روزی یادداشتی فنی درباره محاسبات طراحی فیزیکی شتابدهنده الکترونی کمبریج (CEA) در دانشگاه هاروارد را به خانه آورد . دویچ که این برگه را روی میز کار پدرش دیده بود، با تماشای خطوط کوتاه کدهای رایانهای مجذوب آن شد و روحیه کنجکاویاش تحریک گردید .
- جاذبه سیستمهای نشانهای: دویچ با نگاهی به ۵۰ سال سابقه کاری خود اشاره میکند که او همواره شیفته زبانها و سیستمهای نمادین مکتوب (Denotative Symbols) بوده است ؛ به ویژه زبانهایی که علاوه بر داشتن بار معنایی، اجرای اصوات و کلمات در آنها تأثیرات عملی مستقیم در جهان فیزیکی (مانند حرکت ثباتها در حافظه کامپیوتر یا اجرای نتها در موسیقی) پدید میآورد .
- نخستین برنامه جالب: اولین برنامهای که او به صورت کاملاً مستقل و از روی اشتیاق شخصی نوشت (که دومین برنامهی کل عمر او بود)، ابزاری برای قالببندی خروجی اعداد ممیز شناور (Floating-point formatting) روی یک ماشین باینری بود ؛ کاری که در آن دوران به دلیل نبود کامپایلرهای سطح بالا و نوشتن مستقیم کدها به زبان اسمبلی روی ماشینهای پردازش دستهای (Batch-processing) یک چالش محاسباتی جدی به شمار میآمد .
۲. هک لیسپ ۱.۵ روی سختافزار محدود PDP-1 (The Teenage Lisp Prodigy)
دویچ در سن ۱۴ سالگی پای خود را به آزمایشگاههای مجهز دانشگاه MIT باز کرد و با ماشینهای افسانهای چون TX-0 و مدت کوتاهی بعد PDP-1 مواجه شد :
- کشف نسخه پلیکپی لیسپ ۱.۵: او نسخهای از دفترچه راهنمای برنامهنویسان Lisp 1.5 را پیدا کرد که به صورت دستی و با جوهر بنفش قدیمی پلیکپی شده بود . به دلیل علاقه قلبی او به مباحث منطق ریاضی، نحو و ساختار لیسپ برای او فوقالعاده زیبا و جادویی به نظر رسید .
- پیادهسازی مفرط لیسپ روی PDP-1: از آنجا که او به رایانه اصلی و بزرگ دانشگاه دسترسی نداشت، تصمیم گرفت شخصاً مفسر لیسپ را روی پردازنده کوچک PDP-1 بنویسد . این برنامه به قدری مینیاتوری و فشرده بود که کل پایگاه کد مفسر و اسمبلر آن تنها به چند صد خط کد خلاصه میشد .
- فرموله کردن منطق از روی ساختارهای داده: او برای این کار مجبور شد فراتر از توصیفات مفسر در کتابچه راهنما، لایههای پایینی سیستم شامل لغتسنج (Tokenizer)، خواننده (Reader) و از همه مهمتر کل ساختار فیزیکی ذخیرهسازی دادهها را در حافظه طراحی کند . دویچ این تجربه را شالوده رویکرد مهندسی پایدار خود میداند: «اگر شما ساختارهای داده (Data Structures) و فرضیات پایدار حاکم بر آنها (Invariants) را به درستی طراحی و اثبات کنید، کدهای برنامه در عمل خودبهخود نوشته خواهند شد» .
۳. پروژه انقلابی زماناشتراکی برکلی (Project Genie & The 10,000-Line Kernel)
با هجرت دویچ به دانشگاه کالیفرنیا، برکلی برای گذراندن دوره کارشناسی، او به سرعت جذب پروژه پیشتاز Project Genie شد :
- طراحی نخستین سیستم زماناشتراکی: هدف این پروژه ساخت یکی از نخستین سیستمهای محاسباتی زماناشتراکی (Timesharing) بر پایه مینیکامپیوترها بود . دویچ به عنوان مهندس اصلی، مسئولیت طراحی و نوشتن کل هسته سیستمعامل (Kernel) این ماشین را بر عهده گرفت .
- محتوای مهندسی کدهای هسته: این هسته نرمافزاری که نزدیک به ۱۰ هزار خط کد اسمبلی فوقالعاده بهینهشده بود، شامل سیستم مدیریت زمانبندی فرآیندها (Process Scheduler)، لایه مدیریت حافظه مجازی (Virtual Memory) و چندین سیستم فایل (File Systems) مجزا بود .
- تأثیر تاریخی بر پیدایش یونیکس: در همین زمان، کن تامپسون (Ken Thompson، خالق یونیکس) به عنوان دانشجوی تحصیلات تکمیلی در برکلی بر روی همین پروژه کار میکرد و معماری هسته طراحیشده توسط پیتر دویچ تأثیر عمیقی بر شکلگیری مفاهیم بعدی سیستمعامل یونیکس گذاشت . او همچنین در این دوره نسخه بومی ویرایشگر متنی تعاملی QED را برای این ماشین بازنویسی و پیادهسازی نمود .
۴. بلوغ فکری و انتقال به «تفکر واسطمحور» (Fractal Decomposition & Interface-First Thinking)
انتقال از پروژههای کوچک و انفرادی (مانند لیسپ PDP-1) به پروژههای سیستمی بزرگمقیاس (مانند سیستمعامل Project Genie)، تحول بزرگی در روش تفکر مهندسی دویچ پدید آورد :
- کشف مفهوم تجزیه فراکتالی (Fractal Decomposition): دویچ بر این باور است که نرمافزار ساختاری شبیه به فراکتال دارد که در آن فرآیند تجزیه به قطعات کوچکتر (Decomposition) در تمام سطوح سیستم با اصول یکسانی تکرار میشود . با این حال، او معتقد است تفاوت مهندسان بزرگ در این است که مسائل را در ابعاد کلان بررسی میکنند .
- اولویت طراحی واسط بر کدنویسی: در سیستمهای بزرگ، واسطها (Interfaces) نقش اول را بازی میکنند . دویچ تشریح میکند که در زمان طراحی و تفکر پیرامون یک ماژول جدید، اولین و حیاتیترین سوالاتی که ذهن او را درگیر میکنند به این شرح هستند: «اینترفیس این بخش با سایر لایههای بیرونی قرار است چگونه باشد؟ چه دادههایی وارد میشوند؟ چه دادههایی خارج میشوند؟ و مسئولیت انجام کار به صورت منطقی در کدام سمت این مرز انتزاع قرار دارد؟» . پس از تایید کامل مرزهای این واسط، او فرآیند توسعه درونی ماژول را آغاز میکرد .
شاهکار Ghostscript، مهندسی جیآیتی در اسمالتاک و هجرت به جهان نمادین موسیقی (L. Peter Deutsch - Part 2)
۱. معماری سیستمهای بزرگ: حماسه یکنفره Ghostscript و طراحی دادهمحور (The 50,000-Line Solo Epic)
پیتر دویچ بزرگترین شاهکار سیستمنویسی دوران کاری خود را پروژه Ghostscript میداند که تا سال ۱۹۹۹، تقریباً تمام خطوط کدهای آن را به تنهایی و بدون کمک خارجی توسعه داده بود . او این پروژه بزرگ را در سال ۱۹۸۸ و تحت سیستمعامل MS-DOS با یک نسخه بسیار سبک و خلاصهشده از ویرایشگر Emacs و یک کامپایلر سادهی C آغاز کرد . پایگاه کد اصلی این سیستم گرافیکی در نهایت به مرز ۵۰ تا ۱۰۰ هزار خط کد C رسید .
او در همان ابتدای پروژه، دو تصمیم حیاتی در لایه معماری اتخاذ کرد که پایداری ده ساله سیستم را تضمین نمود :
- تفکیک مطلق مفسر زبان از موتور گرافیکی: مفسر زبان PostScript هیچگونه اطلاعی از ساختارهای دادهی لایه رندرینگ گرافیکی نداشت و ارتباط میان این دو بخش صرفاً از طریق یک واسط برنامهنویسی (API) برقرار میشد . دویچ پیش از نوشتن حتی یک خط کد گرافیکی، مفسر کامل سطح ۱ پستاسکریپت را بر اساس عملگرهایی که ارجاع گرافیکی نداشتند، به طور کامل پیادهسازی کرد .
- طراحی واسط درایور (Driver Interface): لایه کتابخانه گرافیکی اگرچه الگوریتمهای رندرینگ منحنیها، قلمها و پیکسلها را مدیریت میکرد، اما کمترین آگاهی ممکن را از نحوه رمزگذاری فیزیکی یا ارسال پیکسلها به سختافزار نمایشگرهای گوناگون داشت .
- متدولوژی «طراحی دادهمحور» (Data-First Design): دویچ برای توسعه سیستم، پس از مطالعه کامل مستندات پستاسکریپت، بلافاصله شروع به نوشتن ساختارهای داده (Structs) در فایلهای هدر (
.h) کرد . او معتقد است: «اگر شما ساختارهای داده و فرضیات پایدار حاکم بر آنها (Invariants) را به درستی طراحی کنید، بخش عمدهای از کد منبع عملاً خودبهخود نوشته خواهد شد» . با معرفی و استانداردسازی استاندارد ANSI C، او دو ماه کامل را صرف اضافه کردن امضای صریح توابع (Function Signatures) به سراسر پایگاه کد Ghostscript کرد . جالب اینجاست که پس از ۱۰ سال و با وجود عبور از ۲ نسخه بازنگری بزرگ در مشخصات فنی پستاسکریپت، نزدیک به ۷۰ تا ۸۰ درصد از ساختارها و نامگذاریهای اولیه کدهای دویچ همچنان بدون تغییر باقی مانده بودند .
۲. مهندسی کامپایلر درجا (JIT) در شرکت ParcPlace
دویچ در شرکت ParcPlace (که از دل زیراکس پارک متولد شده بود) به عنوان مدیر علمی فعالیت میکرد . او در این شرکت بر روی موتور کامپایلر درجا (JIT Compiler) برای ماشین مجازی اسمالتاک کار کرد . کدهای این کامپایلر پویا که نزدیک به ۲۰ درصد از کل ساختار ماشین مجازی را شامل میشد، در حدود ۳ تا ۵ هزار خط کد C فوقالعاده بهینهشده بود که کدهای بایتکد اسمالتاک را در زمان اجرا مستقیماً به کدهای ماشین بسیار سریع سختافزار مقصد تبدیل میکرد .
۳. تلهی ارجاعها و نشانگرها در زبانهای مدرن (The Pointer/Reference Illusion)
دویچ عمیقترین چالش مهندسی نرمافزار معاصر را در وجود مفهومی به نام «اشارهگر» (Pointer) یا «ارجاع» (Reference) میداند . او ارجاعهای پویا در زبانهایی چون Java و Python را دقیقاً معادل با همان اشارهگرهای سختافزاریِ خطرناک در زبان C قلمداد میکند :
- عدم تغییر کیفی کارایی نرمافزار: او معتقد است از زمان عرضه زبان Simula-67 تا به امروز، پیشرفت کیفی چشمگیری در حوزه ابزارهای توسعه نرمافزار رخ نداده است؛ زیرا تمام زبانهای تجاری بزرگ امروزی همچنان بر پایه فرضیات صلب اشارهگرها بنا شدهاند [۴۳/43, ۱۲۶]. برنامههای جاوا و پایتون در مقیاسهای بزرگ، با وجود برخورداری از سیستم بازیابی خودکار حافظه (GC) و مصونیت از خراب شدن حافظه (Memory Corruption)، دقیقاً با همان مسائل ساختاری و بنبستهای فکریِ کدهای C دستبهگریبان هستند .
- نبود واسط برای توصیف الگوهای اشتراک داده (Sharing Patterns): بزرگترین ضعف زبانهای مدرن از نظر دویچ، فقدان هرگونه مکانیزم زبانی و نحوی برای توصیف، کنترل یا اثبات الگوهای دسترسی و اشتراکگذاری اطلاعات است . کارهایی مانند ذخیره یا پاس دادن یک ارجاع، عملیاتی محلی هستند اما در عمل یک گراف پیچیده سراسری (Global Graph) در حافظه تولید میکنند که تحلیل ایستای رفتار متغیرهای آزاد را ناممکن میسازد .
- راهکار برونرفت: او راهحل ایدهآل را در توسعه زبانهایی میداند که مرز سختی میان لایه تابعی خالص (Functional - بدون اشارهگر و وضعیت تغییرپذیر) و لایه تعاملی (بر پایه مدل اکتورها و کانالهای ارتباطی کپسولهشده و کاملاً کدر مانند زبان E) قائل شوند تا رفتار به اشتراکگذاری دادهها به وضوح تحت نظارت کامپایلر درآید .
۴. فرسودگی مهندسی، شکست صوری اثباتها و کشف راز پیانوهای وین (Burnout & Epiphany in Vienna)
در سال ۱۹۹۸، پیتر دویچ پس از سالها کار انفرادی فرساینده روی Ghostscript (که علاوه بر برنامهنویسی، شامل مدیریت تمام ایمیلها، پشتیبانی کاربران و کارهای اداری شرکت میشد) به شدت دچار فرسودگی شغلی (Burnout) گردید . او مدیریت کارها را واگذار کرد و در سال ۲۰۰۲ برای همیشه توسعه Ghostscript را کنار گذاشت .
او برای پیدا کردن مأموریت بعدی زندگی خود، به دعوت دوست قدیمیاش جی استروتر مور به دانشگاه تگزاس در آستین رفت تا پتانسیل سیستمهای اثبات صوری قضایا (Theorem Proving) را بر روی قابلیت اطمینان نرمافزارها بسنجد :
- دویچ ۲۰ باگ را به صورت تصادفی از سیستم ردیابی باگهای Ghostscript استخراج کرد و تکتک آنها را تحلیل نمود تا ببیند آیا سیستم اثبات قضیه میتوانست جلوی بروز آنها را بگیرد یا خیر .
- یافتهی ناامیدکننده: بررسیها نشان داد که اثبات درستی صوری این سیستم عملاً ناممکن یا فرساینده است؛ زیرا فرآیند صوریسازی (Formalization) و نوشتن دقیق مشخصات فنی رفتار سیستم برای تغذیه به موتور اثبات قضیه، خود نیازمند زحمت عظیمی کارگاهی (Herculean Job) بود که حجم کار آن فراتر از نوشتن خود نرمافزار میرفت .
- شهود فکری در وین (۲۰۰۳): در جریان یک سفر توریستی با شریک زندگیاش به وین در سال ۲۰۰۳، دویچ از موزه سازهای موسیقی قدیمی بازدید کرد و با تماشای پیانوهای شخصی مِتِـدیکِ مشاهیری چون موزارت و برامس به یک شهود فنی بزرگ دست یافت : او دریافت که دیگر هیچ اشتیاق و حرارتی برای حل مسائل دنیای وب و نرمافزار در خود حس نمیکند . او متوجه شد رؤیای دوران کودکیاش مبنی بر اینکه «میتواند دنیا را با نوشتن نرمافزارهای بهتر به جای بهتری تبدیل کند»، دیگر جایگاهی در حقیقت ذهنی او ندارد .
- هجرت به دنیای موسیقی: او برنامهنویسی را پس از ۵۰ سال تعهد مطلق رها کرد و وارد تحصیلات آکادمیک رشته آهنگسازی موسیقی شد . از نظر او، موسیقی یک زبان نمادین فرامدرن با ساختارهای صوری تمیز است که ارتعاش نتهای آن بر خلاف گزارههای سرد محاسباتی، تأثیرات حسی عمیق و بلادرنگی بر روح انسانها بر جای میگذارد .
۵. برنامهنویسی تفننی و ساخت ویرایشگر بومی نت موسیقی
دویچ با وجود بازنشستگی، هنوز هم نمیتواند جلوی اشتیاق خود را برای برنامهنویسیهای تفننی و خلاقانه بگیرد . او فیلترهای اسپم اختصاصی خود را با نرخ موفقیت بالای ۸۰ تا ۹۵ درصد برای سرور ایمیل شخصیاش نوشته است .
پروژه تفننی بزرگتر او، توسعه یک ویرایشگر بومی نت و سورسهای موسیقی به زبان پایتون است :
- او ابزارهای تجاری معروف بازار مانند Finale را به دلیل کیفیت پایین طراحی نرمافزار و ابزار Sibelius را به دلیل ضعف شدید طراحی رابط کاربری (که بدون کلید Num Lock روی لپتاپهای مک غیرقابلاستفاده بود) رد کرد و ترجیح داد مفسر شخصی خود را بنویسد .
- او با استفاده از قدرت شیءگرایی پایتون و کلاسهای میکساین (Mixins)، کدهایی فوقالعاده خوانا و فشرده برای تجزیه وpretty printing فرمتهای پیچیده فایلهای موسیقی نوشته است که پویایی آنها دستکمی از انتزاعهای ماکروی زبان لیسپ ندارد .
فصل دوازدهم: کن تامپسون (Ken Thompson)
بخش نخست: هکرِ ریشدارِ بل لبز، تولد یونیکس و طنزِ قوانین سفتوسخت گوگل
۱. خاستگاه آکادمیک، جادوی باینری و کشف برنامهنویسی در یک تعطیلات زمستانی (Academic Genesis, Binary Magic & The NELIAC Epiphany)
کن تامپسون هکر ریشدار و افسانهای یونیکس است که مسیر محاسباتی خود را از کودکی با شیفتگی مفرط به منطق ریاضی و کار با محاسبات در مبنای دو (باینری) آغاز کرد. او در دوران مدرسه به صورت تفننی و مستقل، الگوریتمهای جمع و کری (انتقال ده بر یک) را در مبناهای مختلف ریاضی استخراج نمود و با یک ماشینحساب مکانیکی دهدهی کوچک (که مانند چرتکه عمل میکرد)، سیستمهای محاسباتی چندگانهای را شبیهسازی کرد.
تامپسون برای تحصیلات دانشگاهی وارد دانشگاه برکلی شد. در آن دوران (اوایل دهه ۶۰ میلادی)، هنوز رشته مستقلی به نام علوم کامپیوتر وجود نداشت و این حوزه عملاً بخشی از دپارتمان مهندسی برق (Double EE) بود. نقطه عطف مهندسی او زمانی رخ داد که با سیستم مینیکامپیوتر Bendix G15 مواجه شد [124, 45/45]. این ماشین مجهز به مفسری به نام Intercom 501 بود. یکی از دانشجویان ارشد برکلی مفسری برای این سیستم روی رایانه بزرگ دانشگاه با زبانی به نام NELIAC (یک نسخه سیستمنویسی از Algol 58) نوشته بود. تامپسون در طول یک تعطیلات زمستانی، کل لیست چاپی کدهای این مفسر را به خانه برد و تمام آن هفته را صرف بازخوانی، کالبدشکافی و درک ساختار آن کرد. او با افتخار اعتراف میکند که کل اصول برنامهنویسی، زبان NELIAC، نحوه نوشتن مفسرها و تعامل با سختافزار را در جریان همین یک هفته مطالعه عمیق کدهای دیگران فرا گرفته است.
۲. فروپاشی MULTICS و تولد سرکشانه یونیکس (MULTICS Collapse & The Rebellious Birth of Unix)
پس از فارغالتحصیلی، تامپسون به عنوان پژوهشگر در آزمایشگاههای معتبر Bell Labs استخدام شد تا بر روی پروژه جاهطلبانه سیستمعامل MULTICS کار کند. با این حال، پس از مدتی بل لبز با درک این موضوع که مولتیکس در حال تبدیل شدن به یک سیستم فوقالعاده سنگین و ناکارآمد است (چیزی که تامپسون آن را نشانه بارز سندرم سیستم دوم یا Second-system syndrome مینامد)، از این پروژه خارج شد.
این رخداد فرصتی بینظیر برای تامپسون پدید آورد:
- با خروج شرکت از پروژه، یک سختافزار غولپیکر مولتیکس به صورت بلاتکلیف و بدون استفاده در آزمایشگاه رها شده بود و تامپسون به همراه دو یا سه نفر دیگر به مدت یک سال کنترل انحصاری این ماشین بزرگ را در دست گرفتند. او کار بر روی یک سیستمعامل سبک را روی این سختافزار آغاز کرد و توانست هستهای بنویسد که پیام Hello را روی ۵۰ ترمینال Teletype در سراسر ساختمان مخابره کند.
- با خروج نهایی آن ماشین از آزمایشگاه، او به سراغ مینیکامپیوترهای بسیار کوچک و ارزانقیمت PDP (به ویژه PDP-11) رفت تا ایده سیستمعامل خود را بر روی آنها پیاده کند. این سیستم جدید که با مشارکت دنیس ریچی توسعه یافت، یونیکس (Unix) نام گرفت.
- تامپسون معتقد است محدودیت شدید فیزیکی پردازندههای PDP-11 (در مقایسه با مینفریمهای بزرگی چون PDP-10) یک موهبت بزرگ بود؛ زیرا آنها را مجبور ساخت تا کدهایی به غایت کوچک، بهینه و چابک بنویسند که از دل آن مفاهیم انقلابی چون سیستم فایل سلسلهمراتب تفکیکشده (Hierarchical File System) و جدا بودن پردازش شل (Shell) از هسته متولد شد.
۳. فلسفه طراحی دادهمحور و مذهبِ خشنِ «دور ریختن کدهای پیچیده» (Data-First Design & Throwaway Code)
روش تامپسون برای طراحی نرمافزار، بر پایه برتری مطلق ساختارهای داده بر الگوریتمها شکل گرفته است:
- جعبهها و فلشهای ارتباطی (Boxes with Arrows): او پیش از نوشتن حتی یک خط کد، هرگز به سراغ رسم فلوچارتها یا تعریف الگوریتمهای صالب نمیرود. در مقابل، او تمام ساختار دادههای مورد نیاز سیستم را در قالب مربعها و فلشهای اتصالی روی کاغذ ترسیم میکند؛ زیرا معتقد است ساختار داده سنگبستر سیستم است که توسعهدهنده در تکتک خطوط کد باید به آن مراجعه کند.
- بیرحمی در دور ریختن کد (The Trigger-happy Rewriter): برخلاف بسیاری از برنامهنویسان که کدهای نوشتهشده خود را مانند بتهای صلب و غیرقابلتغییر میپرستند، تامپسون به شدت سریع بر روی ماشه دور ریختن کد قرار دارد [132, 48/48]. او معتقد است کدهای موجود به سرعت میپوسند و اگر برای اضافه کردن یک ویژگی جدید احساس کند که کار در حال گره خوردن است، بلافاصله کل چند صد خط کد قبلی را پاک کرده، سیستم را با یک افراز تفکیکی جدید (Partitioning) از ابتدا پیادهسازی میکند [132, 48/48].
- اصالت سادگی: بزرگترین شاخصه کدهای تامپسون، سادگی، بخشبخش بودن و فشرده بودن آنها است. او به شدت با بهینهسازیهای زودرس یا استفاده از کدهای پیچیده و هوشمندانه مخالف است و استدلال میکند که «یک الگوریتم ساده با کدهای ساده به مراتب بهتر از یک شاهکار پیچیده ریاضیاتی است که هیچکس توانایی نگهداری آن را ندارد» [147, 52/52].
۴. پروتکل دیباگ: ذهنِ ترتیبی و مذهبِ پرینت (Print-Debugging & Nightly Walkthroughs)
متدولوژی تامپسون برای خطایابی و پایداری سیستم با روشهای مرسوم صنعت متفاوت است:
- قدم زدن شبانه در کدها: او فاش میکند که در سالهای طلایی مهندسی خود (تا سن ۳۵ سالگی)، درکی فوقالعاده عمیق و خطبهخط از تمام کدهایی که مینوشت داشت. او کدهای روز خود را شبها در ذهن خود به صورت ترتیبی و خطبهخط مرور و اجرا میکرد تا باگها را کشف کند و روز بعد مستقیماً برای رفع آنها اقدام میکرد.
- مذهب پرینت به جای دیباگرهای تعاملی: تامپسون تقریباً هرگز از دیباگرهای تعاملی گرافیکی یا ابزارهای ردیابی پیچیده استفاده نمیکند. او توسعه خود را به صورت کاملاً تدریجی انجام میدهد و با تزریق مکرر دستورات چاپ مقادیر و فرضیات پایدار (Invariants) در حین کدنویسی، سیستم را عیبیابی میکند [144, 51/51]. او معتقد است وقتی کدهای چاپ موقتی را کامنت یا حذف میکند، برنامه به درجهای از پایداری رسیده است که به ندرت باگ جدیدی از آن سرازیر خواهد شد [144, 51/51].
۵. اصطکاک فنی با گوگل: طنزِ نداشتن مجوز ثبت کد و نقد تند به C++ (Google C++ Resistance & The C Checkout Blunder)
با پیوستن تامپسون به شرکت گوگل به عنوان معمار ارشد زیرساخت، تفاوتهای فرهنگی عمیقی میان او و استانداردهای بوروکراتیک شرکت پدیدار شد:
- نداشتن مجوز ثبت کد در گوگل (No Code-check-in Authority): گوگل قانون سختگیری دارد که بر اساس آن، تمام مهندسان جدید پیش از چکاین کردن کدهای خود باید آزمون استانداردهای استایل زبانها را پاس کرده و گواهی ثبت دریافت کنند. تامپسون با طنز اقرار میکند که او هرگز این آزمون را در گوگل نگذرانده است و در نتیجه رسماً اجازه ثبت کدهای خود را در مخازن اصلی گوگل ندارد! او تمام کارهای خود را به صورت مستقل و در جعبهابزار شخصی خود (Sandbox) پیش میبرد.
- نقد تند به زبان C++: در حالی که کلاسترهای گوگل به شدت به C++ متعهد هستند، تامپسون از این زبان منزجر است و آن را در کارهای خود تحریم کرده است. او C++ را یک «زبان بد، بزرگ، به شدت پیچیده و تلی از ایدههای متناقض و ناسازگار» میداند که صرفاً به دلیل آموزشهای صلب دانشگاهی و بدون داشتن طراحی منسجم و تمیز به صنعت تحمیل شده است [55/55]. او در گوگل تمام تستها و ابزارهای زیرساختی خود را منحصراً با زبان C بومی توسعه میدهد.
- عشق به yacc و نفرت از lex: از میان ابزارهای توسعه، او عاشق ابزار پارسساز
yaccاست؛ اما ابزار لغتسنجlexرا فاجعهبار میداند و ترجیح میدهد لغتسنجهای خود را همواره به صورت دستی بنویسد.
۶. مکانیزم شناخت استعدادها
تامپسون برای ارزیابی استعداد برنامهنویسان، فرار از پازلهای منطقی کلیشهای را ترجیح میدهد. او کاندیداها را به به چالش کشیدن الگوریتمهای پیچیدهترین پروژهای که خودشان کار کردهاند دعوت میکند؛ اگر آنها نتوانند با شور و حرارت از تصمیمات معماری خود دفاع کنند یا در مواجهه با پرسشهای عمیق او سست شوند، فاقد نبوغ لازم مهندسی تلقی میگردند. اصل اساسی او در استخدام، سنجش مستقیم میزان شور و اشتیاق (Enthusiasm) داوطلب است.
بخش دوم: شطرنج مکانیکی Belle، تولد یکشبهی UTF-8 و رویارویی با لینوکس و برنامهنویسی باادبیات (Ken Thompson - Part 2)
۱. پروژه Belle و شبیهسازی حرکتهای نهایی شطرنج (Computer Chess & Belle)
علاقه کن تامپسون به بازی شطرنج کامپیوتری، او را به سمت یکی از مهمترین پروژههای سختافزاری و الگوریتمی این حوزه هدایت کرد :
- ساخت کامپیوتر اختصاصی Belle: تامپسون با همکاری جو کاندون (Joe Condon)، کامپیوتر Belle را طراحی کرد و ساخت . این دستگاه نخستین سختافزار اختصاصی و پردازندهی سفارشی برای بازی شطرنج بود که به قویترین شطرنجباز کامپیوتری زمان خود تبدیل شد و چندین قهرمانی پیاپی را در مسابقات جهانی شطرنج کامپیوتر به دست آورد .
- خلق پایگاهداده بازیهای نهایی (Endgame Tablebases): تامپسون یکی از پیشگامان محاسبات عقبگرد (Retrograde Analysis) در شطرنج است . او با موازیسازی فرآیندهای جستجو روی ابررایانهها، موفق شد برای نخستین بار پایگاهدادههای عظیمی بسازد که تمام حالتهای ممکن برای بازیهای نهایی ۴ مهرهای و ۵ مهرهای را به طور کامل و صد در صد ریاضیاتی حل و تحلیل کند . این بانک اطلاعاتی نشان داد که در وضعیتهای نهایی، برخی از شاخههای حرکت که مراجع سنتی شطرنج آنها را مساوی یا غیرقابلبرد میدانستند، در عمل با استراتژیهای بسیار طولانی و دقیق (مثلاً مات در ۸۰ حرکت بدون عارضه جانبی) کاملاً برندهاند.
۲. ابداع UTF-8 در ماراتن یکروزه (The One-Night Birth of UTF-8)
در زمان توسعه سیستمعامل Plan 9 (که به عنوان جانشین معنوی و توزیعشدهی یونیکس طراحی میشد)، تیم توسعه با چالش جدی پشتیبانی از کاراکترهای بینالمللی و غلبه بر محدودیت بایتهای تکوجهی ASCII مواجه گردید :
- ماراتن طراحی در یک شب: در سال ۱۹۹۲، زمانی که پیشنهادات اولیه برای استانداردسازی کاراکترهای چندبایتی (مانند طرح FSS-UTF) به دلیل پیچیدگیهای ساختاری بنبست ایجاد کرده بودند، رابرت پایک (Rob Pike) چالشهای پیادهسازی را برای تامپسون تشریح کرد. تامپسون همان شب به خانه رفت، ساختار نوین رمزگذاری UTF-8 را طراحی نمود و تا صبح مفسر و کتابخانههای اصلی آن را پیادهسازی کرد .
- شکوه مهندسی UTF-8: این استاندارد از نظر فنی به غایت زیبا و بهینه بود؛ زیرا: ۱. سازگاری کامل عقبرو (Backward Compatible): کدهای سنتی ASCII بدون نیاز به کوچکترین تغییر به صورت UTF-8 معتبر خوانده میشدند. ۲. همگامسازی خودکار (Self-synchronizing): در صورت مفقود شدن یا خراب شدن بایتها در جریان انتقال لایه شبکه، سیستم در برخورد با کاراکتر بعدی بلافاصله خود را همگام میساخت و از تفسیر اشتباه کل رشته جلوگیری میکرد. ۳. عدم برخورداری از بایت صفر (Null-byte Safe): در بدنه این کاراکترها هیچگونه بایت صفری (
0x00) تزریق نمیشد؛ موضوعی که پایداری کدهای قدیمی زبان C را (که از بایت صفر برای تشخیص انتهای رشته استفاده میکردند) در برابر حملات سرریز بافر تضمین مینمود.
۳. نقد صریح برنامهنویسی باادبیات: توهم همگامی دو بازنمایی (Literate Programming Critique)
تامپسون با وجود ستایش از زیبایی تئوریک ایده دونالد کنوت مبنی بر برنامهنویسی باادبیات (Literate Programming)، آن را در دنیای واقعی مهندسی نرمافزار اساساً غیرکاربردی و شکستخورده میداند :
- مسئله ناهمگامی مداوم (Out-of-phase Representations): استدلال فنی او این است که در این روش، شما مجبورید دو بازنمایی کاملاً متمایز از یک برنامه را به طور همزمان بنویسید و نگهداری کنید: یکی نثر توصیفی انگلیسی و دیگری کدهای اجرایی ماشین . این دو بازنمایی در جریان توسعه و رفع باگهای سریع، به سرعت با یکدیگر ناهمگام (Out of phase) میشوند و هیچ مکانیزم اتوماتیکی برای حل اختلافات منطقی میان نثر انگلیسی و کدهای فیزیکی وجود ندارد .
- اصالت کدهای خودتوصیفگر: تامپسون پافشاری میکند که اگر کدی با استانداردهای تمیز و نامگذاری متغیرهای معنیدار نوشته شود، به خودی خود کاملاً خوانا خواهد بود و نیازی به توضیحات ریزبینانه کلامی در کنار آن نیست . او با لحنی کنایهآمیز میگوید: «شاید دونالد کنوت توانایی نگارش این حجم از نثرهای همراسای موازی را داشته باشد، اما من قطعاً چنین تواناییای ندارم؛ ما باید نهایتاً کدی را بخوانیم که ماشین واقعاً آن را اجرا میکند» .
۴. روابط تجربی با لینوکس و کدهای درایورِ Plan 9 (Linux & The Plan 9 Backporting)
موضعگیریهای تامپسون درباره سیستمعامل Linux در طول زمان دستخوش تغییرات جالبی شده است :
- از انتقاد اولیه تا تایید قابلیت اطمینان: او در اواخر دهه ۹۰ انتقاداتی جدی به ساختار پراکنده و کیفیت کدهای هسته لینوکس مطرح کرده بود؛ اما ده سال بعد اقرار میکند که لینوکس امروزه به شدت پایدار و قابلاعتماد شده است و او خودش در گوگل و سیستمهای شخصیاش از لینوکس استفاده میکند .
- مهندسی معکوس درایورها برای Plan 9: تامپسون فاش میکند که در دوران توسعه سیستمعامل Plan 9، به دلیل محدودیت شدید منابع و کمبود نیروی انسانی، آنها توانایی نگارش درایورهای سختافزاری متعدد را برای هزاران کارت گرافیک و شبکه موجود در بازار نداشتند . در مقابل، جامعه لینوکس از منابع هنگفتی برای پشتیبانی از سختافزارهای گوناگون برخوردار بود . استراتژی کارآمد تامپسون این بود که کدهای درایور لینوکس را باز کرده، فرضیات سختافزاری و ثباتهای بومی قطعه را از درون آن استخراج میکرد و سپس نسخه بسیار کوچکتر و تمیزتری از آن درایور را برای Plan 9 بازنویسی مینمود .
فصل سیزدهم: فرن اَلن (Fran Allen)
بخش نخست: معلم ریاضیِ بدهکار، بهینهسازیِ طبل مغناطیسی و مأموریتِ تاریخیِ فورترن
فرن اَلن (متولد ۱۹۳۲ - درگذشته ۲۰۲۰)، نخستین زن برنده جایزه معتبر تورینگ (در سال ۲۰۰۲) در تاریخ چهلساله این جایزه و اولین زنی است که به عنوان IBM Fellow (بالاترین جایگاه فنی در شرکت آیبیام) منصوب شد . او با ۴۵ سال سابقه کار ممتد در بخش تحقیقات IBM، طراح کلیدی کامپایلرهای فوقپیشرفته برای ابررایانههایStretch-Harvest و ACS-1، بنیانگذار پروژه انقلابی PTRAN (سیستم موازیسازی خودکار کدهای فورترن) و یکی از مبدعان نمایش میانی Static Single Assignment (SSA) است که امروزه سنگ بنای تمام کامپایلرهای ایستا و JIT مدرن به شمار میرود .
۱. خاستگاه آکادمیک و بهینهسازی فیزیکی طبل مغناطیسی IBM 650 (Academic Origins & IBM 650 Optimization)
مسیر علمی فرن اَلن با هدفی کاملاً متفاوت از مهندسی کامپیوتر آغاز شد :
- رویای تدریس ریاضی و بدهی دانشجویی: او تحصیلات خود را در رشته ریاضیات با گرایش فیزیک به پایان رساند و به مدت دو سال به تدریس ریاضی در دبیرستان پرداخت . سپس برای دریافت مدرک کارشناسی ارشد به دانشگاه میشیگان رفت . در آن زمان (سال ۱۹۵۷)، برای فارغالتحصیلی در رشته ریاضی، اَلن ناچار بود دو درس خارج از دپارتمان خود بگذراند؛ انتخابی که او را به سمت کلاس نوظهور محاسبات در دانشکده مهندسی سوق داد (رشتهای به نام علوم کامپیوتر هنوز وجود خارجی نداشت) .
- مهندسیِ زمانبندی روی طبل مغناطیسی (The Drum Machine Challenge): در دانشگاه میشیگان، او کار با ماشین افسانهای IBM 650 را آغاز کرد . این رایانه مجهز به یک طبل مغناطیسی دوار (Magnetic Drum) به عنوان حافظه اصلی بود . اَلن نحوهی کار با ماشین و نوشتن کدهای اسمبلی را به صورت کاملاً تعاملی و عملی روی این سختافزار فراگرفت . چالش بزرگ مهندسی بر روی IBM 650، بهینهسازی موقعیت فیزیکی دستورالعملها روی طبل مغناطیسی بود : از آنجا که طبل مدام در حال چرخش بود، برای بالا بردن سرعت اجرا، برنامهنویس باید آدرس فیزیکی هر دستورالعمل جدید را به گونهای با فاصله روی طبل چیدمان میکرد که درست در زمان اتمام دستور قبلی، دستور بعدی زیر هدِ خواندن قرار گیرد ؛ در غیر این صورت، پردازنده ناچار بود یک دور کامل چرخش طبل را منتظر بماند که کارایی سیستم را به شدت کاهش میداد .
- ورودِ باریبههرجهت به آیبیام: در سال ۱۹۵۷، اَلن به دلیل بدهیهای سنگین ناشی از وامهای دانشجویی، به دنبال یک شغل موقت اما با درآمد مناسب برای بازپرداخت بدهیهایش بود . او در زمان مصاحبه با استخدامکنندگان پرتحرک IBM، حتی نمیدانست که پکیج کاری او مربوط به بخش پیشرفته تحقیقات آیبیام (IBM Research) در منطقه پوکیپسی نیویورک است؛ او صرفاً به دنبال تامین معاش بود، اما این موقعیت او را برای ۴۵ سال در قلب تحولات کامپایلر جهان ماندگار کرد .
۲. مأموریت تاریخی در IBM: تحمیل فورترن به دانشمندان سرکش (The Fortran Evangelism Mission)
زمانی که فرن اَلن در ژوئیه ۱۹۵۷ به مرکز تحقیقات IBM پیوست، تنها سه ماه از عرضه تجاری اولین زبان برنامهنویسی سطح بالای جهان یعنی Fortran (در ۱۵ آوریل ۱۹۵۷) میگذشت :
- بخشنامه حاکمیتی آیبیام: مدیریت ارشد تحقیقات IBM بخشنامهای صادر کرده بود که بر اساس آن، تا سپتامبر همان سال (تنها دو ماه پس از ورود اَلن)، تمام دانشمندان و برنامهنویسان سازمان موظف بودند برنامهنویسی دستی با زبان اسمبلی را کنار گذاشته و کدهای خود را منحصراً با فورترن بنویسند . هدف از این بخشنامه سختگیرانه، اثبات کارایی فورترن در درون خود شرکت برای بازاریابی بیرونی آن بود .
- مقاومت شدید دانشمندان (The Assembly Orthodoxy): اَلن به دلیل سابقه تدریس ریاضی، مأمور شد تا فورترن را به دانشمندان و هکرهای سرسخت سازمان آموزش دهد . این کلاسها با تنشهای شدیدی همراه بود؛ دانشمندان که به کار با ماشین IBM 704 و نوشتن کدهای دستی اسمبلی عادت داشتند و به صورت انحصاری زمان استفاده از سیستم را مدیریت میکردند، به شدت نسبت به این زبان جدید گارد داشتند . آنها با عصبانیت استدلال میکردند که هیچ مترجم یا کامپایلر خودکاری در جهان هرگز نخواهد توانست کدهایی بنویسد که از نظر سرعت و کارایی با کدهای بهینهشدهی دستیِ آنها رقابت کند .
- شکوه بهینهسازِ جان باکوس: اَلن با وجود فضای سنگین کلاس، توانست با تکیه بر کیفیت بینظیر کامپایلر فورترن (که توسط تیم افسانهای جان باکوس طراحی شده بود)، دانشمندان را متقاعد کند . این کامپایلر نه تنها یک زبان ساده را ارائه میداد، بلکه به یک بهینهساز فوقپیشرفته (Optimizer) مجهز بود که کدهای نهایی ماشینِ تولیدشده توسط آن، پایههای ساختاری کامپایلرهای مدرن امروزی را بنا نهاد .
۳. ابررایانه Stretch-Harvest و چالش سهمگین تأخیر حافظه (Memory Latency in Stretch)
پس از موفقیت در پروژه فورترن و توسعه سیستم اشکالزداییِ سطح پایین MAD برای پردازنده 704، اَلن به دلیل اشراف عمیقش بر ساختار بهینهسازی فورترن، به پروژه تاریخی رایانه Stretch فراخوانده شد :
- جاهطلبی برای سرعت ۱۰۰ برابری: پروژه Stretch (که کار روی آن از سال ۱۹۵۵ آغاز شده بود) با هدف ساخت ماشینی طراحی شد که ۱۰۰ برابر سریعتر از تمام کامپیوترهای موجود در جهان عمل کند . این ماشین غولپیکر به بستری فرامدرن برای سیستمهای محاسباتی سنگین امنیتی (به ویژه برای NSA در قالب پروژه Harvest) تبدیل شد .
- کابوس همروندی سختافزاری و تأخیر حافظه (Hardware Concurrency): اَلن توضیح میدهد که در زمان طراحی سختافزار، مهندسان دریافتند که بزرگترین گلوگاه کارایی سیستم، زمان تأخیر دسترسی به حافظه (Memory Latency) است و حل این بنبست فیزیکی فراتر از توانایی برنامهنویسان اسمبلی دستی خواهد بود . سختافزار Stretch مجهز به مکانیزمهای موازی فوقالعاده پیچیدهای بود :
- حافظه سیستم به صورت چندراهه تداخلی (Multiway-interleaved Memory) سازماندهی شده بود، به طوری که ترتیب فیزیکی تحویل دادهها به واحد محاسباتی کاملاً غیرقابلپیشبینی بود .
- سیستم توانایی مدیریت همزمان ۶ درخواست دسترسی به حافظه در حال پرواز (6 accesses in flight) را داشت .
- پردازنده مجهز به خطلولههای موازی (Pipelines) و قابلیت اجرای موازی دستورات چندگانه بود .
- سیستم مجهز به یک واحد پیشبینِ پیشران (Look-ahead Unit) بود که وظیفه داشت مسیرها را به صورت احتمالی جلو ببرد؛ اما به دلیل تعهد معماری به لایه وقفههای دقیق (Precise Interrupts)، در صورت وقوع یک وقفه یا خطای محاسباتی، این واحد باید بلافاصله تمام کارهای موازیِ جلورفته را به عقب بازمیگرداند (Rollback) .
- سنگینی وظایف بهینهساز کامپایلر: اَلن به عنوان مدیر تیم بهینهسازی، وظیفه داشت کامپایلری طراحی کند که بتواند کدهای ترتیبی کاربر را به گونهای تحلیل و آرایش دهد که سختافزار موازیِ توصیفشده همواره در بالاترین سطح کارایی بماند، کلمهها درست در زمان نیاز در ثباتها بارگذاری شوند و از اتلاف چرخههای پردازنده جلوگیری شود .
۴. تیمِ رؤیاییِ زنان و درس تاریخیِ جدول هش (The Hashing Epiphany)
فرآیند مدیریت و تعاملات فنی در پروژه کامپایلر Stretch حاوی دو درس تاریخی بزرگ برای اَلن بود :
- رهبری متمرکز بر واسطها توسط مهندسان زن: برای پر کردن جزئیات دقیق کامپایلر Stretch، تیم مدیریتی تصمیم گرفت یک گروه ۴ نفره از مهندسان ارشد را مأمور طراحی اینترفیسها و تعاریف مشخصات فنی (Specs) کند . نکته شگفتانگیز این بود که سه نفر از این تیم چهار نفره طراحان اصلی، از میان زنان برنامهنویس برجسته انتخاب شده بودند (اَلن مسئول بخش بهینهساز بود و دو همکار زن دیگر او بخشهای پارسر و مدیریت ثبت فایلها را بر عهده داشتند) . اَلن بعداً تیمی متشکل از ۱۷ برنامهنویس را برای پیادهسازی این بهینهساز رهبری کرد .
- طغیان خلاقانه و درسِ جدول هش (The Symbol Table Rebellion): اَلن اقرار میکند که در زمان طراحی ساختار جدول نمادها (Symbol Table)، چند تن از برنامهنویسان جوان تیم او پیشنهاد دادند که به جای استفاده از لیستهای ترتیبی سنتی، از الگوریتم کاملاً جدید و ناشناختهای به نام جدول هش (Hashing) استفاده کنند . اَلن به دلیل ریسکهای زمانی و ناآشنا بودن با این الگوریتم نوظهور، با قاطعیت مخالفت کرد و گفت: «نه، ما نمیتوانیم این کار را بکنیم؛ ما چیزی درباره این روش نمیدانیم» . اما روز دوشنبه هفته بعد که او به آزمایشگاه برگشت، متوجه شد که برنامهنویسانش در طول تعطیلات آخر هفته کل کدهای قبلی را پاره کرده و سیستم را به طور کامل بر پایه جدول هش بازسازی کردهاند! اَلن با تماشای کدهای جدید دریافت که سرعت جستجوی متغیرها به شکلی استثنایی ارتقا یافته است . او با فروتنی از این واقعه یاد میکند: «این یکی از بزرگترین درسهای مدیریتی عمر من بود؛ فهمیدم که به عنوان یک رهبر فنی، همواره باید ذهنم را برای پذیرش ایدههای رادیکال و نوآوریهای تیم باز نگه دارم و جلوی خلاقیت آنها را سد نکنم» .
بخش دوم: پروژه PTRAN، نقد تاریخی به زبان C و جامعهشناسی جنسیت در مهندسی نرمافزار (Fran Allen - Part 2)
۱. پروژه انقلابی PTRAN و حماسه مهار صوریِ SSA (Static Single Assignment)
بزرگترین پروژه تحقیقاتی که فرن اَلن رهبری آن را بر عهده داشت، پروژه PTRAN (Parallel TRANslator) در شرکت IBM بود؛ پروژهای که بر روی موازیسازی خودکار کدهای ترتیبیِ قدیمی (که به صورت کنایهآمیز آنها را «کارتهای پانچ غبارآلود» یا Dusty Decks مینامیدند) تمرکز داشت .
- ظهور Static Single Assignment (SSA) و نبرد با ناممکنها:
یکی از درخشانترین و تاثیرگذارترین دستاوردهای علمی پروژه PTRAN، ابداع نمایش میانی SSA بود که امروزه به عنوان سنگبنای بهینهسازی در تمام کامپایلرهای مدرن جهان استفاده میشود . اَلن اقرار میکند که در زمان ارائه تئوریک این الگوریتم، به شدت نسبت به کارایی عملی آن مشکوک بود :- او معتقد بود این الگوریتم اگرچه روی کاغذ بسیار زیبا به نظر میرسد، اما پیادهسازی آن در یک سیستم واقعی به دلیل محدودیتهای حافظه و زمان کامپایل (در ابعاد پیچیدگی فضا و زمان) اساساً ناممکن یا غیرکاربردی خواهد بود .
- اَلن این چالش بزرگ را پیش روی تیم خود قرار داد و اعلام کرد تا زمانی که کد واقعی و پیادهسازیشدهی آن را با چشمان خود نبیند، آن را به عنوان یک دستاورد کاربردی نمیپذیرد .
- سرانجام، یکی از مهندسان خلاق تیم او روش کدگذاری منحصربهفردی برای این ساختار ارائه داد . اَلن شخصاً خطبهخط آن کد اسمبلی و ساختارهای دادهاش را بازخوانی و کالبدشکافی کرد و با شگفتی گفت: «خودش است؛ کار میکند!» .
- متدولوژی مدیریت در PTRAN (تفکیک مالکیت در بستر همکاری):
اَلن تیمی متشکل از ۱۰ تا ۱۲ مهندس هستهای را مدیریت میکرد . رویکرد او برای صیانت از پایداری سیستم، تقسیم دقیق مالکیت ماژولها میان افراد بود؛ به طوری که هر مهندس مسئولیت کامل و انحصاری یک بخش (مانند بهینهساز یا تحلیلگر درونپرویجری) را بر عهده داشت . با این حال، او برای ملو کردن مرزهای صلب، تئوریسینهای تیم را مجبور به نوشتن کدهای واقعی سیستم میکرد و از برنامهنویسان اجرایی میخواست مقالات علمی بنویسند تا دانش در سراسر پشته توزیع شود .
۲. نقد تاریخی و تند به زبان C: انحراف علم کامپایلرها و نابودی بهینهسازی خودکار
فرن اَلن یکی از سرسختترین و صریحترین منتقدان زبان C در تاریخ محاسبات است . او فاش میکند که برنامهنویسی شخصی خود را دقیقاً از زمان ظهور و همهگیری زبان C به طور کامل متوقف کرد؛ زیرا آن را ضربهای مهلک به پیشرفت علمی کامپایلرها میدانست .
- نبرد تاریخی SIGPLAN (Johnson vs. Harrison):
در یکی از کنفرانسهای بزرگ کامپایلر SIGPLAN، مناظرهای تاریخی میان استیو جانسون (مدافع زبان C از آزمایشگاه Bell Labs) و بیل هریسون (مدافع بهینهسازی خودکار از IBM) رخ داد . جانسون با تکیه بر تفکر بل لبز استدلال میکرد که با وجود زبان C، دیگر نیازی به توسعه بهینهسازهای پیچیده در کامپایلرها نیست؛ زیرا برنامهنویسان خودشان میتوانند با استفاده از اشارهگرها و کدهای دستی، کارایی را در بهینهترین حالت تنظیم کنند . - عقبگرد تاریخی محاسبات از نگاه اَلن:
اَلن استدلال میکند که تا پیش از ظهور C، صنعت نرمافزار به زبانهای فوقالعاده مدرن و سطح بالایی چون لیسپ، فرترن، کوبول و آلگول دست یافته بود که همگی فرسنگها جلوتر از C بودند . اما ظهور C توانایی صنعت را برای پیشرفت در حوزههای زیر کاملاً نابود ساخت : ۱. بهینهسازی خودکار (Automatic Optimization) ۲. موازیسازی خودکار کدهای ترتیبی (Automatic Parallelization) ۳. نقشهنگاری خودکار زبانهای سطح بالا روی سختافزار (Automatic Mapping) - دلیل فنی مخالفت (تلهی بیشتصریح دادهها - Overspecification):
زبان C و حتی زبانهای مدرنتری چون Java، Python و C#، به دلیل پیوند فیزیکی با مفهوم موقعیت و ارجاع دادهها (اشارهگرها به میانه آرایهها یا ساختارها)، راهحل مسائل را بیش از حد در لایه حافظه تصریح میکنند . این امر دست کامپایلر را برای جابهجایی پویا و مدیریت خودکار «محلیسازی دادهها» (Data Locality) متناسب با معماریهای چندهستهای نوین کاملاً میبندد ؛ موضوعی که درس کامپایلر نویسی را در بسیاری از دانشگاههای تراز اول جهان به مرز نابودی و حذف کشانده است . از نظر او، C تنها برای نوشتن هسته سیستمعاملها (Kernels) ابزار مناسبی بود و تعمیم آن به لایه برنامههای کاربردی یک خطای استراتژیک به شمار میآمد .
۳. جامعهشناسی جنسیت در مهندسی نرمافزار: از «محاسبان زنده» تا سقف شیشهای دهه ۷۰
اَلن در طول ۴۵ سال حضور ممتد خود در IBM، شاهد دگرگونیهای ساختاری و جامعهشناختی عمیقی در صنعت نرمافزار بوده است :
- دوران طلایی زنان در سحرگاه برنامهنویسی:
در دهههای ۵۰ و ۶۰ میلادی، حضور زنان در حوزه نرمافزار بسیار پررنگ بود . اَلن توضیح میدهد که در آن دوران، نرمافزار به عنوان جدیدترین بخش محاسبات و به نوعی «بخش نرمِ علم» (Soft part) تلقی میشد و مهندسان مرد ترجیح میدادند روی سختافزارهای صلب تمرکز کنند . در نتیجه، زنان به این حوزه هجرت کردند؛ کما اینکه اولین برنامهنویسان ENIAC و Bletchley Park همگی زنانی بودند که پیش از آن به عنوان محاسب دستی (که شغلشان رسماً Computers نامیده میشد)، جدولهای پرتاب موشک را محاسبه میکردند . در پروژه Stretch در سال ۱۹۵۹، سه نفر از چهار لیدر اصلی طراحی اینترفیسهای کامپایلر، مهندسان زن ارشد بودند . - ظهور آکادمی و زایش سقف شیشهای (The Glass Ceiling):
اَلن فاش میکند که پس از بازگشت از پروژه ACS در دهه ۷۰، با محیطی کاملاً دگرگونشده در بخش تحقیقات مواجه شد که در آن سقف شیشهای سختی علیه زنان شکل گرفته بود . تحلیل جامعهشناختی او علت این پدیده را چنین تبیین میکند :- بین سالهای ۱۹۶۰ تا ۱۹۷۰، رشته «علوم کامپیوتر» به عنوان یک دیسپلین آکادمیک بومی متولد شد .
- این رشته عمدتاً از دل دانشکدههای مهندسی (که اتمسفر آنها ۱۰۰ درصد مردانه بود) بیرون آمد .
- شرکتها (از جمله IBM) چارتهای استخدامی خود را تغییر دادند تا صرفاً فارغالتحصیلان این رشتههای مهندسی جدید را جذب کنند؛ در نتیجه، ورودیهای جدید همگی مهندسان مرد بودند و مدیریت زنجیرهای فرمال جایگزین collegial محیطهای چابک گذشته شد .
- نقدی بر پروژه «۵۰/۵۰ تا ۲۰۲۰»:
اَلن نسبت به موفقیت این دست مأموریتهای برابری جنسیتی در علوم کامپیوتر ابراز ناامیدی میکند . او معتقد است مشکل از آموزش ریاضی دبیرستانها نیست ؛ زیرا دختران نوجوان امروزه در مسابقات بزرگ علمی (مانند Westinghouse) دستاوردهای عظیمی دارند . علت گریز آنها از کامپیوتر این است که این رشته نتوانسته «هویت انسانی و اهمیت اجتماعی» (Human and Social Identity) خود را برای جامعه تبیین کند . دختران نابغه ترجیح میدهند وارد رشتههای پزشکی، زیستشناسی و علوم زمین شوند که تاثیرات اجتماعی ملموستری بر روی زندگی انسانها به همراه دارند .
۴. سرقت علمی کدهای موازی و فاجعه زوجِ هماتاقِ Amdahl
اَلن در جریان بازتابهای جایزه تورینگ خود، با صراحت از فضای نادیده گرفته شدن زنان در تاریخ محاسبات پرده برمیدارد :
- داستانهای تلخ سرقت علمی کدهای حیاتی:
او اشاره میکند که کارهای مهندسی زنان در بسیاری از موارد به طرز بیرحمانهای توسط همکاران مرد سرقت شده است؛ زیرا آنها معمولاً روحیه جنگجویی کمتری داشتند و فاقد حامیان کلهگنده در مجمعهای علمی بودند :- ادیت شونبرگ (Edith Schonberg): او یکی از برجستهترین دانشمندان کامپیوتر بود که مقالهای انقلابی درباره دیباگ کدهای موازی (یکی از سختترین مسائل مهندسی) نوشت . این مقاله توسط کمیته بازبینی یک کنفرانس رد شد، اما یکی از اعضای مرد همان کمیته، مقاله شونبرگ را به طور کامل سرقت کرد و سه مقاله مجزا از درون آن استخراج و به نام خود منتشر ساخت !
- مبتکر سیستم چندبرنامگی (Multiprogramming): اَلن فاش میکند که ایده و پیادهسازی بنیادی سیستم چندبرنامگی در دوران Stretch توسط یک مهندس زن انجام شد، اما اعتبار این کار بعدها توسط مردی که در نهایت جایزه تورینگ را دریافت کرد، مصادره گردید .
- اشتباه مضحک الفبایی با جین اَمدال (Gene Amdahl):
در زمان انتقال پروژه به West Coast، برگزارکننده غریبِ کنفرانس که شناختی از پرسنل نداشت، کل اتاقهای هتل محل اقامت مهندسان ارشد را به صورت کاملاً الفبایی تخصیص داده بود . در نتیجه این کار، فرن اَلن (Fran Allen) به دلیل تشابه حروف الفبا به عنوان هماتاقی معمار افسانهای مِینفریمها یعنی جین اَمدال (Gene Amdahl) انتخاب شده بود! . اَلن با خنده میگوید پس از کشف این افتضاح در لابی، مسئولان هتل با هراس بالا و پایین دویدند و در نهایت یک اتاق کوچک مخصوص خدمتکاران در زیرشیروانی برای او مهیا کردند . - افتخار و شرمساری جایزه تورینگ (Turing Award):
اَلن در پاسخ به این سوال که آیا از تیترهای مکرر رسانهها با عنوان «یک زن برنده جایزه تورینگ شد» دلخور نیست، میگوید از دریافت این جایزه بسیار شادمان است؛ اما واقعیت این است که وجود ۵۰ مرد در طول ۴۰ سال تاریخچه این جایزه و نبود حتی یک زن، یک مایه سرافکندگی بزرگ برای کل جامعه علمی نرمافزار جهان بود . او تلاش کرد به جای تکیه بر جنسیت، بر روی قدمت ۵۰ ساله کارنامه پژوهشی خود و تاریخ شفاهی محاسباتی که از سر گذرانده است، تمرکز کند .
فصل چهاردهم: برنی کازل (Bernie Cosell)
بخش نخست: تزار ۱۹ سالهی سیستمهای زماناشتراکی، پیجر باستانی و متدولوژی تخریب کدهای مبهم
برنی کازل یکی از کلیدیترین مهندسان شرکت BBN (Bolt Beranek and Newman) و از طراحان و توسعهدهندگان اصلی نرمافزار روترهای IMP (Interface Message Processors) در سال ۱۹۶۹ است؛ سیستمی که به عنوان اولین گرههای ارتباطی شبکه انقلابی آرپانت (ARPANET) (سنگ بنای اینترنت امروزی) ایفای نقش میکرد . او در طول ۲۶ سال فعالیت ممتد در BBN، به عنوان یک دیباگر نابغه و «حلکننده مطلق مسائل غیرقابلحل» شناخته میشد . کازل همچنین به صورت تفننی و برای تسلط بر لیسپ، مفسر مشهور DOCTOR (نسخهای بسیار کاملتر از برنامه هوش مصنوعی ELIZA اثر جوزف وایزنبام) را نوشت که همراه با سیستمعامل TENEX در سراسر آرپانت توزیع گردید .
۱. خاستگاه آکادمیک: از مینیکامپیوتر اهدایی تا هنر سیمکشی بوردهای محاسباتی (High School & Plug Boards)
مسیر محاسباتی کازل در سال ۱۹۵۹ و با یک اتفاق شگفتانگیز در دوران دبیرستان آغاز شد :
- اولین دبیرستان مجهز به رایانه فیزیکی: شایعهای در آن دوران وجود داشت مبنی بر اینکه دبیرستان معتبر Bronx High School of Science در نیویورک، نخستین مدرسه در کل آمریکا بود که رایانه اختصاصی خود را داشت . شرکت IBM یک دستگاه مینیکامپیوتر IBM 1620 را به این مدرسه اهدا کرده بود .
- دیباگ کردن کتاب معلم ریاضی: رئیس دپارتمان ریاضی مدرسه در حال نگارش کتابی درباره اصول برنامهنویسی بود . کازل نوجوان که به شدت شیفته این ماشین شده بود، وظیفه یافت تمام کدهای مثالهای این کتاب را به زبان اسمبلی ۱۶۲۰ دیباگ و اصلاح کند . این کار، هنر برنامهنویسی را به تنها خاطره ماندگار او از دوران مدرسه تبدیل کرد .
- هنر باستانی سیمکشی فیزیکی: او در مدرسه کار با ماشینهای چاپ محاسباتی قدیمی مانند IBM 403 را از طریق سیمکشی مستقیم صفحات متصلکننده (Plug Boards) آموخت . ده سال بعد در شرکت BBN، زمانی که تیم به شدت نیازمند یک پرینتر خطی برای رایانه PDP-1 خود بود، کازل با تکیه بر همین مهارت فراموششده، دفترچه راهنمای چاپگر را باز کرد و با سیمکشی دستی پلاکبورد، یک پرینتر حسابداری قدیمی را به عنوان چاپگر بومی سیستم راهاندازی نمود .
- گذر از MIT و برنامهنویسی مارپیچ: او در سال ۱۹۶۳ برای تحصیل در رشته ریاضی محض وارد دانشگاه MIT شد . در آن سالها، پروژههای پویای دانشجویی (مانند نوشتن برنامهای برای هدایت یک قورباغه فرضی که باید با پریدن از روی برگهای نیلوفر آبی از یک حوضچه خارج میشد) به او فهماند که توانایی بالایی در وادار ساختن کامپیوترها به انجام کارهای پیچیده دارد .
۲. هجرت به BBN: تزار شدن در ۱۹ سالگی (Czar of the PDP-1 Timesharing System)
کازل که فضای سختگیرانه و پرفشار دانشگاه MIT را مایه فرسایش ذهنی خود میدید، در پاییز سال سوم دانشگاه (اکتبر ۱۹۶۶)، کار پارتتایم خود را در شرکت BBN به حالت تماموقت تغییر داد و دانشگاه را رها کرد :
- اتوپیای هکرها: او محیط BBN را مانند «سرزمین موعود» توصیف میکند؛ فضایی به شدت پویا، صمیمی و آزاد که در آن مهندسان سگهای خود را به راهروهای کار میآوردند و روز و شب با عشق و اشتیاق روی پروژهها کار میکردند .
- پروژه اتوماسیون بیمارستان ماساچوست: او ابتدا به عنوان برنامهنویس اپلیکیشن در پروژه اتوماسیون بیمارستان عمومی ماساچوست (MGH) استخدام شد . با این حال، کازل تنها پس از ۳ هفته حضور در این لایه، به بخش برنامهنویسی سیستم هجرت کرد تا بر روی کتابخانههای هسته سیستم کار کند .
- سقوطِ ناگهانی به عمقِ سیستم: در میانه زمستان همان سال، دو مهندس ارشد و نابغهای که کل سیستم زماناشتراکی (Timesharing) رایانه PDP-1 شرکت BBN را نوشته بودند، تصمیم گرفتند شرکت را برای ادامه تحصیل در مقطع دکترا ترک کنند . آنها کازل جوان را به عنوان جانشین خود معرفی کردند . بدین ترتیب، در ژانویه ۱۹۶۷، برنی کازل ۱۹ ساله رسماً به عنوان «تزارِ سیستم زماناشتراکی PDP-1» برگزیده شد و مسئولیت نگهداری و کامل کردن کل این پشته پیچیده نرمافزاری را بر عهده گرفت .
۳. پروتکل دیباگ هشتهشتی با پیجر دوران باستان و تلفن سکهای (Payphone Debugging)
سیستم زماناشتراکی در آن دوران فاقد هرگونه ابزار اشکالزدایی زمانواقعی (Real-time Debugger) بود :
- کاغذ شطرنجی و لامپهای فیزیکی: به محض کراش کردن سیستم، چراغ فیزیکی اجرا روی کیس خاموش میشد . تنها راه دیباگ، خواندن وضعیت ثباتها و خانههای حافظه از روی دکمهها و ردیف لامپهای کنسول سختافزار (Bit per light) بود . کازل وضعیت سیستم را گامبهگام بر روی کاغذهای شطرنجی رسم میکرد تا مدل پویای کراش را در ذهن خود بازسازی کند .
- پیجر یکطرفه فرامدرن: او جزو معدود مهندسان (در کنار پزشکان برجسته بوسطن) بود که یک پیجر کلفت و سنگین دریافت کرده بود . این پیجر که فرستندهاش روی سقف برج پرودنشیال بوسطن نصب شده بود، توانایی دریافت متن یا پیام دوطرفه نداشت و صرفاً با صدای «بیپ، بیپ، بیپ» اورژانسی بودن اوضاع را هشدار میداد .
- اصلاح آدرسهای حافظه از باجه تلفن عمومی: کازل تعریف میکند بارها اتفاق میافتاد که در زمان تفریح، پیجر او به صدا درمیآمد . او بدون داشتن هیچ برگه یا کاغذی، خود را به نزدیکترین تلفن عمومی سکهای در پارکینگها میرساند، با اپراتور سیستم تماس میگرفت و اپراتور کدهای هشتهشتی (Octal locations) وضعیت حافظه را پشت تلفن برای او میخواند . کازل با تکیه بر حافظه ترتیبی فوقالعادهاش، آدرسهای تغییریافته را به اپراتور دیکته میکرد تا در کنسول وارد کند و بدین ترتیب، کل سیستم زماناشتراکی دهها بیمارستان را از راه دور و از درون کیوسک تلفن زنده میکرد !
۴. مذهب تخریب و بازنویسی کدهای پیچیده و غیرقابلفهم (The Rewrite Methodology)
یکی از ویژگیهای متمایز کازل در مهندسی نرمافزار، نگرش خاص او به پایداری کدهای بزرگ است :
- اصالت دترمینست بودن سیستم: او اعتقادی راسخ و متعصبانه داشت مبنی بر اینکه کامپیوترها ماشینهایی کاملاً دترمینستی (معین) هستند؛ بنابراین هیچ بهانهای برای کارکرد ناصحیح، رفتارهای تصادفی یا باگی ماندن سیستم پذیرفته نیست .
- راز مگو در پشت شهرت افسانهای: کازل در سراسر BBN به عنوان جادوگری شناخته میشد که سختترین و مرموزترین باگهای پروژهها را که ماهها تیمها را کلافه کرده بود، در یک یا دو روز حل میکرد . او با خنده این راز را برملا میکند: «حقیقت این بود که وقتی کدهای کثیف، درهمتنیده و به شدت پیچیده دیگران را میخواندم، به هیچ وجه منطق آن را درک نمیکردم. بنابراین، به جای وقتگذرانی برای پیدا کردن محل دقیق باگ، کل آن چند صد خط را از سورسپد پاره کرده و دور میانداختم؛ سپس بر اساس فرضیات تمیز خودم، کل بخش را از ابتدا و بسیار سادهتر بازنویسی میکردم و سیستم به صورت معجزهآسایی درست میشد!» .
- نفرت از رخنه تدریجی پیچیدگی (Complexity Oozing): کازل معتقد است کدهای پیچیده در نقاط کوچک و ایزوله (مانند کدهای بهینهسازی شده درونی) قابلتحمل هستند ؛ اما فاجعه زمانی رخ میدهد که پیچیدگی به صورت تدریجی در تاروپود و سراسر پشته سیستم نشت کند (Ooze through the program) به طوری که مرزبندی قطعات کاملاً مخدوش شود .
بخش دوم: ماراتن آرپانت، طنزِ مفسر پزشک و جنگ مذهبی علیه زبان C (Bernie Cosell - Part 2)
۱. نبرد بر سر پایداری ایمپ (ARPANET IMP): پچهای باینری در برابر اسمبل شبانه
در سال ۱۹۶۹، فرآیند نوشتن نرمافزار برای اولین روترهای تاریخ اینترنت (IMPs) در شرکت BBN، به بستری برای رویارویی دو دیدگاه کاملاً متضاد مهندسی میان برنی کازل و همکار نابغهاش، ویل کروتر (Will Crowther) تبدیل شد .
- نبوغ ناتمامِ کروتر: کروتر یک برنامهنویس شهودی و فوقالعاده خلاق بود که سختترین بنبستهای الگوریتمی را به راحتی حل میکرد؛ اما کدهای او معمولاً ۷۵ تا ۸۰ درصد کامل بودند و در ۲۰ درصد مواقع رفتارهای پیشبینینشده نشان میدادند .
- مذهبِ پچهای دفترچهای (The Notebook of Patches): کروتر به شدت معتقد بود که هر بار اسمبل کردن مجدد یک برنامه بزرگ، باگهای بیشتری نسبت به آنچه هرس میکند به سیستم اضافه مینماید . در نتیجه، او دفترچهای داشت که صفحات آن مملو از پچهای باینری دستی بود . او کدهای سیستم در حال اجرا را با دستورات پرش (
jump) به بخشهای خالی حافظه هدایت میکرد تا قطعه کدهای اصلاحی جدید را بدون کامپایل مجدد اجرا کند . پچها روی پچهای قبلی سوار میشدند و سیستم را به کلافی به غایت سردرگم تبدیل میکردند . - انضباط آهنین اسمبل شبانه: کازل تفاوت فاحشی با این رویکرد داشت؛ او معتقد بود کدهای منبع سیستم همواره باید تمیز و قابلاجرا از روی دیسک باشند و هیچ دستنوشتهای نباید روی لیستهای چاپشده قرار گیرد . کازل شبها بیدار میماند، تمام پچهای روز را درون کدهای منبع اعمال میکرد، کل پروژه را در طول شب دوباره اسمبل میکرد و صبح روز بعد، نوار کاغذی باینریِ کاملاً پاک و بدون پچ را برای شروع تست در اختیار تیم قرار میداد . او با این انضباط توانست نرخ بروز باگهای رگرسیون را در پروژه ایمپ عملاً به صفر برساند .
- مهندسی مجدد الگوریتم مسیریابی (Routing Algorithm): کروتر الگوریتم مسیریابی اولیه آرپانت را با نزدیک به ۲۰۰ ثبات و ثابت عددیِ (Constants) پراکنده و بدون توضیح نوشته بود . کازل که از این آشفتگی عددی بیزار بود، کل الگوریتم را بازنویسی کرد . او تمام اعداد را به فرمولهای ریاضی و متغیرهای نمادین قانونمند (مانند ترکیب قطر شبکه و نرخ تپش) تبدیل کرد تا اگر الگوریتم دچار نوسان (Oscillation) فیزیکی شد، علت آن به صورت علمی قابلاثبات باشد .
۲. مفسر DOCTOR و بوروکراتی که با رایانه گلاویز شد (The DOCTOR/ELIZA Hack)
کازل برای تسلط بر زبان Lisp تصمیم گرفت مفسر مشهور DOCTOR (نسخه ارتقایافتهای از برنامه هوش مصنوعی گفتگوی ELIZA اثر جوزف وایزنبام) را به زبان BBN-LISP بنویسد . این هک تفننی بعدها همراه با سیستمعامل TENEX در سراسر شبکه آرپانت توزیع شد و به شهرت بالایی دست یافت .
- گرفتار شدن مدیر ارشد BBN در تله هوش مصنوعی: یکی از خندهدارترین و در عین حال آموزندهترین وقایع تاریخ هوش مصنوعی در اتاق رایانه PDP-1 شرکت BBN رقم خورد :
- یکی از مدیران ارشد اجرایی BBN اواخر وقت اداری وارد اتاق کامپیوتر شد و با دیدن ترمینال تلهتایپ، تصور کرد که دانشمند برجسته، دانیال بابرو (Daniel Bobrow) از خانه به این ترمینال متصل شده است .
- او شروع به تایپ پیام کرد، اما در حقیقت در حال گفتگو با مفسر DOCTOR برنی کازل بود . مدیر از پاسخهای گنگ اما به ظاهر عمیق مفسر شگفتزده شده بود و اصرار داشت درباره پروژههای شرکت با او صحبت کند .
- در میانه بحث، مدیر کلماتی را تایپ کرد اما فراموش کرد دکمه ارسال (Go button) را بفشارد . سیستم در حالت تعلیق ماند و مدیر به گمان اینکه بابرو به نشانه بیاحترامی گفتگو را قطع کرده، با عصبانیت به خانه بابرو تلفن زد و او را از خواب بیدار کرد و بر سرش فریاد کشید ! بابرو که هیچ اطلاعی از ماجرا نداشت، روز بعد پس از بررسی سورسهای ترمینال، کل برگههای چاپی گفتگو را برای اثبات حماقت مدیر آرشیو کرد .
۳. جنگ مذهبی علیه زبان C: بزرگترین تهدید امنیتی رایانههای مدرن
به عنوان مهندسی که سالها دوره امنیت شبکه را تدریس کرده است، کازل صراحتاً با ایده همکاران قدیمیاش (مانند کن تامپسون) درباره بیخطر بودن ذات زبان C مخالفت میکند :
- بزرگترین مشکل امنیتی تاریخ محاسبات: کازل صراحتاً اعلام میکند که «بزرگترین فاجعه امنیتی که رایانههای مدرن را به زانو درآورد، زبان C است» . این زبان به عنوان یک ابزار سیستمنویسی عالی طراحی شده بود، اما تسلیم شدن صنعت در برابر آن و تعمیمش به لایه برنامههای کاربردی فاجعهبار بود .
- سربار فکری فراتر از ظرفیت انسان عادی: در یک پروژه پیچیده با زبان C، این فرض که برنامهنویس معمولی میتواند همواره و بدون حتی یک خطا، مرز بافرها را در زمان خواندن بررسی کند، تخصیصهای حافظه را بدون ایجاد اشارهگرهای معلق (Stale Pointers) رها سازد و از تداخلهای فیزیکی بگریزد، یک شوخی بیرحمانه است .
- دفاع از زبانهای محافظهکار: کازل به نبرد تاریخی نیکلاوس ویرت و ادسگر دیکسترا (طرفداران زبانهای ایمن مانند Pascal) در برابر توسعهدهندگان بل لبز اشاره میکند و معتقد است حق با ویرت بود . رایانهها باید به برنامهنویسان کمک کنند، نه اینکه با تفنگهای بدون ضامن پاهای آنها را هدف قرار دهند [۱۸۹/15].
- هجرت به Perl برای امنیت: کازل امروزه کدهای امنیتی و ابزارهای وب خود را منحصراً با زبان Perl مینویسد . او استدلال میکند که اگرچه پرل زبان کندی است، اما امنیت ساختاری آن بینظیر است؛ زیرا اگر در پرل از مرز آرایه خارج شوید، زبان خودبهخود آرایه را بزرگتر میکند و به دلیل مدیریت خودکار ارجاعها، نشت حافظه یا جعل آدرس در آن غیرممکن است .
۴. مهار پیچیدگی هرزرفته (Complexity Oozing)
کازل تفاوت میان برنامهنویسان بزرگ و متوسط را در نحوه مدیریت پیچیدگی میداند :
- پیچیدگی کپسولهشده در برابر پیچیدگی هرزرفته: او مخالفت چندانی با نوشتن کدهای پیچیده ندارد؛ به شرط آنکه این پیچیدگی (مانند الگوریتمهای فوقبهینهشده جستجو) درون یک جعبه سیاه (Black Box) مستحکم با مستندات کامل کپسوله شده باشد تا برنامهنویسان بعدی نیازی به لمس آن نداشته باشند .
- کابوسِ نشت تدریجی: فاجعه زمانی رخ میدهد که پیچیدگی به آرامی در تمام تاروپود برنامه نشت و نفوذ کند (Ooze through the program)، به طوری که برای اصلاح یک بخش کوچک، ناچار به دستکاری ده نقطه سراسری در سیستم باشید . او در تمام پروژههای بازسازی خود، این کدهای هرزرفته را بیرحمانه پاک و با کدهای سادهتر جایگزین میساخت .
فصل پانزدهم: دونالد کنوت (Donald Knuth)
دونالد کنوت بدون شک یکی از بزرگترین تئوریسینهای تاریخ علوم کامپیوتر، برنده جایزه تورینگ (۱۹۷۴)، نویسنده مجموعه کتابهای مرجع The Art of Computer Programming و خالق سیستمهای حروفچینی انقلابی TeX و METAFONT است . او بر خلاف تئوریسینهای محض، همواره ارتباطی عمیق و عملی با «بیتها و کدهای واقعی ماشین» داشته و پارادایم برنامهنویسی باادبیات (Literate Programming) را برای انسانیتر کردن کدهای منبع اختراع کرده است .
بخش نخست: تئوریسینِ دستبهکد، صد باگ در صد خط و حماسه نوشتن TeX با مداد روی کاغذ
۱. یادگیری زنده روی IBM 650 و کشف ۱۰۰ باگ در برنامهای ۱۰۰ خطی (The 100-Bug Prime Factors)
کشف دنیای محاسبات برای کنوت در پاییز سال ۱۹۵۶ و در زمان سال اول تحصیل او در مؤسسه فناوری کیس (Case Institute of Technology) رقم خورد :
- تماشای ماشین از پشت شیشه: در آن دوران، دانشگاه کیس به تازگی یک رایانه IBM 650 (نخستین مِینفریم تولید انبوه جهان) خریداری کرده بود . کنوت که برای تامین هزینههای تحصیلی خود در آزمایشگاه آمار کارتهای پانچ را مرتب میکرد، از پشت پنجره شیفته چراغهای چشمکزن فلاشینگ این ماشین شد .
- به چالش کشیدن کتابچههای راهنما: روزی یکی از اعضای آزمایشگاه اصول کارکرد ماشین را پای تخته برای او و دو دانشجوی سال اولی دیگر تشریح کرد . کنوت با پیدا کردن دفترچه راهنمای این ماشین و مطالعه کدهای مثالِ ۱۰ خطی آن، به صورت غریزی متوجه شد که این برنامهها ضعیف نوشته شدهاند و او به عنوان یک دانشجوی سال اولی میتواند کارایی آنها را ارتقا دهد .
- موهبت تماس فیزیکی با سختافزار در شب: بر خلاف بیشتر دانشگاههای آن زمان که دانشجویان اجازه دسترسی مستقیم به سیستم را نداشتند، کیس به دانشجویان اجازه میداد تا شبها به صورت مستقیم و انحصاری با دکمهها و سوییچهای کنسول ماشین ور بروند .
- نخستین برنامهنویسی و بحران باگها: نخستین برنامهای که کنوت برای این ماشین نوشت، ابزاری ۱۰۰ خطی برای محاسبه عاملهای اول اعداد (Prime Factors) بود . او شبها به آزمایشگاه میآمد و کدهایش را دیباگ میکرد؛ او فاش میکند که در این برنامه ۱۰۰ خطی، بیش از ۱۰۰ باگ مختلف پیدا و اصلاح کرد تا سرانجام پس از دو هفته سیستم توانست با گرفتن یک عدد ۱۰ رقمی از روی سوییچهای فیزیکی کنسول، به درستی عوامل اول آن را محاسبه کند .
۲. نوشتن تِک (TeX) با مداد روی کاغذ و بدون تست زودهنگام (The Pencil-and-Paper TeX Epic)
یکی از شگفتانگیزترین حقایق درباره طراحی سیستم حروفچینی TeX (که کنوت برای رضایت از کیفیت چاپ کتابهایش یک وقفه ۱۰ ساله در نگهداری مجموعه کتابهای خود ایجاد کرد تا آن را بنویسد)، این است که نسخه اولیه آن به طور کامل به دور از هرگونه رایانهای توسعه یافت :
- شش ماه تفکرِ مدادی: کنوت در طول ماههای اکتبر ۱۹۷۷ تا مارس ۱۹۷۸، بدون اینکه حتی یک خط کد را وارد رایانه کند، کل پایگاه کد TeX را با متدولوژی برنامهنویسی ساختاریافته در یک دفترچه یادداشت بزرگ و به صورت دستی با مداد نوشت .
- صرفهجویی در لایههای تست جانبی: او پس از اتمام نگارش دستی، در مارس ۱۹۷۸ تایپ کدها را در کامپیوتر آغاز کرد و فرآیند دیباگ را پیش برد . کنوت معتقد است این روش که در آن برنامهنویس از ابتدا کل سیستم را به صورت یکپارچه روی کاغذ میبیند و مینویسد، به دلیل عدم نیاز به ساخت کدهای موقت تست و داربستبندیهای کاذب (Scaffolding/Stubs)، زمان توسعه نهایی را به شدت کاهش میدهد .
۳. تسخیر مطلق ذهن توسط نرمافزار (The Brain-consuming Richness of Coding)
تجربه پیادهسازی پروژه عظیمی چون TeX، دیدگاه کنوت را درباره ظرفیت پردازشی مغز انسان در زمان برنامهنویسی به شدت دگرگون ساخت :
- تفاوت تالیف کتاب با نوشتن کد: کنوت تشریح میکند که او به راحتی میتواند همزمان با تدریس تماموقت در دانشگاه، کتابهای علمی سنگین تالیف کند؛ اما در زمان نوشتن نرمافزار، چنین کاری عملاً ناممکن است .
- سربار تمرکز بر جزئیات: نرمافزار به شدت مغز انسان را اشغال میکند و به قدری به جزئیات ریز گرایش دارد که ظرفیت پردازشی ذهن را به طور کامل به انحصار خود درمیآورد . این رویارویی عملی با حجم عظیم متغیرها و حالتهای مرزی در پروژههای واقعی، احترام و ستایش عمیقی را در قلب کنوت نسبت به مهندسان و برنامهنویسانی پدید آورد که سیستمهای نرمافزاری بزرگ صنعتی را توسعه میدهند .
۴. برنامهنویسی باادبیات (Literate Programming): کد به مثابه یک اثر ادبی
کنوت با ابداع ابزارهای WEB و CWEB، پارادایم انقلابی برنامهنویسی باادبیات (Literate Programming) را معرفی کرد که در آن، هدف توسعهدهنده دیگر صرفاً دستور دادن به ماشین نیست، بلکه توضیح اندیشههای محاسباتی به انسانهای دیگر است :
- فرار از صلبیت تفکر کمپایلرها: در برنامهنویسی سنتی، ترتیب کدها را نیازهای گنگ کامپایلر (مانند تقدم اعلام متغیرها) تعیین میکند . اما در برنامهنویسی باادبیات، برنامهنویس میتواند قطعات کد را کاملاً بر اساس سیر طبیعی ذهن و منطقِ توضیحی خود بنویسد و ابزار خودبهخود این قطعات را برای مفسر و کامپایلر بازآرایی و مرتب میکند .
- ترکیب ریاضی و ادبیات: کنوت قانون اول نگارش فنی را ادغام فرمولهای ریاضیاتی دقیق (ترکیب نمادین) با نثرهای توصیفی ساده انگلیسی میداند [۵۸/58]. کدهای نوشتهشده به روش CWEB به قدری زیبا و با انضباط هستند که خواننده میتواند آنها را مانند یک رمان کلاسیک بخواند و به سرعت درک کند .
۵. متدولوژی بومی تغییر فایلها (Change Files) در توزیع نرمافزار
یکی از نوآوریهای مینیاتوری کنوت در بستر برنامهنویسی باادبیات، ابداع سازوکار تغییر فایلها (Change Files) است :
- صیانت از کدهای منبع پایدار: او برای اینکه برنامه TeX بتواند بر روی صدها پلتفرم، معماری سختافزاری و سیستمعامل مختلف در سراسر جهان کامپایل شود، به جای تغییر مستقیم سورس اصلی (Master File)، مکانیزم فایل تغییر را طراحی کرد .
- کدگذاری وصلهها بدون دستکاری هسته: در این روش، کدهای اصلی برای همیشه به صورت یکپارچه و بدون تغییر باقی میمانند و تمام تنظیمات سفارشی پلتفرمها به صورت مجزا در یک فایل تغییر نگهداری میشوند که در زمان بیلد به صورت اتوماتیک با کد اصلی ادغام میگردد . این ابزار به قدری کارآمد بود که در زمان مهاجرت TeX به سیستم یونیکد (Unicode)، توسعهدهندگان Omega موفق شدند با نوشتن یک میلیون خط در Change files، کل سیستم ۲۰ هزار خطی TeX را بدون مخدوش کردن کدهای پایدار کنوت ارتقا دهند .
۶. مذهبِ راستیآزمایی دادهها (Sanity Checking) و ادغام با GDB
روش کنوت برای خطایابی کدهای پیچیده، تکیه بر راستیآزماییهای سختگیرانه زمان اجرا است :
- کدهای سنجش ثبات (Sanity Check Code): او نزدیک به ۱۰ درصد از کل ساختار برنامه را منحصراً به کدهایی اختصاص میدهد که وظیفهای جز بررسی صحت وضعیت ساختارهای داده (مانند شمارندههای ارجاع پیچیده در حافظه) ندارند . فعال کردن این سنجشها ممکن است سرعت سیستم را تا ۱۰۰ برابر کاهش دهد، اما با کشف زودهنگام تداخلها، از وقوع کراشهای مبهم در آینده جلوگیری میکند .
- یکپارچگی CWEB با GDB: کنوت با ستایش از طراحان کامپایلر GNU و ابزار دیباگر GDB اشاره میکند که آنها با معرفی دستورالعملهای
#lineبه زبان C، پلی جادویی میان بایتکدهای ماشین و کدهای سطح بالای CWEB ساختند؛ به طوری که برنامهنویس در زمان گام زدن در دیباگر، مستقیماً کدهای ادبی CWEB خود را تماشا میکند، بدون اینکه نیازی به دیدن کدهای اسمبلر یا ساختارهای میانی داشته باشد .
۷. مخالفت با کپسولهسازی کورکورانه و جعبههای سیاه صلب (Critique of Reusable Software)
یکی از دیدگاههای رادیکال کنوت، نقد تند او به فرهنگ افراطی بازاستفاده از نرمافزارها و استفاده از جعبههای سیاه صلب (Black Boxes) است :
- تلهی عدم دستکاری درون سیستم: او استدلال میکند که مخفی کردن کدها در پشت پوششهای فشرده و اینترفیسهای تجاری بدون اجازه دادن به برنامهنویس برای گشودن درِ جعبه و دستکاری در ساختار درونی آن، مهارتهای فکری برنامهنویسان را تنزل میدهد .
- تمثیل قضایای ریاضی: کنوت این چالش را با اثبات قضایای ریاضی مقایسه میکند : در حل مسائل ریاضی، شما به ندرت قضیهای را پیدا میکنید که دقیقاً با فرضیات مسئله شما مطابقت داشته باشد؛ ریاضیدانان معمولاً سورس و روش اثبات آن قضیه را باز میکنند، در گامهایش تغییر اعمال میکنند و قضایای بومی خود را میسازند . نرمافزار نیز باید همینگونه باشد؛ مهندسان باید بتوانند ساختارهای درونی مانند لیستهای پیوندی یا درختهای B-Tree کتابخانهها را باز کرده، آنها را مطابق با نیازهای دادهای دقیق خود شخصیسازی کنند تا کارایی و بهینهسازی واقعی محقق شود .
بخش دوم: رمزگشایی از ترفندهای کثیف، قانونِ دو درصد و مذهبِ تفکر در مرزهای محدودیت (Donald Knuth - Part 2)
۱. حقیقت گزارهی «بهینهسازی زودهنگام»: شاهکارهای ظریفِ مستند شده
جملهی معروف دونالد کنوت مبنی بر اینکه «بهینهسازی زودهنگام ریشهی تمام شرارتهاست»، اغلب در صنعت نرمافزار به اشتباه تفسیر میشود . او معتقد نیست که باید بهینهسازی را به طور کامل کنار گذاشت؛ بلکه یک برنامه ادبی (Literate Program) باید تاریخچه تکامل خود را به نمایش بگذارد . از نظر او، کد باید بگوید: «راهحل بدیهی برای این مسئله این است، و اینها دلایلی هستند که نشان میدهند چرا ما این مسیر بدیهی را دنبال نکردهایم» .
کنوت اقرار میکند که در دو حالت دست به استفاده از «ترفندهای کثیف» (Dirty Tricks) در بهینهسازی میزند :
- نخست، زمانی که این کار بهبود واقعی و ملموسی در کارایی سیستم پدید آورد که برای کاربران نهایی ارزشمند باشد .
- دوم، به خاطر «لذتِ محض زیباشناختی»؛ یعنی زمانی که یک ایده به قدری هوشمندانه و بامزه (Cute) است که او نمیتواند در برابر وسوسهی نوشتن آن مقاومت کند .
با این حال، تفاوت کلیدی او با برنامهنویسان دیگر در این است که او هرگز این بهینهسازیهای غریب را به عنوان یک راز مبهم رها نمیسازد؛ بلکه تمام مفروضات و ترفندها را با دقت در بخش توضیحات متنی (Prose) مستند میکند . او حتی بخشهایی از کدهای ساده یا نسخههای اولیه و خام را در سند برنامه نگهداری میکند (بدون اینکه در برنامه نهایی فراخوانی شوند) تا خواننده با مقایسه آنها روند بهینهسازی سیستم را به درستی درک کند . او گاهی سه نسخه کاملاً متفاوت از یک برنامه (مانند برنامه حل پازل ۱۵) را به ترتیب مینویسد و به خواننده هشدار میدهد که «بدون خواندن نسخه اول، هرگز نسخه دوم و سوم را نخواهی فهمید» .
۲. شخصیت مهاجم در خطایابی: آزمون شکنجهی تِک و رمزگشایی سختافزار باروز
فرآیند تست و خطایابی از نظر کنوت، نیازمند یک گسست روانی بزرگ از هویت نویسندگی نرمافزار است . او در زمان نوشتن مفسر TeX، آزمون شکنجهی معروف TRIP را برای به چالش کشیدن تمام مرزهای سیستم طراحی کرد . او برای انجام چنین کارهای تخریبی سختگیری توضیح میدهد که در تمام طول زندگی خود یک «موشکافِ بهانهگیر» (Nitpicker) بوده است . پروتکل ذهنی او برای نوشتن تستهای مخرب به این شرح است:
- او تلاش میکند به طور کامل فراموش کند که خودش نویسنده و آفریننده این برنامه است و در کالبد یک بازبین بیرونی و کاملاً مهاجم فرو میرود .
- متدولوژی او شبیه به اثبات قضایای ریاضی است؛ او به جای تلاش برای اثباتِ مستقیم درستیِ یک قضیه، تمام توان خود را روی یافتن یک مثال نقض (Counterexample) متمرکز میسازد؛ اگر تمام تلاشها برای یافتن رخنه و مثال نقض با شکست مواجه شد، آن زمان است که درستیِ ریاضیاتی سیستم اثبات میگردد .
کنوت با اتکا به همین تفکر تفحصگر و مهاجم، پیش از آنکه پردازندههای سری Burroughs B-5000 وارد مرحله تولید فیزیکی شوند، مشخصات فنی سختافزار آنها را مطالعه کرد و با شبیهسازی منطقی رفتار ثباتها و پشته در حالتهای مرزی، بیش از ۲۰۰ باگ و نقص طراحی سختافزاری را پیش از بیلد نهایی شناسایی و شکار کرد .
۳. کار کردن در مرزهای توانایی: چرا تئوریسین بزرگ هنوز باگ تولید میکند؟
یکی از مشهورترین مقالات کنوت، The Errors of TeX است که در آن او تمام باگهای کشفشده در طول تاریخ تکامل TeX را با کدهای دستهبندیشده ثبت کرده است . پیتر سیبل از او میپرسد که آیا تحلیل و ثبت این گناهان محاسباتی، او را در برابر تکرار آنها بیمه کرده است ؟ پاسخ کنوت شگفتانگیز و متواضعانه است:
- او اعتراف میکند که هنوز هم مرتکب همان اشتباهات و باگهای قدیمی میشود .
- علت فنی این موضوع از نظر او این است که او هرگز در حاشیه امن خود نمیماند؛ او همواره کارهایی را انتخاب میکند که دقیقاً در مرزهای توانایی فکریاش قرار دارند .
- او معتقد است اگر برنامهنویس صرفاً کارهای ساده و تکراری گذشته را انجام دهد، مرتکب خطایی نخواهد شد؛ اما ماندن در قلمروهای راحت مهندسی فاقد شور و خلاقیت است . بنابراین، حرکت مداوم به سمت مسائل سختتر، به طور طبیعی با بروز باگهای جدید همگام خواهد بود .
۴. قانون ۲ درصد: سرنوشتِ زایش هکرهای اصیل و اعتیاد صبحگاهی به کدنویسی
کنوت بر پایه دههها تدریس و تعامل با جوامع مختلف، به یک قانون تجربی درباره خاستگاه برنامهنویسان رسیده است :
- توزیعِ ثابتِ هکرهای واقعی: او معتقد است در هر جامعهای از انسانها (صرفنظر از دانشجویان رشته کامپیوتر)، به طور متوسط تنها ۲ درصد از افراد با ذهنی متولد میشوند که با فرکانس فیزیکی ماشین همرسا و همفرکانس است . برای مثال، او به طنز میگوید شهر کوچک واسیلا در آلاسکا با ۱۰ هزار نفر جمعیت، قطعاً حدود ۲۰۰ برنامهنویس اصیل در خود جای داده است . از نظر او، برنامهنویسی به این معنا، فشردن ماشین به مرزهای نهایی فیزیک و حافظه است، نه صرفاً سر هم کردن کتابخانهها برای گرفتن یک خروجی ساده .
- اعتیاد شاعرانه به کدنویسی: برای خودِ کنوت، برنامهنویسی فراتر از یک شغل، یک نیاز زیستی و compulsiveness عمیق است . او میگوید: «من صبحها با جملات آمادهی یک برنامه ادبی (Literate Program) از خواب بیدار میشوم. درست قبل از صبحانه – مطمئنم شاعران نیز چنین حسی دارند – باید به سمت کامپیوتر بدوم و آن قطعه کد را بنویسم تا بتوانم با آرامش غذا بخورم و شادمان شوم!» . او با هیجان بالا کدهای روز قبل خود را توصیف میکند که در آنها اعداد صحیحِ غولپیکری را (که از ابعاد فیزیکی جهان بزرگتر هستند اما با روشهای فشردهسازی بازنمایی شدهاند) در هم ضرب و مجذور ساخته تا رفتار بصری و منطقی آنها را بررسی کند .
۵. جزر و مد تاریخ: تقابل دانشگاههای متکلم و صنعتِ چابک، و جادوی خواندن کدهای باستانی
تحلیل کنوت از رابطه میان دپارتمانهای آکادمیک و صنعت نرمافزار، نشاندهنده یک حرکت نوسانی و موجی است :
- دهه ۱۹۶۰ (پیشتازی آکادمی): در این دوران، دانشگاهها فرسنگها جلوتر از صنعت بودند و کدهای نوشتهشده در شرکتهای تجاری (به جز سیستمهای رزرو پرواز) از نظر علمی خندهدار تلقی میشدند .
- دهه ۱۹۸۰ (ظهور دگماتیسم دانشگاهی): در این سالها اوضاع کاملاً برعکس شد؛ دانشگاهها وارد «فازِ الهیات متکلمانه» (Theological Mode) شدند . اساتید قوانین سختگیری مانند تحریم مطلق دستور
gotoصادر کردند و دستوپای دانشجویان را بستند؛ در حالی که مهندسان صنعت بدون درگیر شدن با این تعصبات نظری، نرمافزارهایی به مراتب کارآمدتر و پایدارتر خلق میکردند .
علاوه بر این، کنوت یکی از معدود دانشمندانی است که کدها را به عنوان یک «میراث تاریخی و ادبی» مطالعه میکند . او ساعتها به مطالعه کدهای مفسر فرترن مینیکامپیوتر Bunker Ramo 300 (بدون داشتن دفترچه راهنمای ماشین) پرداخته و مانند یک رمزگشای متون باستانی، از روی کدهای منبع لغتسنج کارتهای پانچ، اسمبلی سختافزار را بازسازی کرده است . او همچنین برای درک نحوه تفکر گذشتگان، دستنوشتههای ریاضیاتیcombinatorial بابلیها متعلق به ۴ هزار سال پیش و متون سانسکریت قرن سیزدهم را خطبهخط بازخوانی کرده است . او حسرت میخورد که چرا برنامهنویسان جوان از این تاریخ باشکوه بیخبرند و مدام چرخهایی را که در دهه ۷۰ ابداع شده بودند (مانند الگوریتم بویر-مور) دوباره اختراع میکنند .
کلام آخر: پایان سفر در هنر برنامهنویسی (Coders at Work Conclusion)
با پایان یافتن پروندهی دونالد کنوت، سفر طولانی و شگفتانگیز ما در تاروپود کتاب Coders at Work به انتهای خود میرسد . در طول این ۱۵ فصل، ما با تیپهای شخصیتی فوقالعاده متنوعی همراه شدیم: از هکرهای سرکش و زمانواقعی لایه سیستم مانند جیمی زاوینسکی و برنی کازل ، تا معماران بزرگ زبانهای برنامهنویسی چون گای استیل، سایمون پیتون جونز و جو آرمسترانگ ؛ از تئوریسینهای دستبهکد مانند دونالد کنوت ، تا مدیران و رهبران پروژههای عظیم صنعتی نظیر فرن اَلن و پیتر نورویگ .
با وجود تمام تضادهای فلسفی عمیق میان این نوابغ، چند حقیقت بزرگ و پایدار به عنوان میراث این کتاب در ذهن ما حک میشود: ۱. کد برای انسانها نوشته میشود، نه ماشینها: تقریباً تمام این مهندسان برجسته، پایداری، سادگی و خوانایی کد را به عنوان اولویت نخست خود در مهندسی نرمافزار برمیگزینند . ۲. سادگی شجاعانه بر پیچیدگی هوشمندانه پیروز است: زیباترین کدهای جهان ساختارهایی مینیاتوری دارند که با حذف تمام بخشهای زائد، در نهایت پایداری به تکامل رسیدهاند . ۳. برنامهنویسی یک هنر و پیشه انسانی است: فراتر از فرمولهای ریاضی و کتابخانههای صلب، نرمافزار حاصل همدلی، تعاملات اجتماعی، گفتگوی مستقیم با همکاران و ترجمهی دقیق اندیشههای کلامی ما به ساختارهای منطقی است .
