بعدازظهر ۹ سپتامبر ۱۹۴۷، ساعت ۱۵:۴۵. کامپیوتر Mark II دانشگاه هاروارد — با ۲۵ تن وزن و ۱۳ هزار رله — مدتی است جوابهای غلط میدهد. تیم اپراتورها دنبال خطا میگردد؛ پنل F را باز میکنند و به رلهی شماره ۷۰ میرسند. آنجا، میان کنتاکتهای برقی، چیزی پیدا میشود که در هیچ دفترچهی تعمیراتی نوشته نشده بود: یک شبپرهی واقعی.
شبپره را بیرون میآورند، با چسب به صفحهی لاگبوک میچسبانند و کنارش مینویسند: «First actual case of bug being found» — اولین موردِ واقعیِ پیداشدنِ باگ. اما ماجرا یک پیچش دارد که کمتر کسی میداند: آن شب، واژهی Bug متولد نشد. اصلاً جملهی روی لاگبوک فقط وقتی جوکِ بامزهای است که بدانید این واژه از کجا آمده است...
#
آیا این قصه واقعی است؟ بله — و شبپره هنوز در موزه است
این یکی از همان قصههایی است که آنقدر قشنگ است که فکر میکنید باید ساختگی باشد؛ اما نیست. ماجرای شبپرهی سال ۱۹۴۷ کاملاً واقعی است و برگهی لاگبوک با همان شبپرهی چسبیده رویش، امروز در موزهی ملی تاریخ آمریکایی اسمیتسونیان نگهداری میشود. جملهای که کنارش نوشته شد، عیناً این است:
“First actual case of bug being found.”
اولین موردِ واقعیِ پیداشدنِ باگ — دستخطِ لاگبوکِ Mark II، ۹ سپتامبر ۱۹۴۷
اما دو باور رایج دربارهی این ماجرا اصلاً درست نیست: اول اینکه واژهی Bug آن شب ساخته نشد — این واژه دهها سال قبل از کامپیوترها در زبان مهندسان وجود داشت. دوم اینکه چیزی که آن شب پیدا شد، اصلاً باگ نرمافزاری نبود؛ یک خطای سختافزاریِ کاملاً فیزیکی بود، با یک دلیل کاملاً زمینی: یک حشرهی چهارسانتیمتری داخل یک کلید برقی گیر کرده بود.
بخش واقعی ماجرا
شبپره در رلهی ۷۰ پنل F گیر کرده بود، لاگبوک واقعی است و امروز در موزه است
بخش افسانهای ماجرا
اینکه «واژهی باگ در ۱۹۴۷ اختراع شد» یا «اولین خطای نرمافزاری تاریخ بود»
حالا بیایید از اول شروع کنیم: چه ماشینی بود این Mark II؟ چرا اصلاً «رله» داشت؟ و چطور یک موجود نرم و بیمغزِ بالدار توانست یک ماشین چندتنی را از کار بیندازد؟
#
ماشینی ۲۵ تُنی از ۱۳ هزار کلید برقی
Harvard Mark II که به «ماشینحساب رلهای آیکن» هم معروف است، در سال ۱۹۴۷ در آزمایشگاه محاسبات هاروارد زیر نظر هاوارد آیکن و با بودجهی نیروی دریایی آمریکا ساخته شد. «رله» قلب این ماشین بود: کلیدی الکترومکانیکی که خودش، با برق، کلید میخورد. کارکردش چهار قدم ساده دارد:
1
سیمپیچ برق میگیرد — و مثل یک آهنربا عمل میکند
2
بازوی فلزی جذب میشود — با صدای همان «کلیک» معروف
3
کنتاکت بسته میشود — مدار دوم وصل میشود
4
برق قطع، بازو رها — مدار باز میشود؛ آمادهی فرمان بعدی
نکتهی کلیدی اینجاست: هر رله فقط دو وضعیت دارد — بسته یا باز. یعنی هر رله دقیقاً یک بیت است: صفر یا یک. Mark II حدود ۱۳ هزار رله داشت که با هم حافظه و منطق ماشین را میساختند؛ ۲۵ تن وزن، بیش از ۴ هزار فوت مربع فضای کف، و سرعتی در حدود هشت جمع در ثانیه. برای مقایسه:
ویژگی
Mark II (۱۹۴۷)
یک گوشی امروزی
عناصر کلیدی
~۱۳٬۰۰۰ رله
~۲۰ میلیارد ترانزیستور در تراشه
سرعت
~۸ عمل جمع در ثانیه
هزاران میلیارد عمل در ثانیه
وزن / فضای کف
~۲۵ تن / ۴٬۰۰۰+ فوت مربع
چند گرم در جیب شما
صدای کارکرد
بارش مداوم کلیک
سکوت
آن ردیف آخر شوخی نیست: Mark II موقع کار مدام تیکتیک میکرد — هزاران رله که هر کدام در هر ثانیه چند بار باز و بسته میشدند. روایتها میگویند اپراتورهای باتجربه حتی میتوانستند از ناهماهنگیِ صداها بفهمند چیزی درست کار نمیکند؛ مثل مکانیکی که از صدای موتور میفهمد مشکل کجاست.
#
بعدازظهر ۹ سپتامبر ۱۹۴۷؛ ساعت ۱۵:۴۵
ماشین در میانهی کارش جوابهای غلط تحویل میدهد. نه پیام خطایی، نه صفحهی آبی، نه stack trace — فقط اعدادی که درست نبودند. تیم اپراتورها میداند مشکل somewhere در آن ۱۳ هزار رله است و شروع میکند به ردیابی سیستماتیک: بخشبهبخش، پنلبهپنل. سرانجام به پنل F و رلهی شماره ۷۰ میرسند و درчее را باز میکنند.
آنجا، بین بازوی فلزی و کنتاکت، یک شبپره گیر کرده است. شبپرهای درشت که احتمالاً شب قبل به سوی نور یا گرما آمده و در جای اشتباهی عمرش را تمام کرده. اپراتورها آن را بیرون میآورند و کاری میکنند که بعد از هفتاد و چند سال هنوز معروفترین حشرهی تاریخ کامپیوتر باشد: با چسب به صفحهی لاگبوک میچسبانندش و کنارش جملهای مینویسند که به نسخهی بازسازیشدهی زیر تبدیل شده:
mark2_logbook.txt
Harvard Computation Laboratory - Log Book, Mark II
1947-09-09 15:45
Relay #70, Panel F
Moth found stuck between the relay contacts.
Removed & taped into this logbook.
"First actual case of bug being found."
به آن کلمهی actual دقت کنید. چرا «واقعی»؟ چون برای هر مهندسِ آن سالها، «باگ» یک واژهی کاملاً آشنا بود — چیزی انتزاعی، آن خطای سرسامآور که هر اختراعی به همراهش میآید. این بار اما، برای اولین بار، باگِ پیداشده خودِ کلمه بود: یک حشرهی واقعی، با بال و پا. جملهی لاگبوک اساساً یک جوک مهندسی است، دقیقاً از همان جنس شوخیهایی که امروز در کامیتها و کامنتهای کد میبینیم.
ⓘ
شبپره الان کجاست؟ صفحهی لاگبوک با همان شبپرهی چسبیده، امروز بخشی از مجموعهی موزهی ملی تاریخ آمریکایی اسمیتسونیان است. گریس هاپر سالها بعد این صفحه را به موزه سپرد و خودش همیشه با لذت قصه را تعریف میکرد. شاید بتوان آن را قدیمیترین attachment ثبتشدهی یک باگ در تاریخ دانست.
#
چرا یک شبپره میتواند ماشین ۲۵ تُنی را زمینگیر کند؟
مکانیک خرابی بهطرز عجیبی ساده است. در بخش قبل دیدیم که بازوی فلزی رله باید به کنتاکت برسد تا مدار بسته شود. حالا تصور کنید بدنهی یک شبپره دقیقاً در همان فاصلهی چندمیلیمتری گیر کرده باشد: آهنربا هرقدر هم بکشد، بازو هرگز به کنتاکت نمیرسد. رله فرمانِ «بسته شو» میگیرد، اما مدارش باز میماند.
یک بیتِ همیشهغلط بهتنهایی بیخطر به نظر میرسد؛ اما در ماشینی که تمام حافظه و منطقش از همین بیتها ساخته شده، یعنی یکی از ارقام دودوییِ یک عدد، هر بار و بهطور نامحسوس، اشتباه خوانده میشود. نتیجه: ماشین بدون هیچ علامت هشداری با اطمینان کامل جواب غلط میدهد. آشنا به نظر میرسد؟ این دقیقاً همان رفتاری است که امروز از باگهای نرمافزاری میبینیم — با این تفاوت بزرگ که باگ ۱۹۴۷ را میشد با چشم دید، با پنس درآورد و با چسب به لاگبوک بچسباند.
#
اما واژهی Bug آن شب متولد نشد
محبوبترین سوءتفاهم این ماجرا این است که «واژهی باگ در ۱۹۴۷ در هاروارد ساخته شد». نه. این واژه وقتی به کامپیوترها رسید، اصلاً پیر شده بود. قدیمیترین سند مشهور، نامهای است از توماس ادیسون به همکارش تئودور پوشکاش، در سال ۱۸۷۸ — یعنی ۶۹ سال قبل از شبپرهی هاروارد:
“…then difficulties arise — this thing gives out and [it is] then that
‘Bugs’ — as such little faults and difficulties are called —
show themselves…”
ادیسون، ۱۸۷۸: «آنوقت مشکلات پدیدار میشوند… و باگها — که به این خطاها و دشواریهای کوچک میگویند — خودشان را نشان میدهند…»
ادیسون و مهندسانِ پس از او، به خطاهای گریبانگیرِ دستگاهها مدتها بود که «باگ» میگفتند و جالب اینکه چیزهایی مثل «bug trap» — وسیلهای برای بهدامانداختن خطاها — هم در ادبیات مهندسی آن دوره وجود داشت. پس وقتی تیم هاروارد شبپره را پیدا کرد، آنها واژهی جدیدی نساختند؛ بلکه یک بازی زبانی قدیمی را برای اولین بار به معنای واقعی کلمه محقق کردند. برای همین هم نوشتند «actual»: تا آن لحظه باگ مجازی و انتزاعی بود؛ اینبار، یک بار هم که شده، خودِ باگ را در دست گرفتند.
تصور رایج
واژهی Bug در ۱۹۴۷ با ماجرای شبپره اختراع شد
واقعیت
واژه از دههها قبل اسلنگ مهندسی بود؛ هاروارد اولین موردِ لفظبهلفظِ آن را ثبت کرد
واژهی debug هم — دیباگکردن، حذف باگ — در همان سالهای آغازین کامپیوتر رایج شد و گریس هاپر، که الان به او میرسیم، بیش از هر کس دیگری در جاودانهکردن هر دو داستان نقش داشت.
#
گریس هاپر؛ زنی که شبپره را جاودانه کرد
قصهی شبپره بدون گریس هاپر، فقط یک اتفاق کوچک در سپتامبر ۱۹۴۷ بود. هاپر ریاضیدانی بود که در ۱۹۴۳ به نیروی دریایی آمریکا پیوست و به پروژهی ماشینهای حسابِ هاوارد آیکن در هاروارد فرستاده شد؛ از Mark I شروع کرد و در تیم Mark II و Mark III هم بود. بعد از جنگ به دنیای کامپیوترهای تجاری رفت و همانجا کارهایی کرد که بعضیها آنها را از جدیترین کارهای تاریخ نرمافزار میدانند:
1
اولین کامپایلر تاریخ (A-0، سال ۱۹۵۲)
برنامهای که خودش برنامهی دیگر مینوشت — وقتی هیچکس باور نداشت کامپیوتر بتواند «خودش را برنامهریزی کند»
2
از FLOW-MATIC تا COBOL
زبانش الهامبخش COBOL شد؛ زبانی که هنوز — باورش سخت است — بخشی از سیستمهای بانکی دنیا روی آن کار میکنند
★
امیر دریاییِ ۷۹ ساله
تا ۱۹۸۶ در سن ۷۹ سالگی خدمت کرد — مسنترین افسر فعال آن روزهای نیروی دریایی؛ ناوشکن USS Hopper و نشان افتخار ریاستجمهوری هم به نام اوست
هاپر را با یک شیء کوچک هم میشناسند: تکهسیمهای حدود ۳۰ سانتیمتری که در جلسات پخش میکرد تا نشان بدهد نور در یک نانوثانیه چه مسافتی میرود — «اینجا یک نانوثانیه است، این هم میکروثانیه؛ حالا ببینید چرا برنامهتان اینقدر کند است». قصهی شبپره را هم همیشه با همان لذت تعریف میکرد و همان صفحهی لاگبوک سالها بعد به اسمیتسونیان رفت. جملهی معروفش هم درست همان جور که زندگی کرده بود: «گرفتن اجازه سختتر است تا بخشیدن — راحتتر است بعداً عذرخواهی کنی.»
#
آن شب، هنرِ دیباگ متولد شد
شاید مهمترین بخش ماجرا، خودِ شبپره نباشد؛ بلکه روشی باشد که با آن پیدا شد. از میان ۱۳ هزار رله، رلهی ۷۰ چطور پیدا شد؟ قطعاً نه با بازکردن تکتک درچهها و دعا کردن. اپراتورها همان کاری را میکردند که هر مهندس عاقلی میکرد: بازهی مشکوک را قدمبهقدم باریکتر میکردند.
1
بازتولید خطا — ماشین روی چه ورودیای جواب غلط میدهد؟
2
نصفکردن بازه — نیمهی اول سالم است یا خراب؟ هر جواب، نصفِ رلهها را کنار میگذارد
3
تکرار روی نیمهی معیوب — هر بار فضا را نصف کن
4
ریشهیابی و ثبت — شبپره را درآور، ماجرا را در لاگبوک ثبت کن
این همان روش نیمنمایی (half-split) است که تعمیرکاران تجهیزات الکترونیکی امروز هم یادشان میدهند، و در قالب الگوریتم، همان جستجوی دودویی است. زیباییاش در این عدد است:
تعداد تستها ≈ ⌈log₂ N⌉ → ۱۳٬۰۰۰ رله ≈ فقط ۱۴ تست
هر تست، فضای جستجو را نصف میکند؛ هزینهی جستجو بهجای خطی، لگاریتمی رشد میکند
ⓘ
این ایده امروز کجاست؟ در git bisect. یک کامیت سالم و یک کامیت خراب به git میدهید و خودش با جستجوی دودویی روی تاریخچه، وسطها را میآزماید تا کامیتِ مقصر را پیدا کند — دقیقاً همان نیمنماییِ سال ۱۹۴۷، این بار روی گراف کامیتها. breakpoint، لاگگیری و حذف تدریجی کد مشکوک هم همه فرزندان همان روشاند: خطا را بازتولید کن، بازه را باریک کن، ریشه را ببین.
#
بیایید همان شب را با Python بازپخش کنیم
یک پنل کوچک ۸ رلهای شبیهسازی میکنیم. برنامه یک بایت را در پنل ذخیره میکند، اما یک شبپره (تصادفی) داخل یکی از رلهها گیر کرده و همان بیت را همیشه غلط میخواند. اول «نشانهی خطا» را میبینیم — تفاوت مقدار ذخیرهشده و مقدار خواندهشده — بعد با همان نیمنمایی سال ۱۹۴۷، شبپره را پیدا میکنیم:
moth_finder.py
# moth_finder.py - the night of Sept 9, 1947, replayed
import random
NUM_RELAYS = 8
moth = random.randrange(NUM_RELAYS) # the moth lands somewhere
# what the program stored vs what the panel reads back:
stored = 0b10110101
readback = stored ^ (1 << moth) # one stuck relay = one wrong bit
print(f"stored : {stored:08b} ({stored})")
print(f"readback: {readback:08b} ({readback})")
print("a relay is lying - time to hunt\n")
def section_is_faulty(lo, hi):
return lo <= moth < hi # the half-split probe
probes = 0
lo, hi = 0, NUM_RELAYS
while hi - lo > 1:
mid = (lo + hi) // 2
probes += 1
faulty = section_is_faulty(lo, mid)
print(f"probe {probes}: test relays {lo}..{mid-1} -> "
+ ("FAULTY"if faulty else"ok"))
if faulty: hi = mid
else: lo = mid
print(f"\nmoth found in relay #{lo} after {probes} probes")
print(f"Mark II's 13000 relays would need only "
f"{13000 .bit_length()} probes")
یکی از اجراهای برنامه (هر بار شبپره جای دیگری مینشیند):
output.txt
stored : 10110101 (181)
readback: 10110001 (177)
a relay is lying - time to hunt
probe 1: test relays 0..3 -> FAULTY
probe 2: test relays 0..1 -> ok
probe 3: test relays 2..2 -> FAULTY
moth found in relay #2 after 3 probes
Mark II's 13000 relays would need only 14 probes
دو نکته دربارهی این خروجی: اول، اختلاف stored و readback فقط یک بیت است — بیت شماره ۲ — و دقیقاً همین «یک بیتِ همیشهغلط» بود که آن شب در هاروارد ماشین را دروغگو کرده بود. دوم، عدد پایانی: 13000.bit_length() همان ⌈log₂ 13000⌉ است؛ یعنی حتی آن ماشین غولآسای ۱۳ هزار رلهای هم برای مهندسانِ صبور، حداکثر حدود ۱۴ تست فاصله تا شبپره داشت.
#
آزمایشگاه: شما اپراتور Mark II هستید
ساعت ۱۵:۴۵ است و Mark II دوباره جواب غلط میدهد. یکی از ۸ رلهی زیر درست کار نمیکند و در یکی از آنها شبپره نشسته. با دکمهی تست، بازهی مشکوک را نصف کنید و وقتی به یک رله رسیدید، روی خود آن رله کلیک کنید تا شبپره را بردارید. سؤال این است: در چند تست پیدایش میکنید؟
moth_lab.exe — interactive
رلههایی که حاشیهی روشن دارند، بازهی مشکوک فعلیاند؛ رلههای کمرنگ از فهرست خطا خارج شدهاند.
چرا ۳ تست کافی است؟ هر تست، فضای جستجو را نصف میکند: ۸ → ۴ → ۲ → ۱. سه بار نصفکردن، هشت رله را به یک رله میرساند. برای همین است که log₂ N اینقدر قدرتمند است: فضای جستجو هزار برابر شود، تستها فقط ده تا اضافه میشوند.
#
چرا ماجرای یک شبپره هنوز مهم است؟
بخش زیادی از جذابیت این قصه در یک تفاوت ساده با امروز است: باگ آن شب فیزیکی و قابلدیدن بود. میشد با چشم پیدا کرد، با پنس بیرون آورد و با چسب به لاگبوک چسباند. باگهای امروز — یک race condition، یک اشارهگر آویزان، یک توکنِ اشتباه در آرایهی احتمالات مدل زبانی — هیچکدام جسم ندارند. ما همان کار را با breakpoint و لاگ و تست خودکار انجام میدهیم، اما شبپرهای در کار نیست که قاب بگیریم.
آنچه از ۱۹۴۷ تا امروز دستنخورده مانده، روش و نگرش است: خطا را بازتولید کن. بازهی مشکوک را قدمبهقدم باریک کن. وقتی ریشه را دیدی، درستش کن و ماجرا را ثبت کن — همان کاری که آن تیم با چسباندن شبپره به لاگبوک کرد. آنها نتوانستند جلوی رسیدنِ شبپره را بگیرند، اما کاری کردند که از آن پس هیچ باگی بدون ثبت و سند نماند.
و یک نکتهی آخر برای آن شبهای طولانی دیباگ: وقتی ساعت از نیمهشب گذشته و خطا هنوز برندهی میدان است، یادتان باشد اولین باگ تاریخ کامپیوتر یک موجود بیمغز بود که فقط به سمت نور رفته بود. بعضی وقتها مشکل سیستمی و عمیق است؛ بعضی وقتها هم فقط یک شبپره است که باید پیدایش میکردید.
takeaway.txt
هر باگی بالاخره پیدا میشود —
فقط اولینشان بال داشت.
تاریخ انتشار: ۱۴۰۵/۰۷/۱۰ · آخرین بهروزرسانی: ۱۴۰۵/۰۷/۱۰
author.dat
علی زمانی
توسعهدهنده فولاستک
توسعهدهنده فولاستک با تخصص در وب، هوش مصنوعی و توسعه بازی.