ماه گذشته، یک دستیار هوش مصنوعی یک اسکریپت Python برای یک پروژه عملیاتی تولید کرد. خروجی بدون خطا اجرا شد و دادهها نیز درست به نظر میرسیدند. اما یک بررسی دستی، وجود الگوی پرسوجوی N+1 را در فراخوانیهای پایگاه داده آشکار کرد. برای یک مجموعه داده کوچک، کد به خوبی عمل میکرد؛ اما با افزایش مقیاس به هزاران رکورد، برنامه برای اشیاء والد یک پرسوجو صادر میکرد و سپس هزاران پرسوجوی پیدرپی برای دادههای مرتبط اجرا میکرد. نتیجه، یک سقوط فاجعهبار در عملکرد بود که هیچ تست واحدی (unit test) قادر به شناسایی آن نبود.
این واقعیت توسعه نرمافزار مدرن است. ابزارهای هوش مصنوعی اکنون کدنویسی، عیبیابی و پیشنهادهای معماری را با سرعتی انجام میدهند که هیچ انسانی نمیتواند با آن برابری کند. این سرعت واقعی است، اما اساساً ماهیت شغلی شما را تغییر میدهد. شما دیگر عمدتاً برای تایپ کردن نحو (syntax) حقوق نمیگیرید؛ بلکه برای بازرسی، طراحی معماری و شناسایی دقیق همین نوع تلههای نامرئی حقوق میگیرید.
خطر خاموشِ «منطقی اما غلط»
کدهای تولید شده توسط هوش مصنوعی اغلب درست به نظر میرسند، زیرا کامپایل میشوند، اجرا میشوند و مقدار مورد انتظار را برمیگردانند. منطق آنها در ظاهر درست است، اما در لایههای زیرین میتواند به شکلی خاموش، خراب باشد.
عبارتهای منظم (regular expressions) را در نظر بگیرید. یک هوش مصنوعی ممکن است الگویی به شما بدهد که آدرسهای ایمیل یا شناسهها را در زبان انگلیسی به شکلی بینقص مطابقت دهد. اما همان عبارت را در برابر اوملاتهای آلمانی، خطوط عربی یا موارد خاص نرمالسازی Unicode اجرا کنید، خواهید دید که بیصدا شکست میخورد. کد از نوعی نیست که خطایی (exception) پرتاب کند؛ بلکه صرفاً دادههای معتبر دنیای واقعی را نادیده میگیرد.
پرسوجوهای پایگاه داده نیز ریسک مشابهی دارند. یک هوش مصنوعی میتواند یک پرسوجوی PostgreSQL بنویسد که در طول تست، ردیفهای درست را برمیگرداند، اما همچنان جداول شما را با تاپلهای مرده (dead tuples) پر کند، از استفاده از ایندکسها چشمپوشی کند یا اسکنهای ترتیبی (sequential scans) را تحمیل کند که بارهای کاری محیط عملیاتی (production) را فلج میکند. آنچه در یک مجموعه داده آزمایشی کار میکند با آنچه تحت بار واقعی کار میکند، دو چیز کاملاً متفاوت است. ماشین تأخیر (latency) را حس نمیکند و هزینه سرویسهای ابری را پرداخت نمیکند.
از نوشتن تا تأیید کردن
تغییر اساسی، حرکت از «چگونه این را بنویسم؟» به سمت «چگونه این را تأیید کنم؟» است. وقتی هوش مصنوعی پیشنویس اول را انجام میدهد، بار شناختی شما باید به مراحل بعدی منتقل شود. شما باید کد را همانگونه بخوانید که یک بازرس امنیتی میخواند، نه آنگونه که یک نویسنده خسته، کار خودش را سرسری مرور میکند.
این امر مستلزم نوع متفاوتی از انضباط است. سوگیری خودکارسازی (Automation bias) یک واقعیت است. وقتی ابزاری خروجی روان و از نظر نحو بینقص تولید میکند، مغز انسان آرام میگیرد. شما فرض را بر درست بودن میگذارید چون ارائه آن صیقلخورده است. مقاومت در برابر این تکانه، مهارت اصلی امروز است. شما باید فرض کنید که هر پیشنهاد، تا زمانی که خلاف آن ثابت نشده، تنها یک فرضیه است.
کار با ماشین
گرفتن خروجی مفید از یک دستیار کدنویسی هوش مصنوعی، به معنای سریعتر تایپ کردن نیست؛ بلکه به معنای کاهش فاصله بین دادههای آموزشی ماشین و واقعیت خاص شماست. شما میتوانید این فاصله را با چند تمرین ملموس کاهش دهید.
در دستورات (prompts) خود دقیق باشید. ابهام در اینجا شعر نمیسازد، بلکه باگ ایجاد میکند. دستوری مانند "optimize this function" باعث دریافت توصیههای کلی میشود. در عوض، بنویسید: "refactor this Python loop to use a single bulk database update instead of iterated saves". دقت بالا، فضای احتمالات را محدود میکند.
زمینه (context) واقعی ارائه دهید. هوش مصنوعی نمیداند که شما در حال اجرای Django 4.2 روی PostgreSQL 15 در یک کلاستر Kubernetes با محدودیت زمانی ۳۰ ثانیهای برای درخواستها هستید، مگر اینکه خودتان بگویید. نسخههای وابستگیها، کتابخانههای داخلی و محدودیتهای غیرقابل مذاکره خود را به آن بدهید. زمینه، صرفاً تزئین نیست؛ بلکه حفاظهای ایمنی است.
پاسخها را با اسناد خودتان مستند کنید. تولید تقویتشده با بازیابی یا RAG، فقط یک واژه پرزرقوبرق برای چتباتها نیست. دستیار خود را به سمت مشخصات واقعی API، سوابق تصمیمات معماری و قراردادهای کد خود هدایت کنید. وقتی مدل به جای حدس زدن از دادههای آموزشی، حقایق را از مستندات شما بازیابی میکند، شکاف بین توصیههای عمومی و کد قابل استفاده به طرز چشمگیری کاهش مییابد.
کارهای پیچیده را به وظایف مجزا تقسیم کنید. الگوهای عامل (Agent patterns) زمانی بهترین عملکرد را دارند که هر مرحله محدوده مشخصی داشته باشد. درخواست بازنویسی (refactor) کامل یک میکروسرویس را در یک مرحله ندهید. ابتدا طرحواره داده (data schema) را بخواهید. آن را تأیید کنید. سپس اسکریپت مهاجرت (migration script) را بخواهید. آن را هم تأیید کنید. سپس به سراغ لایه سرویس (service layer) بروید.
