پذیرش بدون تحلیلِ اولین راهکار هوش مصنوعی میتواند بهآرامی معماری یک کدبیس را نابود کند. این درسِ سخت، حاصل تجربه کارسون گراس (Carson Gross)، خالق زبان hyperscript است که در ۲۹ ژوئن ۲۰۲۶، تلاشش برای رفع یک نقص فنی (Regression) در نسخه ۰.۹.۹۱ با کمک مدل Claude را مستند کرد.
این اتفاق در دورانی رخ میدهد که پدیده «کدنویسی با حس» یا Vibe Coding — یعنی توسعه نرمافزار بدون درک عمیق از منطق زیربنایی — در حال رایج شدن است. گراس استدلال میکند که اگرچه AI یک ضربهگیر بهرهوری است، اما خطر ایجاد وضعیت «شاگرد جادوگر» را دارد؛ سناریویی که در آن توسعهدهندگان چنان به AI وابسته میشوند که دیگر قادر به درک یا رسیدگی درست به مشکلاتی که در سیستمهای خود میسازند، نیستند. او بهطور کلی نسبت به AI ambivalent یا ambivalent (تردیدآمیز) است؛ از یک سو قدرت آن را میپذیرد و از سوی دیگر نسبت به خطراتی چون کند شدن تدریجی قوای ذهنی افراد و نگرانیهای جمعی درباره محیط زیست و گرانتر شدن محاسبات شخصی هشدار میدهد.
زمینه: تجزیهکننده Hyperscript
برای درک این باگ، ابتدا باید ماهیت منحصربهفرد hyperscript را شناخت. این زبان یک زبان اسکریپتنویسی جایگزین برای وب است که بهطور طنزآمیزی کاملاً با جاوااسکریپت نوشته شده است.
گراس این نرمافزار را «قطعهای عجیب» مینامد؛ زیرا او در زمان خلق آن، بهطور عمدی بسیاری از قوانین سنتی تجزیه و تحلیل دستورات (Parsing) را به عنوان یک آزمایش شکست. او میخواست ببیند اگر از رویههای استاندارد فاصله بگیرد، نتایج چگونه خواهد بود.
بر اساس مستندات فنی گراس، ویژگیهای کلیدی معماری این زبان عبارتند از:
- منطق مکانمند (Colocated Logic): منطق تجزیه دقیقاً روی عناصر تجزیهشده قرار دارد.
- دستور زبان پویا (Dynamic Grammar): تجزیهکننده قابلیت جایگزینی (pluggable) دارد و گرامر بهصورت پویا تعریف میشود.
- دسترسی منعطف: از چندین نحو (syntax) مختلف برای دسترسی به ویژگیها پشتیبانی میکند.
گراس اعتراف میکند که این رویکرد را برای اکثر زبانهای برنامهنویسی توصیه نمیکند، اما برای این پروژه خاص جواب داده است. از نظر او، این پروژه نشان میدهد که در نرمافزار «راههای متعددی برای رسیدن به هدف وجود دارد».
باگ: تداخل در اتصال (Binding Conflict)
مشکل با گزارش یک کاربر درباره یک رگرسیون (پسرفت) در نسخه ۰.۹.۹۱ شروع شد. یک عبارت خاص دیگر بهدرستی تجزیه نمیشد: fetch {% url 'trade:get_symbol_data' %}?symbol=${symbol} as JSON.
این یک تداخل کلاسیک در اتصال (Binding Conflict) بود. بخش as JSON بیش از حد سخت متصل شده بود. بهجای اینکه بهعنوان یک اصلاحکننده (modifier) برای دستور fetch عمل کند (یعنی URL را بگیرد و نتایج را به عنوان JSON پردازش کند)، تجزیهکننده سعی میکرد رشتهی متنی را قبل از تحویل دادن به دستور fetch، به JSON تبدیل کند.
چون hyperscript زبانی با سبک xTalk است و ابهامات زبان انگلیسی را به ارث برده، این نوع تداخلات در تجزیه بسیار شدیدتر میشوند. این موضوع باعث میشود تداخل اتصال در hyperscript بهمراتب بدتر از زبانهای سختگیرانه و صلب باشد.
بررسی علت ریشهای
گراس برای یافتن علت ریشهای به Claude تکیه کرد و AI بهسرعت موفق شد. بررسیها نشان داد که در بازسازی (refactor) نسخه ۰.۹.۹۱، گراس در تلاش برای به اشتراک گذاشتن منطق بین دستورات go و fetch «بیش از حد تهاجمی» عمل کرده بود.
او متدی به نام parseURLOrExpression() را استخراج کرده بود. اما این بازسازی بهطور اتفاقی باعث شد گرامر بعد از دستور fetch گسترش یابد تا عبارات کلی (general expressions) را نیز شامل شود. این امر تداخلی ایجاد کرد چون کلمه کلیدی as در hyperscript دو معنای متمایز دارد:
۱. در عبارات کلی: یک عبارت تبدیل است که اجازه میدهد بین انواع دادهها تبدیل انجام دهید (مثلاً set x to "42" as Int).
۲. به عنوان اصلاحکننده دستور fetch: به دستور میگوید که پاسخ را چگونه تبدیل کند (مثلاً fetch https://hyperscript.org as Text).
بهطور ناخواسته، بازسازی کد باعث شد تجزیهکننده کلمه as را به عنوان یک «عبارت تبدیل» ببیند، نه یک «اصلاحکننده fetch». گراس اشاره میکند که ایده استفاده از یک کلمه کلیدی برای هر دو نقش، ممکن است باعث شود مهندسان تجزیهکننده «کمی حالت تهوع بگیرند».
مدل Claude توانست این نقطه حساس را در عرض چند دقیقه شناسایی کند؛ کاری که اگر گراس میخواست بهتنهایی انجام دهد، بسیار بیشتر زمان میبرد.
سه پیشنهاد شکستخوردهی هوش مصنوعی
در حالی که Claude در بررسی و شناسایی عالی بود، در ارائه راهکار برای رفع مشکل ضعیفتر عمل کرد. گراس اعتراف میکند که از روی تنبلی راهکار را از AI خواست، اما زنجیرهای از اتفاقات بعدی، خطرات معماریled-AI را نشان میدهد:
پیشنهاد اول (راهکار سرپایی/Hack): مدل پیشنهاد داد ابتدا یک برگ «شبیه به رشته» (string-like leaf) را تجزیه کند و سپس به سراغ عبارت کامل برود:
return this.parseElement("stringLike") || this.requireElement("expression");. گراس این را رد کرد چون بیش از حد به باگ گزارششده وابسته بود. اگر کاربر از یک متغیر بهعنوان هدف fetch استفاده میکرد (مثلاًfetch $url as JSON)، این راهکار شکست میخورد. او آن را «بیش از حد سرپایی و نه راهحل کلی» نامید، هرچند اشاره کرد که تجزیهکننده hyperscript در حال حاضر هم پر از هکهای ارگانیک است.پیشنهاد دوم (پیچیدگی بیهوده): هوش مصنوعی پیشنهاد داد یک پرچم (flag) به نام
noConversionsبه تجزیهکننده اضافه شود. این پرچم در اطراف تجزیه URL فعال میشد و متدAsExpression.parseدر صورت فعال بودن این پرچم، عملیات را متوقف میکرد:if (parser.noConversions) return;. گراس اشاره کرد که این کار تجزیهکننده را «وابسته به زمینه» (context-sensitive) میکند؛ تغییری که «بسیاری از مهندسان تجزیهکننده را به وحشت میاندازد». با این حال، او اشاره کرد که تجزیهکننده hyperscript در حال حاضر هم وابسته به زمینه است، بنابراین این پیشنهاد فقط پیچیدگی بیمورد اضافه میکرد.پیشنهاد سوم (اصلاح بیش از حد): گراس پیشنهاد داد از زیرساخت موجودِ «دنبالکنندهها» (follows) استفاده شود. در تجزیهکننده Recursive Descent زبان hyperscript، «دنبالکنندهها» توکنهایی هستند که توسط یک عنصر تجزیه بالاتر تصاحب میشوند تا عبارات پاییندستی با آنها تطابق پیدا نکنند. برای مثال، ویژگی
whenدر اعلانهای خود ازorبه عنوان جداکننده استفاده میکند نه به عنوان یک رابط منطقی:<div _="when $x or $y changes put it into me"></div>.
Claude موافقت کرد که این راهکار «کاملاً درست» است و اصلاحیه را در parseURLOrExpression() پیاده کرد. اگرچه این کار باگ را بهطور کلی رفع کرد و نیاز به زیرساخت جدید نداشت، اما بیش از حد گسترده بود. از آنجایی که fetch و go از این متد مشترک بودند، این اصلاح بهطور اتفاقی مانع از استفاده درست از عبارات تبدیل as در دستورات go شد.
مداخله انسانی
در نهایت، گراس خودش راهکار نهایی را که یک اصلاح «نیمهارگانیک» بود پیاده کرد. او متوجه شد که پیادهسازی AI بیش از حد کلی است. او مورد خاص را دقیقاً به متد FetchCommand#parse() محدود کرد تا تجزیه دستور go بدون تغییر باقی بماند. پیادهسازی نهایی او به این شکل بود:
parser.pushFollow("as"); try { var url = parser.parseURLOrExpression(); } finally { parser.popFollow(); } if (parser.matchToken("as")) { ... }
علیرغم شکستها در منطق معماری، گراس اشاره کرد که Claude در تولید تستها فوقالعاده عمل کرد. AI تستهای کوچک و متمرکزی ایجاد کرد که مشکل را نشان میداد و اصلاحیه را تأیید میکرد. گراس اعتراف کرد که این تستها جامعتر از آن چیزی بودند که او خودش انرژی لازم برای نوشتنشان داشته باشد.
تحلیل: هزینه آسایش شناختی
این پرونده نشان میدهد که عاملهای AI در حال حاضر در «کارهای سخت و تکراری» (مثل تستنویسی و جستوجو) بهتر هستند تا در «معماری». اگر گراس با جزئیات زیرساخت تجزیهکننده آشنا نبود، احتمالاً راهکاری را میپذیرفت که منجر به انباشت بدهی فنی (Technical Debt) — یعنی هزینهی اضافهای که بهدلیل تصمیمات سریع و غلط در کدنویسی ایجاد میشود و باید بعداً پرداخت شود — میشد؛ چه از طریق یک مورد خاص (edge case) سرپایی و چه از طریق اضافه کردن حالتهای (state) غیرضروری به تجزیهکننده.
گراس (بدون ارائه شواهد آماری) ادعا میکند که بدهی فنی بهصورت نمایی رشد میکند و باید در پروژهها به حداقل برسد. این داستان بر ارزش «انسان در حلقه» (Human-in-the-Loop) تأکید میکند؛ کسی که به جای «شاگرد»، نقش «جادوگر» را ایفا کند. جادوگر مشکل را میفهمد و خواستار راهکاری درست است که با معماری موجود سازگار باشد، در حالی که شاگرد صرفاً یک پیشنهاد کاربردی اما شلخته را میپذیرد.
شاید برخی به ایده کنترل پیچیدگی در کدبیس hyperscript بخندند، اما گراس استدلال میکند که در این سناریوی عینی، پیچیدگی توسط یک انسان آگاه که با یک عامل AI همکاری میکرد، مهار شد.
نکتهای درباره AI و توسعهدهندگان قدیمی
گراس تجربیات خود را به عنوان توسعهدهندهای که امسال ۵۰ ساله شده بازتاب میدهد. او اشاره میکند که توسعهدهندگان قدیمیتر معمولاً «قدرت ضربهشان را از دست میدهند»، بهویژه در دو حوزه:
- حافظه: او دیگر نمیتواند مانند گذشته موارد زیادی را به خاطر بسپارد. AI با این امکان که از طریق پرامپتهای مناسب، دوباره سیستمهای پیچیده را بهسرعت بفهمد، این مشکل را حل میکند. این امر به او اجازه میدهد بسیار کارآمدتر بین پروژههای متنباز و کاری جابهجا شود.
- استقامت: او دیگر نمیتواند ساعتهای طاقتفرسای یک توسعهدهنده جوان را کار کند. AI «سختکوشی» مربوط به ایجاد مجموعهتستهای گسترده را بر عهده میگیرد؛ کاری که حتی در دوران جوانیاش هم دنبال کردن آن برایش دشوار بود.
با این حال، او ابراز نگرانی عمیقی میکند که AI ممکن است باعث یک «پسرفت کلی» در هوش انسانی شود؛ فرآیندی که بهطور طبیعی با افزایش سن رخ میدهد. با بازنگری در رفع این باگ، گراس اعتراف کرد که از اینکه چقدر طولانی به Claude تکیه کرد پیش از آنکه خودش راه درست را اجرا کند، «کمی احساس شرم» میکند. او هشدار میدهد که تکیه بر AI برای دور زدن تلاش ذهنی، ممکن است زوال عقل را تسریع کند.
نتیجهگیری
در نهایت، این تجربه دوگانگی کمکهای AI را به تصویر میکشد. AI ارزش بیاندازهای در مرحله بررسی (Investigation) و تأیید (Verification) فراهم میکند، اما وقتی نوبت به یکپارچگی ساختاری میرسد، خطرناک است. تفاوت بین یک پروژه موفق و پروژهای که در بدهی فنی دفن شده، توانایی رد کردن یک «هک کاربردی اما زشت» به نفع یک «تطبیق دقیق معماری» است. با ظهور IDEهای عاملی (agentic) که تغییرات بزرگی را در کدبیسهای قدیمی پیشنهاد میدهند، تنش بین «کدنویسی با حس» و مهندسی نرمافزار رسمی تنها افزایش خواهد یافت.
گام بعدی شما
- هنگام پذیرش کد پیشنهادی AI، از خود بپرسید: «آیا این راهکار فقط یک مورد خاص را حل میکند یا با ساختار کلی سیستم همراستا است؟»
- برای کارهای تکراری مثل تستنویسی به AI تکیه کنید، اما در تصمیمات معماری، «انسان در حلقه» (Human-in-the-Loop) را حذف نکنید.
- اگر در یک پروژه قدیمی (Legacy) هستید، هر تغییر پیشنهادی AI را با بررسی اثرات جانبی روی سایر ماژولها بسنجید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما درباره تراشههای Blackwell مراجعه کنید.




گفتگو