ChatGPT، GitHub Copilot، Cursor و همخانوادههایشان حالا میتوانند قبل از اینکه تایپ کردن دستور (prompt) را تمام کنید، یک کامپوننت React تحویل دهند. اتصال یک مسیر Next.js به Supabase؟ در عرض چند ثانیه انجام میشود. بازنویسی (Refactor) آن ابزار پیچیده TypeScript؟ این هم سه گزینه، همراه با type guardها. برای هر کسی که با پشتههای (stacks) مدرن وب کار میکند، این تجربه میتواند تقریباً جادویی به نظر برسد.
من هر روز از این ابزارها استفاده میکنم. پشته من شامل Next.js، TypeScript و Supabase است و هوش مصنوعی دقیقاً در ویرایشگر من حضور دارد، آماده برای ساختاردهی (scaffold) هوکهای سفارشی، تولید کوئریهای پایگاه داده، یا تمیز کردن منطقهای شرطی نامنظم. در مقیاس کوچک، مانند یک برنامهنویس جونیور بسیار سریع عمل میکند. سینتکس را مثل کف دست میشناسد. سطوح API را که من باید در گوگل جستجو کنم، به خاطر میسپارد. از نوشتن کدهای تکراری (boilerplate) خسته نمیشود.
اما نرمافزارها همچنان دچار مشکل میشوند. اپلیکیشنها کندتر به نظر میرسند. داشبوردهای مشتریان لگ دارند. موارد خاص (edge cases) باعث کرش کردن فرمها میشوند. اگر هوش مصنوعی کدنویسی را تا این حد آسان کرده است، چرا استفاده از نرمافزار نسبت به چند سال پیش بدتر شده است؟
پاسخ این است که تولید سینتکس و ساخت نرمافزار، دو کار متفاوت هستند.
سینتکس، معماری نیست
هوش مصنوعی توکنها را به طرز فوقالعادهای مدیریت میکند. از آن بخواهید یک هوک useEffect بنویسد که یک کانال real-time در Supabase را گوش دهد، و چیزی دریافت خواهید کرد که بدون خطا کامپایل میشود. میتواند یک فایل JavaScript بدون تایپ را به TypeScript سختگیرانه تبدیل کند، یا قبل از اینکه قهوهتان را بنوشید، یک کامپوننت فرم با اعتبارسنجی Zod بسازد.
کاری که نمیتواند انجام دهد، درک ساختار و جزئیات اپلیکیشن خاص شماست. نرمافزار خوب نیازمند مدیریت وضعیت (state management) آگاهانه، مدیریت دقیق شرایط رقابتی (race conditions) و نقشهای شفاف از محل ذخیره دادهها در مقابل محل نمایش آنهاست. هوش مصنوعی فایلِ دمِ دست را میبیند، نه سیستم را. با کدبیس شما مانند یک راهروی متنی تخت برخورد میکند، نه یک ساختار زنده با دیوارهای باربر.
آن را مانند معماری تصور کنید که هرگز در یک خانه زندگی نکرده است. او میتواند نقشههای طبقات زیبایی بکشد. میداند یک اتاق خواب باید چند پنجره داشته باشد. اما نمیداند لولهها در ماه فوریه کجا معمولاً نشت میکنند، یا کدام راهرو در گرمای تابستان غیرقابل استفاده میشود. این دانشِ تجربی است که یک ساختمان را پابرجا نگه میدارد. کد هم دقیقاً به همین شکل عمل میکند.
دو نقطه اصطکاک
وقتی اجازه میدهم هوش مصنوعی قطعات بزرگتری از کد را بدون محدودیتهای (guardrails) سختگیرانه بنویسد، متوجه میشوم که همان دو مشکل بارها و بارها تکرار میشوند.
اول اینکه، الگوهای طراحی (design patterns) که قبلاً مستقر کردهاید را نادیده میگیرد. شاید تیم شما تمام عملیات دریافت داده را به یک لایه اختصاصی از هوکهای سفارشی منتقل کرده باشد. شاید قرارداد سختگیرانهای برای نحوه نگاشت سیاستهای RLS در Supabase به کمککنندههای (helpers) فرانتاند داشته باشید. هوش مصنوعی اهمیتی نمیدهد. اگر نوشتن یک supabase.from().select() خام مستقیماً در onClick یک دکمه، آن دستور (prompt) را حل کند، همین کار را انجام میدهد. کد اجرا میشود. حتی تمیز هم به نظر میرسد. اما این یک مورد استثنا (outlier) در کدبیس شماست، و هر مورد استثنایی، مالیاتی برای بازنویسی (refactoring) در آینده است. شش ماه بعد، کسی باید آن سوزن را پیدا کند، بفهمد چرا وجود دارد و با ملایمت آن را به مسیر اصلی بازگرداند.
دوم اینکه، وقتی سادگی کفایت میکند، به دنبال پیچیدگی میرود. این ابزار روی مخازنی (repositories) آموزش دیده است که آنقدر بزرگ هستند که به فکتوریهای انتزاعی (abstract factories)، الگوهای پیچیده reducer و کامپوننتهای مرتبه بالاتر (higher-order components) چندلایه نیاز دارند. وقتی از آن میخواهید یک فرم تماس ساده بسازد، ممکن است یک ماشین وضعیت (state machine)، یک context provider و یک انتزاع هوک سفارشی به شما تحویل دهد که در سه فایل پخش شده است. راه حل از نظر فنی غلط نیست؛ فقط سنگین است. هر لایه غیرضروری، بدهی شناختی (cognitive debt) اضافه میکند. شما کار را حذف نکردید، بلکه آن را با بهره (interest) به تعویق انداختید.
تله سرعت
یک حلقه بازخورد خطرناک در اینجا وجود دارد. هوش مصنوعی به شما اجازه میدهد ویژگیها را دو برابر سریعتر بسازید، اما توجه انسان به همان نسبت مقیاسپذیر نیست. اگر در نصف زمان معمول محصول را عرضه میکنید، آیا دو برابر زمان بیشتری را صرف بررسی کد (code review) میکنید؟ آیا تستهای بیشتری مینویسید یا کمتر؟
در عمل، اعتماد کردن به کد تولید شده بسیار آسان است، چون معتبر به نظر میرسد. از سینتکس مدرن استفاده میکند. کامنتها دقیقاً در جاهای درست پراکنده شدهاند. نام متغیرها حرفهای به نظر میرسد. باگهای ظریف در پس این ظاهر صیقلخورده پنهان شدهاند. مثلاً یک آرایه وابستگی (dependency array) در یک هوک که یک setter را جا انداخته است. یک تایپ TypeScript که از نظر فنی درست است اما اجازه میدهد یک حالت null وجود داشته باشد که فراموش کردهاید مدیریت کنید. یا یک کوئری Supabase که فراموش میکند ردیفهای حذفشده نرم (soft-deleted) را در طرحواره (schema) خاص شما در نظر بگیرد. شما به جای خواندن خط به خط، کد را سرسری میخوانید، چون سرعت تحویل محصول این را ایجاب میکند. سرعت در روز دوشنبه عالی به نظر میرسد، اما جلسه عیبیابی (debugging) در روز جمعه تا نیمهشب طول میکشد.
هزینه واقعی
کسانی که هزینه این کار را میدهند، توسعهدهندگان نیستند؛ بلکه کاربران نهایی هستند.
نرمافزار سنگینتر و دشوارتر به نظر میرسد، زیرا پیچیدگی سریعتر از توانایی تیمها در مدیریت آن در حال رشد است. ما با تیمهای کوچکتر و مسلح به ابزارهایی که به ما احساس شکستناپذیری میدهند، در حال ساخت اپلیکیشنهای بزرگتر هستیم. وقتی یک توسعهدهنده میتواند کل یک داشبورد را در یک بعدازظهر پیادهسازی کند، سازمان انتظار دارد تا چهارشنبه سه داشبورد آماده باشد. مقیاسپذیری بدون دقت، سیستمهای شکننده ایجاد میکند. حجم State به شدت بالا میرود. حجم باندلها به تدریج افزایش مییابد. شرایط رقابتی (Race conditions) افزایش مییابند. رابط کاربری ممکن است مدرن به نظر برسد، اما وقتی کاربر دکمه بازگشت را میزند، خودش را ریست میکند، یا چهار ثانیه طول میکشد تا hydrate شود، چون هیچکس وقت نداشته تا آبشاری از درخواستهای دادهی تولیدشده توسط هوش مصنوعی را تحلیل کند.
با ماشین کار کنید، نه برای آن
هیچکدام از اینها به این معنا نیست که باید هوش مصنوعی را از ویرایشگر خود بیرون بیندازید. بلکه به این معناست که به مرزهایی نیاز دارید.
از آن برای کارهایی که در آنها مهارت دارد استفاده کنید. اجازه دهید کارهای کسلکننده را انجام دهد: اینترفیسهای تکراری TypeScript، کوئریهای boilerplate Supabase، و تنظیمات Jest.
