كل المقالات والفيديوهات

أنزِل رتبة الكود القديم ولا تحذفه: خطة ترحيل تصمد في الإنتاج

اطلب من وكيل برمجي ترحيل وحدة Angular قديمة، فيبدأ خطته بكلمة «احذف». هذه الخطة خاطئة. إليك الخطة التي تنجح، والمراجعة التي تكشف الخطأ.

Adil Ben Moussa
07 نوفمبر 2026· 4 دقائق
أنزِل رتبة الكود القديم ولا تحذفه: خطة ترحيل تصمد في الإنتاج

أعطى الجزء السابق الوكيلَ ملف مهمة لميزة جديدة. أما الترحيل فأصعب، لأن الكود يعمل أصلاً في الإنتاج. اطلب من بالذكاء الاصطناعي (AI coding agent) تحديث وحدة قديمة ()، وستصلك خطة خلال ثلاثين ثانية.

في التجارب التي رأيتها، تبدأ تلك الخطة بكلمة «احذف». يتناول هذا الجزء سبب فشلها، والخطة التي تنجح، ومراجعة من خمس دقائق تميّز بينهما.

خطة الوكيل، والمواضع الثلاثة التي تنهار فيها

المثال العملي هو libs/legacy/transfers في المستودع التجريبي: وحدة NgModule، ومكوّن يستخدم *ngIf، واشتراكات يدوية ()، واستدعاءات markForCheck()، وجدول خاص به لحدود التحويلات. أما الجانب الحديث من التطبيق فيضم أصلاً مخزناً مبنياً على هو AccountsStore، إضافة إلى القواعد في libs/domain.

تقول للوكيل «رحّل هذا إلى signals»، فتأتي الخطة المعتادة في أربع خطوات (وتمرين الورشة يتحقق من الخطوات نفسها): احذف LegacyTransfersModule، وحوّل المكوّن في مكانه، واكتب دالة مساعدة validateTransfer()، وحدّث الاختبارات. تبدو خطة نظيفة. لكنها تغيير شامل دفعة واحدة ()، وتنهار في ثلاثة مواضع.

مستخدمون لا تعرفهم. في قاعدة كود قديمة، للكود القديم مستخدمون لم يبحث عنهم الوكيل بـ : مسار ()، أو رابط في صفحة أخرى، أو حارس مسار (). احذف المصدر، وستلتقي بهم في الإنتاج.

لا لحظة للتوقف والنشر. إعادة الكتابة في المكان يعني أن النسخة القديمة تختفي قبل أن تعمل الجديدة. في منتصف الطريق لا يوجد شيء قابل للنشر، والطريق الوحيد للعودة هو التراجع عن التغييرات ().

الـ لا يمكن مراجعته. لا أحد يقرأ ترحيلاً كاملاً في طلب دمج واحد (). تتحول المراجعة إلى «الاختبارات ناجحة، انشر»، مع أن الوكيل الذي كتب الكود هو نفسه من أعاد كتابة الاختبارات.

العلامة تظهر في السطر الأول.

أي خطة ترحيل تبدأ بعبارة «احذف X» خاطئة.

أنزِل الرتبة ولا تحذف

الخطة التي تصمد من ثلاث خطوات، ويمكن نشر كل واحدة منها على حدة.

ابنِ بجانبه. تذهب الميزة الجديدة إلى مكتبة خاصة بها، libs/feature/transfers، بجانب المكتبة القديمة. وتواصل الوحدة القديمة خدمة الصفحة دون أن يمسّها أحد.

بدّل المسار. حين تثبت استمارة التحويل الجديدة جدارتها، يتغير سطر واحد في app.routes.ts. عندها تكون رتبة الوحدة القديمة قد أُنزلت: ما زالت في الكود، لكنها لا تخدم أحداً.

# apps/atlas/src/app/app.routes.ts: التبديل كله
- { path: 'transfers', loadChildren: () => import('@atlas/legacy-transfers').then((m) => m.LegacyTransfersModule) },
+ { path: 'transfers', loadChildren: () => import('@atlas/feature-transfers').then((m) => m.transfersRoutes) },

وإذا ظهرت مشكلة في الإنتاج، فالعودة هي التعديل نفسه من سطر واحد.

احذف أخيراً. حين لا يعود أي شيء يستورد المكتبة القديمة، يصبح حذفها تعديلاً يزيل كوداً ولا يغيّر شيئاً. في المستودع التجريبي، لا تسمح قواعد باستيراد مكتبة من نوع type:legacy إلا للتطبيق نفسه، فلا يمكن لأي مكتبة حديثة أن تعتمد عليها. وبعد الحذف، يثبت نجاح فحص الأنواع () أن التطبيق لم يعد يعتمد عليها هو أيضاً. أما إذا حذفتها قبل تبديل المسار، فسيوقفك المترجم () فوراً:

error TS2307: Cannot find module '@atlas/legacy-transfers' or its corresponding type declarations.

هذا هو النوع الوحيد من الحذف الذي تريده: حذف يتحقق منه المترجم نيابةً عنك.

اطلب الخطة أولاً

لا تطلب الكود. اطلب الخطة، واقرأها في ضوء القواعد:

برومبت · الخطة أولاً

اقرأ AGENTS.md وكل ملف داخل libs/legacy/transfers/src. اقترح خطة لترحيل وحدة التحويلات القديمة إلى ميزة standalone مبنية على signals تناسب مساحة العمل هذه (workspace). الخطة فقط: خطوات مرقّمة، والملفات التي تُنشأ أو تُعدَّل أو تُحذف في كل خطوة، والخطوة التي يتحول فيها المسار /transfers/new/:accountId. لا تكتب كوداً ولا تعدّل أي ملف.

وحين تعود الخطوات الأربع المذكورة أعلاه، تكون المراجعة قصيرة:

  • احذف الوحدة أولاً: لا. تواصل الوحدة القديمة خدمة /transfers/new/:accountId إلى أن تثبت الميزة الجديدة جدارتها. تُحذف في النهاية، في تغيير مستقل.
  • أعد كتابته في المكان: لا. ابنِ بجانبها، في libs/feature/transfers، كي يبقى لديك دائماً شيء قابل للنشر.
  • دالة مساعدة validateTransfer(): تكرّر قواعد موجودة أصلاً. ملف القواعد يقول: ابحث بـ grep في libs/domain قبل إضافة أي قيمة سحرية ()، و canTransfer() ورسائلها موجودة هناك.
  • حدّث الاختبارات: لا. التحققات () الموجودة لا تُعدَّل أبداً لكي يمرّ تعديل ما. وإذا كان أحدها خاطئاً، يقول الوكيل ذلك في طلب الدمج ويتوقف.

ثم تأتي ثلاثة ملفات مهام بدل طلب دمج واحد، ولكل منها حدّ أقصى للحجم: تثبيت سلوك الكود القديم (المهمة 000)، ثم بناء الميزة الجديدة بجانبه وتبديل المسار (المهمة 002)، ثم حذف المكتبة القديمة (المهمة 003).

ومع ملفات المهام هذه، يأتي المكوّن الذي يبنيه الوكيل شبيهاً ببقية قاعدة الكود. في النسخة المرجعية بالمستودع التجريبي لا يحتوي المكوّن إلا على signals وقيم computed، وتأتي القواعد من استدعاء واحد لدالة من المجال، canTransfer()، كانت لها اختبارات أصلاً. بلا اشتراكات، وبلا markForCheck()، وبلا جدول حدود.

ويطلب ملف المهمة من الوكيل أيضاً أن يبلّغ عن التغيير الحقيقي الوحيد في السلوك. كان الجدول القديم يتجاهل التحويلات التي أُجريت اليوم، أما canTransfer() فتحسبها. أي أن الجدول المكرَّر كان يخفي خللاً ()، وطلب الدمج يصرّح بذلك بدل أن يمرّره خفية.

مع بداية الأسبوع

  • خطة ترحيل تبدأ بكلمة «احذف»: أرجِعها إلى صاحبها.
  • ابنِ بجانب القديم، وبدّل المسار، واحذف أخيراً.
  • اجعل الوكيل يقترح قبل أن يكتب الكود، واقرأ الخطة في ضوء قواعدك. خمس دقائق.

التمرين: الوحدة 2 في المستودع التجريبي، المشهدان الأول والثاني، مع الوحدة المجمّدة libs/legacy/transfers وملفات المهام. البداية: git switch -c m2/you main. الحل المرجعي: origin/track1/m2-ngmodule-solution.

وأول تلك الملفات، المهمة 000، يأتي قبل أي كود جديد: الجزء التالي يثبّت ما يفعله الكود القديم اليوم.


المسار 1، الجزء 4 من السلسلة المجانية المرافقة لورشة سريع وآمن: الذكاء الاصطناعي في قاعدة كود Angular الخاصة بك.

شارك هذا المقال
ورشة

سريع وآمن: الذكاء الاصطناعي في كود Angular الخاص بكم

دع الوكلاء يكتبون Angular تحت قواعد، وحدّث الكود القديم دون أن تكسر الإنتاج، وحافظ على أمانه، في ثلاثة أيام، على كود بحجم المؤسسات.

اطّلع على البرنامج
اقرأ بعد ذلك