پرش به محتوای اصلی
پرش به محتوای مقاله

«کاهش توکن‌ها از ۱۵۹ به ۲۷ هزار»؛ دستاورد بازسازی کدهای هوش مصنوعی

·۸ مرداد ۱۴۰۵۱۴ دقیقه مطالعه
بازآرایی کد: صرفه‌جویی هزینه نگهداری نرم‌افزار و افزایش بهره‌وری توسعه‌دهندگان
بازآرایی کد: صرفه‌جویی هزینه نگهداری نرم‌افزار و افزایش بهره‌وری توسعه‌دهندگان
اشتراک‌گذاری
واقعاً چه چیز جدید است؟

ارائه اولین داده‌های کمّی که ثابت می‌کند بازسازی کد (Refactoring) سنتی، مستقیماً توکن‌های ورودی عامل‌های کدنویس را تا ۸۳٪ کاهش می‌دهد و بدهی فنی AI را به هزینه دلاری تبدیل می‌کند.

۸۳ درصد؛ این عدد دقیقِ کاهش هزینه‌ی توکن‌های ورودی است که با پاک‌سازی بدهی‌های فنیِ تولیدشده توسط هوش مصنوعی به‌دست آمده است. طبق اعلام مارتین فاولر، متخصص برجسته‌ی مهندسی نرم‌افزار، در آزمایش دقیقی که ۳۰ ژوئیه ۲۰۲۶ منتشر شد، ثابت شد که به‌کارگیری انضباط سنتی بازسازی کد، مستقیماً هزینه‌ی عملیاتی مهندسی عامل‌محور (Agentic Engineering) را کاهش می‌دهد.

تصور کنید برنامه‌نویسی هستید که با استفاده از عامل‌های هوش مصنوعی، هزاران خط کد را بدون بازبینی دستی منتشر می‌کند. جذابیت این ابزارها در سرعت است، اما این سرعت یک مالیات پنهان دارد. عامل‌ها تمایل دارند فایل‌ها را به‌صورت یک‌سره رشد دهند و الگوها را تکرار کنند؛ تا جایی که ماژول‌ها به «تک‌سنگی‌های» (Monoliths) عظیمی تبدیل می‌شوند که هر بار برای یک تغییر کوچک، حجم زیادی از پنجره متنی (Context Window) — مثل میز کاری که جا برای چند ورق دارد، نه برای کل کتابخانه — و پول شما را می‌بلعند.

همان‌طور که در تحلیل‌های قبلی ما درباره‌ی امنیت و بهینه‌سازی مدل‌های بازمتن اشاره کردیم، سازماندهی داده‌ها کلید بهره‌وری است. آزمایش فاولر در لحظه‌ای حساس رخ داد؛ زمانی که صنعت از تعاملات ساده‌ی پرسش-پاسخ به سمت گردش‌کارهای پیچیده‌ی عامل‌محور حرکت می‌کند. این رویکرد در صنایع مختلف در حال گسترش است و برای مثال، می‌توانیم شاهد تغییر نقش عامل‌ها از گزارش‌دهی ساده به اجرای عملیاتی کمپین‌های بازاریابی باشیم. این عامل‌ها برای اعمال تغییر، ابتدا باید کد موجود را بخوانند تا بفهمند تغییرات را دقیقاً کجا اعمال کنند. اگر کد یک آشفتگی سازمان‌نیافته باشد، عامل بیش از نیاز می‌خواند و هزینه هر ویرایش بالا می‌رود.

مشکل تک‌سنگی

فاولر یک اپلیکیشن پیچیده با حدود ۱۵۰ هزار خط کد (LoC) ساخت. بدنه اصلی این برنامه با زبان Rust (حدود ۱۲۰ هزار خط) و بقیه با TypeScript و Terraform نوشته شده بود. این برنامه دارای یک رابط کاربری وب با کیفیت بالا بود که قابلیت‌های رفرش دینامیک، مودال‌ها، ذخیره‌سازی خودکار (auto-save)، یکپارچگی با سیستم‌های خارجی، یادگیری ماشین، تحلیل متن و کارهای پس‌زمینه (background jobs) را داشت و تمامی این‌ها توسط یک محیط استقرار کاملاً خودکار پشتیبانی می‌شد.

در حالی که کل برنامه توسط عامل‌ها — عمدتاً Claude Code و مقداری Cursor — نوشته شده بود، بهداشت معماری کاملاً نادیده گرفته شد. فاولر اعتراف کرد که کدهای تولید شده را بازبینی نکرده است و فقط گهگاه از روی کنجکاوی آن‌ها را نگاه می‌کرد. او تنها زمانی متوجه تورم کد شد که دید برای ویرایش خط ۴۰۰۰ از یک فایل، باید حجم عظیمی از متن در ترمینال اسکرول شود.

به‌طور مشخص، یک لایه‌ی دسترسی به داده به یک فایل Rust تبدیل شده بود که ۱۷ هزار و ۱۵۵ خط داشت. بر اساس مستندات این آزمایش، این فایل از مشکلات بحرانی رنج می‌برد:

  • نبود هیچ‌گونه حذف تکرار در منطق کد (Zero de-duplication).
  • فقدان یک زبان دامنه داخلی (Internal Domain Language).
  • تکرار شدید تنظیمات درخواست‌های HTTP، کدگذاری JSON و رمزگشایی آن‌ها برای هر عملیات خواندن یا نوشتن.
  • استخراج حداقلی توابع یا کلاس‌ها.

آزمایش بازسازی

فاولر برای سنجش سود اقتصادی پاک‌سازی این کد، یک خط مبنا (Baseline) تعریف کرد. او تغییری را توصیف کرد که باید توسط یک پرامپت واحد انجام شود: افزودن یک ItemWatchStore public async trait به لایه‌ی Firestore. این Trait نیازمند سه متد خاص بود: watch_item ،unwatch_item و watched_items_for_user. طبق طراحی، این «دیده‌بان‌ها» (watches) باید در یک مجموعه (collection) در Firestore به نام item_watches با فیلدهای itemId ،userId و createdAt ذخیره می‌شدند.

او از عامل خواست تا این مورد را هم برای FakeStore (با استفاده از یک فیلد در حافظه از نوع Vec<(String, String)>) و هم برای FirestoreStore (با استفاده از الگوهای HTTP موجود) پیاده‌سازی کند. او از یک عامل کاملاً جدید خواست این تغییر را اعمال کند و میزان مصرف توکن را ثبت کرد. چون عامل‌ها در یک جلسه جدید چیزی «یاد نمی‌گیرند»، او توانست بعد از هر مرحله از بازسازی، دوباره همان تغییر را از یک sub-agent جدید بخواهد تا یک خط مبنای علمی و بدون اثر یادگیری داشته باشد.

او سپس یک برنامه بازسازی ۱۵ مرحله‌ای را بر اساس اصول کتاب Refactoring (ویرایش دوم) اثر مارتین فاولر اجرا کرد. این فرآیند مکانیکی بود؛ او از اسکریپت‌های پایتون با grep و sed برای جابجایی کدها استفاده کرد، زیرا متوجه شد Claude در اجرای دقیق بازسازی‌ها دچار مشکل می‌شود و اغلب در فاصله‌گذاری‌ها (Indentation) گیج می‌زند.

تفکیک ماژولار

فاولر یک نظم سخت‌گیرانه را دنبال کرد تا هر مرحله به‌طور مجزا تست و تأیید شود. هدف این بود که اکنون توکن مصرف کند تا مصرف توکن در آینده کاهش یابد.

فاز ۱: استخراج منطقی

  • FirestoreClient (استخراج کلاس ۷.۵): جداسازی انتقال HTTP (شامل هدرهای احراز هویت، ساخت URL، reqwest::Client ،project_id ،MetadataAuth و documents_url()) از سازمان‌دهی پرس‌وجوهای دامنه. این کار حدود ۱۲۰۰ خط از پیاده‌سازی‌های FirestoreStore را حذف و در مقابل حدود ۱۲۰ خط کد خالص اضافه کرد.
  • کمک‌کننده‌های تجزیه (استخراج تابع ۶.۱): استخراج تابع extract_doc_id برای جایگزینی یک عبارت تکراری (doc.name.rsplit('/').next()?.to_string()) که در ۲۰ تابع تجزیه استفاده شده بود. همچنین ایجاد یک تابع کارخانه (Factory) به نام new_link برای جایگزینی یک بلوک ۱۰ خطی (تنظیمات HashMap/UUID) که ۶۲ بار تکرار شده بود.
  • کمک‌کننده‌های پرس‌وجوی لینک (استخراج تابع ۶.۱): استخراج دو الگوی تکراری از پیاده‌سازی‌های Trait؛ الگوی A برای جمع‌آوری تمام اسناد لینک از ردیف‌های پرس‌وجو (در حدود ۱۵ سایت) و الگوی B برای پرس‌وجوی لینک‌ها و بازگرداندن دقیقاً یک شناسه هدف (در ۸ سایت).
  • گزاره‌های FakeStore (استخراج تابع ۶.۱): استخراج دو متد در FakeStoreInner برای جایگزینی زنجیره‌های تکراری .iter().filter(...) در ۱۵ متد مختلف. مواردی که به گزاره دوم (مانند to_kind) نیاز داشتند، اکنون از طریق .into_iter().filter(...) به نتیجه‌ی تابع کمکی متصل می‌شدند.

فاز ۲: بهینه‌سازی ساختاری

  • سازنده‌های مقدار (جایگزینی کد inline ۸.۵): افزودن چهار تابع آزاد (free function) خصوصی قبل از بلوک کدک (codec block). این کار بیش از ۱۲۸ فراخوانی inline ماکروی json! (مانند stringValue و timestampValue) را با توابع کوتاه جایگزین کرد و ماکروهای چند-خطی را به تک-خطی تبدیل نمود.
  • FieldsBuilder (استخراج کلاس ۷.۳): ایجاد یک Builder برای مدیریت فرآیند تکراری درج در serde_json::Map. او حدود ۲۰ تابع انکودر را که قبلاً ساختار صلب درج در Map و بسته‌بندی JSON داشتند، بازنویسی کرد. این کار انکودرهای ۴۰ خطی را به حدود ۱۲ خط کاهش داد.

فاز ۳: تجزیه فایل‌ها (جابجایی تابع ۸.۱)

فاولر فایل src/firestore.rs را به یک دایرکتوری ماژول (src/firestore/mod.rs) تبدیل کرد و ۱۷ هزار خط را بین ۱۹ فایل تقسیم کرد:

  • queries.rs: انتقال ۳۲ ثابت LinkQuery و تعریف تایپ‌ها (EqFilter ،EqValue ،Ordering ،Direction).
  • traits.rs و پوشه traits: انتقال ۱۷ Trait عمومی به چهار فایل هم‌راستا با دامنه: فایل planning.rs (برای ConcentrationStore، GoalStore و غیره)، فایل content.rs (برای CaptureStore، TagStore و غیره)، فایل people.rs (برای ThoughtworkerStore، CompanyStore و غیره) و فایل system.rs (برای SessionState، LinkStore و غیره). تایپ‌های خطای مرتبط نیز به همراه Traitهای خود منتقل شدند.
  • codec.rs: تجمیع توابع انکودر/دیکودر، FieldsBuilder و سازنده‌های مقدار در یک ماژول ۴۰۰ تا ۵۰۰ خطی.
  • fake_store.rs: انتقال FakeStore ،FakeStoreInner و تمام ۱۸ بلوک پیاده‌سازی Trait. این کار باعث کاهش ۴۷۰۰ خطی فایل mod.rs شد.
  • پوشه store: تقسیم پیاده‌سازی‌های FirestoreStore به فایل‌های مجزا بر اساس هر Trait. فایل store/mod.rs تعریف Struct و FirestoreClient را حفظ کرد، در حالی که گروه‌های دامنه به ۱۰ فایل با اندازه ۱۲۰ تا ۶۵۰ خط منتقل شدند.
  • تست‌ها: انتقال ماژول‌های #[cfg(test)] به داخل فایل‌های هدف مربوطه. این کار حدود ۲۰۰۰ خط را از mod.rs خارج کرد و منطق تست را دقیقاً در کنار کدی قرار داد که آن را آزمایش می‌کرد.

بازآرایی کد: کاهش هزینه نگهداری و افزایش بهره‌وری توسعه‌دهندگان

نتایج کمّی

به نقل از وب‌سایت martinfowler.com، نتایج تکان‌دهنده بود. او از tiktoken برای تخمین توکن‌ها استفاده کرد (تقسیم تعداد کاراکترها بر ۴)، زیرا شمارش لحظه‌ای توکن‌های Claude غیرقابل اعتماد بود.

مرحله خطوط لایه‌ی داده بزرگ‌ترین فایل (خط) توکن‌های ورودی توکن‌های خروجی زمان (ثانیه)
مبنا ۱۷,۱۵۵ ۱۷,۱۵۵ ۱۵۹,۵۶۴ ۱,۷۰۵ ۳۴۲
مرحله ۱ ۱۶,۷۰۶ ۱۶,۷۰۶ ۱۵۵,۲۰۵ ۱,۷۲۳ ۵۳۰
مرحله ۲ ۱۶,۵۶۲ ۱۶,۵۶۲ ۱۵۹,۲۲۷ ۲,۱۰۵ ۵۷۴
مرحله ۳ ۱۶,۵۶۷ ۱۶,۵۶۷ ۱۵۴,۰۵۴ ۲,۱۰۵ ۵۲۴
مرحله ۴ ۱۶,۵۷۷ ۱۶,۵۷۷ ۱۵۴,۱۴۶ ۲,۰۶۰ ۶۵۴
مرحله ۵ ۱۶,۴۶۹ ۱۶,۴۶۹ ۱۷۱,۲۵۱ ۲,۰۳۶ ۱,۳۵۳
مرحله ۶ ۱۶,۴۶۹ ۱۶,۴۶۹ ۱۷۱,۲۵۱ ۲,۰۳۶ ۱,۳۵۳
مرحله ۷ ۱۶,۴۷۴ ۱۵,۶۷۰ ۱۵۱,۸۵۰ ۱,۸۰۰ ۵۸۷
مرحله ۸ ۱۶,۵۰۸ ۱۳,۸۴۵ ۱۳۲,۵۵۸ ۱,۷۲۳ ۴۴۶
مرحله ۹ ۱۶,۵۰۸ ۱۳,۸۴۵ ۱۳۲,۵۵۸ ۱,۷۲۳ ۴۴۶
مرحله ۱۰ ۱۶,۵۲۱ ۱۲,۸۴۶ ۱۳۱,۸۷۱ ۱,۷۵۰ ۵۴۰
مرحله ۱۱ ۱۶,۵۳۵ ۱۱,۱۲۲ ۱۳۳,۰۱۶ ۲,۴۶۰ ۶۰۰
مرحله ۱۲ ۱۶,۵۵۰ ۹,۲۶۹ ۱۰۴,۰۸۰ ۲,۰۵۰ ۴۹۰
مرحله ۱۳ ۱۶,۵۵۰ ۹,۲۶۹ ۱۰۴,۰۸۰ ۲,۰۵۰ ۴۹۰
مرحله ۱۴ ۱۶,۵۵۳ ۷,۲۲۵ ۱۰۷,۲۰۵ ۲,۴۵۳ ۵۲۳
مرحله ۱۵ ۱۶,۶۰۸ ۳,۶۹۵ ۲۷,۳۶۰ ۲,۱۱۳ ۴۵۴

در حالی که مجموع خطوط کد در لایه‌ی دسترسی به داده تقریباً ثابت ماند (و با ۱۶,۶۰۸ خط به پایان رسید)، حجم کدی که عامل باید می‌خواند به‌شدت کاهش یافت:

  • توکن ورودی مبنا: ۱۵۹,۵۶۴ توکن برای هر تغییر.
  • توکن ورودی نهایی: ۲۷,۳۶۰ توکن برای هر تغییر.
  • صرفه‌جویی کل: ۱۳۲,۲۰۴ توکن (کاهش ۸۳ درصدی).

اقتصاد توکن‌ها

با قیمت ۳ دلار به‌ازای هر میلیون توکن برای مدل Sonnet 5، یک تغییر ساده حدود ۳۹.۷ سنت سود داشت. اگرچه این مبلغ برای یک ویرایش ناچیز است، اما فاولر خاطرنشان می‌کند که این صرفه‌جویی در هر رفع باگ، افزودن ویژگی و جلسه دیباگ تکثیر می‌شود.

این کاهش هزینه به‌دلیل کم شدن مقدار کد نیست، بلکه به این دلیل است که عامل می‌تواند کوچک‌ترین زیرمجموعه لازم از فایل‌ها را شناسایی و بخواند. بررسی زنجیره تفکر (Chain-of-Thought) — مثل وقتی شاگرد ریاضی پای تخته بلند بلند فکر می‌کند تا به جواب برسد — نشان داد که sub-agent با تقسیم فایل‌ها، بخش‌های کوچک‌تری را می‌خواند. این تایید می‌کند که صرفاً بریدن یک فایل به تکه‌های کوچک و تصادفی جواب نمی‌دهد؛ سازمان‌دهی باید منطقی باشد.

تحلیل: هزینه جدید کیفیت

این آزمایش، بحث پیرامون «بدهی فنی هوش مصنوعی» را تغییر می‌دهد. پیش از این، بدهی فنی ریسکی برای نگهداری یا مانعی برای برنامه‌نویسان انسانی بود. اکنون، بدهی فنی یک هزینه عملیاتی مستقیم و تکرارشونده در صورت‌حساب ابری است. این موضوع با تلاش‌های دیگر برای بهینه‌سازی ساختاری هم‌سو است؛ برای مثال، استفاده از ابزارهای تحلیل گراف در بازبینی کد توانسته است مصرف توکن‌ها را تا ۸۲ برابر کاهش دهد.

برای برنامه‌نویس، بازگشت سرمایه (ROI) بازسازی کد تغییر کرده است. در دنیای انسان‌محور، بازسازی چون «کد کار می‌کند» به تعویق می‌افتاد. در دنیای عامل‌محور، تعویق در بازسازی یعنی تصمیم برای پرداخت ۸۳ درصد هزینه اضافی برای هر خط کدی که هوش مصنوعی در آینده می‌نویسد.

اما یک نکته وجود دارد: عامل‌ها هنوز به‌اندازه کافی خودمختار نیستند تا این فرآیند را رهبری کنند. فاولر دریافت که Claude نمی‌توانست به‌طور مستقل تشخیص دهد چه بازسازی‌هایی لازم است و یک انسان باید نقشه را ترسیم می‌کرد. جالب است که Claude.ai در مرحله برنامه‌ریزی بهتر از Claude Code عمل کرد و استخراج کلاس Client را شناسایی کرد که Claude Code نادیده گرفته بود. همچنین، توکن‌های خروجی که پنج برابر گران‌تر از ورودی‌ها هستند، به‌طور کلی تحت تأثیر بازسازی قرار نگرفتند.

پیامدهای بلندمدت

اگر بازسازی تهاجمی بتواند این صرفه‌جویی را در یک ماژول ایجاد کند، احتمالاً در کل کدبیس قابل اجرا است. این امر چرخه حیات جدیدی برای نرم‌افزار ایجاد می‌کند: عامل‌ها پیش‌نویس اول را می‌سازند، انسان‌ها برای بهینه‌سازی توکن بازسازی می‌کنند و سپس عامل‌ها کدبیسِ سبک را با هزینه کمتر نگهداری می‌کنند. برای پشتیبانی از این حجم از تعاملات سریع با مخازن بزرگ کد، زیرساخت‌های جدیدی در حال ظهور هستند که مثلاً راهکار Entire برای مدیریت بهینه کلون‌های انبوه مخازن هوش مصنوعی است.

این آزمایش حدود ۸ ساعت زمان برد و بیشتر به‌صورت بدون نظارت اجرا شد، هرچند که با سرعت پایین وای‌فای هتل و حجم بالای کش موقت cargo برای ساخت (build cache) که اجرای تست‌ها را کند می‌کرد، مواجه بود. او تخمین می‌زند مجموع توکن‌های مصرف شده برای طراحی و اجرای این آزمایش (شامل تهیه نقشه بازسازی و طراحی تغییر نمونه) زیر ۵ میلیون توکن باشد.

منتظر ظهور «عامل‌های بازسازی» باشید؛ مدل‌های تخصصی که ویژگی جدید نمی‌سازند، بلکه صرفاً به دنبال تورم توکن‌ها می‌گردند و کدها را ماژولار می‌کنند تا هزینه کل مالکیت (TCO) نرم‌افزارهای تولیدشده توسط AI را پایین بیاورند.

گام بعدی شما

  • اگر از عامل‌های کدنویس استفاده می‌کنید، هرگز اجازه ندهید فایل‌ها بیش از ۵۰۰ خط رشد کنند؛ هزینه‌ی هر تغییر را به‌صورت توکنی محاسبه کنید.
  • از مدل‌های چت (مثل Claude.ai) برای «طراحی نقشه بازسازی» استفاده کنید و سپس اجرای آن را به Agent بسپارید.
  • برای کاهش هزینه استنتاج، روی استخراج توابع تکراری (Extract Function) تمرکز کنید تا حجم پنجره متنی کاهش یابد.

اما داستان سخت‌افزاری این تحول حتی شگفت‌انگیزتر است — به تحلیل ما درباره‌ی تراشه‌های Blackwell مراجعه کنید.

چرا این موضوع مهم است؟

این یافته با تکیه بر تجربه عملی مارتین فاولر، نشان می‌دهد که تحلیل ساختاری کد در عصر AI یک ضرورت مالی است. این موضوع باعث می‌شود شرکت‌ها برای کاهش هزینه‌های API، دوباره به سراغ انضباط سخت‌گیرانه معماری نرم‌افزار بروند.

تأثیر برای ایران

برای برنامه‌نویسان ایرانی که با محدودیت بودجه برای خرید APIهای گران‌قیمت مدل‌های پیشرفته مواجه‌اند، این متدولوژی راهکاری حیاتی برای کاهش هزینه‌های عملیاتی است.

·نگاه ما
تحریریه دات‌هوش

این آزمایش پارادایم نگهداری کد را از «خوانایی برای انسان» به «بهینگی برای مدل» تغییر می‌دهد. بازسازی کد دیگر یک اقدام اختیاری برای بهبود کیفیت نیست، بلکه به یک استراتژی کاهش هزینه تبدیل شده است. در واقع، ما شاهد تولد مفهومی هستیم که در آن ساختار کد، مستقیماً روی قیمتِ هر Feature Request اثر می‌گذارد.

منابع

این گزارش با خط‌لولهٔ خودکار دات‌هوش از منابع معتبر جهانی تدوین و زیر نظر تحریریه منتشر شده است. روش کار ما

گفتگو

پنج‌شنبه‌های هوش‌محور

بسته‌ی هفتگی دات‌هوش

۵ خبر، ۲ ابزار، ۱ پرامپت در هر شماره. به‌زودی راه‌اندازی می‌شود — هر پنج‌شنبه صبح.

خبر کلیدی
ابزار کاربردی
پرامپت حرفه‌ای
تحلیل پژوهش
به‌زودی
زاویه‌ی ایرانی
به‌زودی
تمرین این هفته
به‌زودی

راهنماهای دات‌هوش

راهنماهای کاربردیِ دات‌هوش برای کار با هوش مصنوعی — از همین‌جا شروع کنید:

دات‌هوش

راهنمای فارسی هوش مصنوعی — با نگاه به ایران

اخبار روزانه، معرفی ابزارها و مدل‌ها، و آموزشِ کار با هوش مصنوعی؛ همیشه با این پرسش که از ایران چه چیزی کار می‌کند و چه چیزی نه.