مهاجرت نسخههای قدیمی نرمافزاری مانند ارتقای کدهای Java 8 به 17 یا Python 2 به 3، در تیمهای مهندسی معمولاً پروژهای زمانبر، پرهزینه و فرسایشی است. استفاده از اسکریپتهای سنتی و ابزارهای بازنویسی مکانیکی تنها بخشی از کار را جلو میبرد و در مواردی مثل ناسازگاری وابستگیهای غیرمستقیم، شکست پیکربندی بیلد و خطاهای سینتکسی پیچیده، کار بازمیماند. در این درس یاد میگیرید چگونه با معماری دولایه شامل ابزارهای قطعی (مانند OpenRewrite) و ایجنتهای هوشمند مبتنی بر مدل زبانی، پایپلاین مهاجرت خودکار را پیاده کنید.
در این رویکرد، ایجنت در یک محیط ایزوله یا ساندباکس مجهز به ابزارهای بیلد و اجرا، پروژهها را تا سبز شدن بیلد و حفظ پوشش آزمونها هدایت میکند. پیادهسازی این سیستمها چالشهایی در دسترسی به APIهای خارجی یا ابزارهای ساندباکس ابری ایجاد میکند. با توجه به محدودیتهای دسترسی و پرداخت ارزی برای سرویسهای توسعهدهنده از ایران، میتوان برای بخش ایجنت از گیتویهای واسط سازگار با پروتکل OpenAI استفاده کرد و محیط ساندباکس را نیز با داکر روی سیستم یا سرور محلی بالا آورد.
بنچمارک MigrationBench آمازون (مهاجرت از Java 8 به 17) و ابزار مهاجرت Python 2 به Python 3 در App Engine گوگل، استاندارد سال 2026 را تعیین کردهاند. پلتفرم OpenRewrite شرکت Moderne بازنویسیهای قطعی AST را در مقیاس وسیع انجام میدهد. ابزار Grit نیز همین مسئله را با یک DSL به سبک codemod هدف گرفته است. الگوی محیط عملیاتی (پروداکشن) ترکیبی از هر دو رویکرد است: یک بستر قطعی برای بازنویسیهای امن، بههمراه یک لایهی ایجنت برای موارد مبهم، یک ساندباکس برای بیلد به ازای هر branch، و یک بستر آزمایشی که قبل از باز شدن PR سبز میشود. پروژهی نهایی این است که 50 مخزن واقعی را مهاجرت دهید و نرخ قبولی (pass rate) را همراه با ردهبندی خطاها منتشر کنید.
فازهای تمرینشده: P5 · P7 · P11 · P13 · P14 · P15 · P17
زمان: 30 ساعت
صورت مسئله
مهاجرت کدهای حجیم، یکی از تمیزترین کاربردهای پروداکشن برای ایجنتهای کدنویسی سال 2026 است. دادهی واقعی (ground truth) کاملاً شفاف است (آیا مجموعهی تستها بعد از مهاجرت قبول میشوند؟)، ارزش کار واقعی است (مهاجرت ناوگان سرویسهای Java 8 یک شرکت، پروژهای در مقیاس چندین نیروی تماموقت است)، و بنچمارکها عمومی هستند (زیرمجموعهی 50 مخزنی MigrationBench). ابزار OpenRewrite بخشهای قطعی را مدیریت میکند. لایهی ایجنت هم به سراغ هر آن چیزی میرود که دستورالعملهای (recipes) OpenRewrite توان حلش را ندارند: بازنویسیهای مبهم، تغییرات تدریجی سیستم بیلد (build-system drift)، سینتکسهای نادر، و شکست وابستگیهای غیرمستقیم (transitive dependencies).
شما ایجنتی میسازید که یک مخزن Java 8 (یا مخزن Python 2) را تحویل میگیرد و یک branch مهاجرتیافته با CI کاملاً سبز تحویل میدهد. نرخ قبولی، حفظ پوشش آزمون و هزینهی هر مخزن را اندازه میگیرید و ردهبندی خطاها را میسازید. مقایسهی روبهرو با خط مبنای (baseline) صرفاً قطعی، دقیقاً نشان میدهد که ارزش واقعی ایجنت کجاست.
مفاهیم کلیدی
این پایپلاین دو لایه دارد. بستر قطعی (OpenRewrite برای Java، یا libcst برای Python) بخش عمدهی بازنویسیهای مکانیکی را با امنیت کامل اجرا میکند: importها، امضای متدها، ویرایشهای null-safety، ساختارهای try-with-resources و جایگزینی APIهای منسوخ. این لایه سریع است و diffهای قابل بررسی تولید میکند. لایهی ایجنت (OpenAI Agents SDK یا LangGraph روی Claude Opus 4.7 و GPT-5.4-Codex) مواردی را رفع میکند که دستورالعملها از پس آنها برنمیآیند: ارتقای فایلهای بیلد (Maven/Gradle/pyproject)، تداخل وابستگیهای غیرمستقیم، تستهای ناپایدار (test flakes) و annotationهای سفارشی.
به هر مخزن یک ساندباکس Daytona با محیط اجرای مقصد که از پیش نصب شده اختصاص داده میشود. ایجنت در یک حلقه تکرار میشود: اجرای بیلد، دستهبندی خطاها، اعمال اصلاحیه، اجرای مجدد. محدودیتهای سختگیرانه: 30 دقیقه زمان واقعی برای هر مخزن، 8 دلار هزینه برای هر مخزن، 20 نوبت گفتوگوی ایجنت (agent turn). اگر همهی تستها پاس شوند و پوشش آزمون بیش از 2 واحد درصد افت نکند، برای branch یک PR باز میشود. در غیر این صورت، مخزن همراه با شواهد (evidence) ذیل یک ردهی خطا ثبت میشود.
دستهبندی موضوعی خطاها خروجی اصلی کار است. در طول 50 مخزن، چه چیزی خراب شد؟ وابستگیهای غیرمستقیم؟ annotationهای سفارشی؟ نسخهی ابزار بیلد؟ تستهای ناپایدار نامرتبط با مهاجرت؟ به هر رده یک تعداد و یک نمونه diff واقعی اختصاص مییابد تا نویسندگان بعدی دستورالعملها بتوانند روی سه مورد اول تمرکز کنند.
معماری
target repo
|
v
OpenRewrite / libcst deterministic recipes
(safe, fast, auditable, ~70-80% of fixes)
|
v
Daytona sandbox per branch
|
v
agent loop (Claude Opus 4.7 / GPT-5.4-Codex):
- run build -> capture failures
- classify failures (build, test, lint)
- apply fix (patch or retry recipe)
- rerun
- budget: 30 min, $8, 20 turns
|
v
test + coverage delta gate
|
v (passed)
open PR
|
v (failed)
file under failure class + attach repro
ابزارها و فناوریها
- بستر قطعی: OpenRewrite (برای Java) یا libcst (برای Python)
- ایجنت: OpenAI Agents SDK یا LangGraph بر پایهی Claude Opus 4.7 و GPT-5.4-Codex
- ساندباکس: محیطهای devcontainer در Daytona به ازای هر branch، با محیط اجرای مقصد نصبشده (Java 17 / Python 3.12)
- سیستمهای بیلد: Maven، Gradle، uv (برای Python)
- بنچمارکها: زیرمجموعهی 50 مخزنی MigrationBench آمازون (Java 8 به 17)، مخازن Google App Engine Py2-to-Py3
- بستر آزمایشی: اجراکنندهی موازی، محاسبهی پوشش از طریق Jacoco (برای Java) یا coverage.py (برای Python)
- مشاهدهپذیری (Observability): لاگهای Langfuse + یک بسته ردگیری محاسبات (trace bundle) به ازای هر مخزن همراه با تکتک تغییرات diff
- داشبورد: داشبورد ردهبندی خطاها همراه با تعداد هر رده و نمونههای diff
پیادهسازی گامبهگام
-
اجرای دستورالعملها. ابتدا دستورالعملهای OpenRewrite (برای Java) یا libcst (برای Python) را اجرا کنید تا 70 تا 80 درصد مهاجرتهای مکانیکی انجام شوند. تغییرات را با عنوان commit به نام «recipe» ثبت کنید.
-
تست بیلد اولیه. در ساندباکس Daytona: محیط اجرای مقصد را تنظیم و بیلد را اجرا کنید. اگر سبز شد، یکراست سراغ آزمونها بروید. اگر قرمز شد، کار را به ایجنت بسپارید.
-
حلقهی ایجنت. LangGraph با ابزارهای:
run_build،read_file،edit_file،run_test،git_diff. ایجنت علت خطا را ردهبندی میکند (وابستگی، سینتکس، آزمون، ابزار بیلد)، اصلاح هدفمند را اعمال کرده و دوباره اجرا میکند. -
سقف بودجه. حداکثر 30 دقیقه زمان تقویمی، 8 دلار هزینه و 20 نوبت گفتوگو برای هر مخزن. با نقض هر کدام از این سقفها، کار متوقف شده و مخزن همراه با diff جاری در ردهی «budget_exhausted» ثبت میشود.
-
فیلتر آزمون و پوشش کد. پس از سبز شدن بیلد، مجموعهی تستها را اجرا کنید. درصد پوشش را با مخزن پایه مقایسه کنید؛ اگر پوشش بیش از 2 واحد درصد افت کند، مخزن ذیل «coverage_regression» ثبت میشود.
-
باز کردن PR. در صورت موفقیت، branch را push کنید و PR را به همراه diff و خلاصهای از دستورالعملهای اجراشده و commitهای اختصاصی ایجنت باز کنید.
-
ردهبندی خطاها. به ازای هر مخزن ناموفق، برچسب مشخصی بزنید:
dep_upgrade_required،build_tool_drift،custom_annotation،test_flake،syntax_edge_case،budget_exhausted. سپس داشبورد خروجی را بسازید. -
اجرا روی 50 مخزن. پایپلاین را روی زیرمجموعهی MigrationBench اجرا کنید. گزارش جامعی از نرخ قبولی هر رده، هزینهی هر مخزن، نرخ حفظ پوشش آزمون، و مقایسه با خط مبنای صرفاً قطعی ارائه دهید.
استفاده از ابزارهای واقعی
$ migrate legacy-java-service --target java17
[recipe] 27 rewrites applied (JUnit 4->5, HashMap initializer, try-with-resources)
[build] FAIL: cannot find symbol sun.misc.BASE64Encoder
[agent] turn 1 classify: removed_jdk_api
[agent] turn 2 apply: sun.misc.BASE64Encoder -> java.util.Base64
[build] OK
[tests] 412/412 passing; coverage 84.1% -> 84.3%
[pr] opened #1841 cost=$3.20 turns=4
خروجی نهایی
فایل outputs/skill-migration-agent.md خروجی قابلتحویل شماست. این ایجنت با دریافت یک مخزن، ابتدا دستورالعملهای قطعی و سپس حلقهی ایجنت را اجرا میکند تا یک branch مهاجرتیافته با تستهای سبز تولید کند، یا مخزن را ذیل یک ردهی خطا ثبت نماید.
| ضریب | معیار ارزیابی | نحوهی سنجش |
|---|---|---|
| 25 | نرخ قبولی در MigrationBench | معیار pass@1 در زیرمجموعهی 50 مخزنی |
| 20 | حفظ پوشش آزمون | میانگین تغییر پوشش (دلتا) نسبت به مخزن پایه |
| 20 | هزینهی هر مخزن مهاجرتیافته | دلار پرداختی به ازای هر مخزن موفق |
| 20 | یکپارچگی ابزار قطعی و ایجنت | نسبت اصلاحات انجامشده توسط OpenRewrite در برابر اصلاحات ایجنت |
| 15 | گزارش ردهبندی خطاها | کامل بودن دستهبندی موضوعی همراه با ارائهی نمونههای واقعی |
| 100 |
تمرینها
-
پایپلاین مهاجرت را فقط با OpenRewrite (بدون ایجنت) اجرا کنید. نرخ قبولی را با پایپلاین کامل مقایسه کنید و مواردی را که فقط با حضور ایجنت حل شدهاند مشخص کنید.
-
اعتبارسنجی «بدون خطای لینت» را پیاده کنید: پس از مهاجرت، لینتر سبک کد (spotless برای Java، ruff برای Python) را اجرا کنید. اگر خطای لینت جدیدی ایجاد شد، PR را رد کنید. نرخ پروژههایی را که پوشش آزمونشان حفظ شده ولی استایل کدشان دچار پسرفت شده است اندازه بگیرید.
-
یک بهینهساز «حداقل diff» اضافه کنید: پس از اینکه branch تغییریافتهی ایجنت تستها را پاس کرد، تغییرات اضافه را در یک مرحلهی دوم پاکسازی کنید. درصد کاهش حجم diff را گزارش دهید.
-
پایپلاین را برای مهاجرت سوم گسترش دهید: از Node 18 به Node 22. محیط ساندباکس را دوباره به کار بگیرید و لایهی دستورالعملها را با یک codemod سفارشی تعویض کنید.
-
زمان تا اولین بیلد سبز (TTFGB) را به عنوان معیاری از تجربهی کاربری اندازه بگیرید. هدف: صدک پنجاهم (p50) زیر 10 دقیقه باشد.
اصطلاحات کلیدی
| اصطلاح | در گفتوگوهای عامیانه | معنای دقیق فنی |
|---|---|---|
| بستر قطعی (Deterministic substrate) | «موتور دستورالعمل» | OpenRewrite / libcst: بازنویسیهای اعلانی AST با تضمینهای امنیتی |
| کدماد (Codemod) | «برنامهی تغییر کد» | یک قاعدهی بازنویسی که سورسکد را بهشکل مکانیکی تغییر میدهد |
| ناهماهنگی بیلد (Build drift) | «عدم انطباق نسخهی ابزار» | تغییر رفتارهای نامحسوس در Maven / Gradle / uv بین نسخههای اصلی |
| ردهی خطا (Failure class) | «دستهی موضوعی» | علت برچسبگذاریشده برای شکست مهاجرت: وابستگی، سینتکس، تست، ابزار بیلد، اتمام بودجه |
| تغییر پوشش (Coverage delta) | «حفظ پوشش تست» | تغییر درصد پوشش آزمون از مخزن پایه تا branch مهاجرتیافته |
| نوبت ایجنت (Agent turn) | «دور فراخوانی ابزار» | یک چرخهی کامل برنامهریزی -> اقدام -> مشاهده در حلقهی ایجنت |
| اتمام بودجه (Budget exhaustion) | «رسیدن به سقف مجاز» | وضعیتی که مخزن محدودیتهای 30 دقیقه / 8 دلار / 20 نوبت را بدون پاس شدن تمام کرده است |
برای مطالعهی بیشتر
- بنچمارک MigrationBench آمازون — بنچمارک مرجع سال 2026
- پلتفرم Moderne.io OpenRewrite — مرجع بستر بازنویسی قطعی
- مستندات OpenRewrite — راهنمای نوشتن دستورالعملها (recipes)
- وبسایت Grit.io — یک DSL جایگزین برای codemod
- دستورالعمل مهاجرت ساندباکسشدهی OpenAI — مرجع استفاده از Agents SDK
- ابزار مهاجرت Google App Engine Py2 به Py3 — بنچمارک مهاجرت جایگزین
- کتابخانهی libcst — بستر بازنویسی قطعی برای پایتون
- ساندباکسهای Daytona — مرجع ساندباکس به ازای هر branch
