EN
تعلّم المسارات المرجع مقالات المحفوظات
المسار المؤهِّل للاعتماد التغيير الآمن

التغيير الآمن: refactor خلف حزمة خضراء، لا على حسن الظن

الـ playbook يريك الخطوات. أما هذه الوحدة فإتقان انضباط الأمان — ماذا يعني «السلوك لم يتغيّر» تقنيًا، ولماذا اختبارات الـ characterization هي الشرط المسبق لا الإحماء، وكيف تمسك refactor يوشك أن يصير إعادة كتابة في صمت، وماذا يعني أن تثبت التنظيف بدل أن ترجوه.

قراءة 13 دقيقة · حُدّث في 2026-06-30
التغيير الآمن: refactor خلف حزمة خضراء، لا على حسن الظن

بين يدي فريقك playbook الـ safe-refactor — الوصفة المجرّبة لتثبيت الأساس الأخضر، والتحرك في خطوات صغيرة، وإعادة تشغيل الحزمة لإثبات أن السلوك لم يتغيّر. هذه الوحدة طبقة أعلى من الوصفة: هنا تُتقن ما يعنيه انضباط الأمان فعلًا — لا «شغّل الاختبارات مرتين» فحسب، بل الحسّ الذي يلتقط refactor يتحول إلى إعادة كتابة، والقراءة التي تفصل diff خطوةً بخطوة عن جدار تعديلات، ووصف الـ PR الذي يجعل القصد البنيوي واضحًا بدل أن يُترك المُراجِع يستنتجه من الـ diff.

«الحزمة الخضراء حزام أمانك — فاربطه فعلًا.» هذه هي العبارة التي يدقّ عليها الـ playbook، وهي أعمق مما تبدو. لا تعني «شغّل الحزمة في النهاية»؛ تعني شغّلها قبلُ (ثبّت الأساس الأخضر)، وبعد كل خطوة إن كانت التعديلات كبيرة، وفي النهاية. وإن احمرّ شيء، فليست تلك مشكلة تُغطّى — بل النظام يعمل كما ينبغي. الـ refactor حافظ للسلوك فقط إذا قالت الحزمة ذلك، لا إذا بدا كذلك.

«السلوك لم يتغيّر» — ماذا تعني تقنيًا

الـ playbook يعلّمك تشغيل الاختبارات قبلُ وبعدُ. الإتقان هو الحسّ وراء ما يثبته الأخضران فعلًا — وما لا يثبتانه.

  • الحزمة تثبت أن الاختبارات تنجح، لا أن السلوك لم يتغيّر. الحزمة التي تغطي 40% من الكود تعطيك حزام أمان يغطي 40% من المقاعد. إن مسّ الـ refactor مسارًا غير مغطًّى — حالة خطأ نادرة، أو معالج المهلة، أو مُنسّق النصوص العربية — تستطيع الحزمة أن تخضرّ والسلوك قد تغيّر. اعرف ما الذي تغطيه تغطيتك قبل أن تأتمنها برهانًا.
  • اختبارات الـ characterization تثبّت سلوكًا لا تعرفه بعد. حين تكون تغطية الكود الذي تعيد هيكلته رقيقة، الشرط المسبق الصحيح جولة characterization: أطعم الكود الحالي مدخلات منوّعة، وسجّل مخرجاته الحالية، واكتب اختبارات تجزم بها. لست تحكم هل السلوك الحالي صحيح — أنت تثبّته، كي يظهر أي تغيير يُحدثه الـ refactor فيه اختبارًا أحمر لا انحرافًا صامتًا. هذه الاختبارات هي كيف تحوّل «أرجو ألا يكون شيء تغيّر» إلى «أعلم أن شيئًا لم يتغيّر».
  • «يبدو مكافئًا» و«هو مكافئ» ادعاءان مختلفان. سيقرأ Claude نسختين من دالة ويحكم بتكافئهما من منطقهما. وسيخطئ أحيانًا — لأن التكافؤ مع الآثار الجانبية، والحالة المشتركة، والتزامن، والبيانات التي يجري عليها الإنتاج عندكم فعلًا، أصعب من أن يُستدل عليه من الشاشة. الحزمة هي الحكم، لا المظهر. إن اخضرّت الحزمة فالسلوك لم يتغيّر. وإن لم تخضرّ فقد تغيّر شيء، ولو بدا المنطق مكافئًا.
  • الاختبار الأحمر بعد تعديل «حافظ للسلوك» إشارة حقيقية — لا عقبة. الـ playbook يقولها وهي تستحق التوكيد: لا تدع Claude يعدّل اختبارًا ليُسكت فشل refactor. الأحمر بعد تعديل يُفترض أنه حافظ للسلوك يعني إما أن الـ refactor غيّر السلوك (ارجع عن تلك الخطوة) وإما أن الاختبار كان خاطئًا (وذلك مهم أن يُعرف ويُصلح على حدة، لا أن يُطمس). الـ refactor الذي ينجح على اختبار عُدّل ليس refactor آمنًا.

الخطوات الصغيرة — الانضباط الذي يجعل الفشل قابلًا للتحديد

الـ playbook يطلب أن يجري الـ refactor خطواتٍ منفصلة، لا إعادة كتابة واحدة عملاقة. الإتقان هو الحسّ الذي يجعل «الخطوات المنفصلة» معنًى لا اسمًا.

  • لكل خطوة قصد واحد. «استخرج التحقق في دالة مستقلة» خطوة واحدة. أما «استخرج التحقق، وادمج الفروع المكررة، وأعد تسمية الدالة» فثلاث خطوات ينبغي أن تكون ثلاثة diffs، لا واحدًا. حين يكون للخطوة قصد واحد، يقول لك الاختبار الأحمر بالضبط أي قصد انكسر. وحين تحمل ثلاثة، يقول لك: اذهب فابحث.
  • أرني diff كل خطوة قبل المضي. في Claude Desktop تهبط كل خطوة diff مرئيًا تقبله أو ترفضه في لوحة الملفات. والانضباط الصحيح أن تقرأ وتقبل (أو ترفض) كل خطوة قبل أن تبدأ التالية. ليست هذه مراجعة اختيارية في النهاية — إنها المراجعة أولًا بأول، وهي ما يجعل قصد كل خطوة مرئيًا لا مدفونًا في جدار تعديلات.
  • إن فاجأتك خطوة، فقف. الـ diff الذي يمسّ ملفًا لم تتوقعه، أو يغيّر توقيع دالة لم تذكره الخطة، أو يُدخل تجريدًا جديدًا ليس فيها، يُسأل عنه قبل قبوله. «لماذا مسست src/lib/db.ts؟» سؤال يُطرح الآن، لا بعد جولة حزمة احمرّت.
  • همّ واحد، commit واحد، حتى في الـ refactor. عرف الـ commit من الوحدة الثانية يمضي مباشرة إلى commits الـ refactor: استخرجت التحقق؟ التزمه. دمجت الفروع؟ التزمه. أعدت التسمية؟ التزمه. الـ commits الصغيرة بمتون لماذا واضحة هي ما يجعل الـ refactor قابلًا للمراجعة — وقابلًا للرجوع إن ساء شيء.

الـ refactor في مقابل إعادة الكتابة — الخط وكيف تمسكه

أصعب حُكم في الـ refactor الآمن أن تلتقط تحوّله إلى إعادة كتابة قبل أن تلتقطه حزمة الاختبارات.

  • تغيير السلوك commit آخر دائمًا. إن قال Claude وأنت تنظف دالة: «وما دمنا هنا، نستطيع أيضًا إصلاح الحالة الحدّية حيث كذا» — قف. تلك الحالة إما إصلاح خطأ (commit آخر، وربما PR آخر) وإما تغيير سلوك (خارج نطاق refactor حافظ للسلوك). اقبل الـ refactor، والتزمه، ثم عالج الحالة على حدة. خلط refactor بتغيير سلوك يعني أن الاختبار الأحمر قد يكون من أيهما — وقد فقدت حزام الأمان.
  • الخطة عقدُ نطاقك. خطة الـ refactor التي اتفقتما عليها في الخطوة الأولى هي الحدّ: «استخرج التحقق، وادمج الفروع المكررة، وأعد تسمية data إلى invoicePayload». وما خرج عنها ليس من الـ refactor — إنه تمدد نطاق. الـ refactor الذي ينمو خارج خطته إعادةُ كتابة بدأت تحدث. أمسِك الخطة.
  • إن كان الـ refactor إعادة كتابة فعلًا، فسمِّه. أحيانًا تفتح دالة لتنظفها فتكتشف أن التعديل الحقيقي المطلوب إعادة تصميم بنيوية، لا تنظيف. وذلك اكتشاف مهم — والرد الصحيح أن تقف، وتسمّي الاكتشاف، وتعامل إعادة التصميم عملًا مستقلًا (spec، وخطة، وتنفيذ، واختبارات، وcommits نظيفة). الـ refactor الذي يصير إعادة كتابة دون إعلان diff لا يستطيع أحد مراجعته بأمان.

وصف الـ PR — شرح القصد البنيوي

الـ playbook يُختم بطلب خلاصة لما تغيّر ولماذا. الإتقان هو الحسّ الذي يجعل تلك الخلاصة نافعة لمُراجِع يقرأ الـ diff أصلًا.

  • المُراجِع يرى ما انتقل؛ ولا يرى لماذا. «استخرجت التحقق إلى invoice-validate.ts» شيء يقرؤه المُراجِع في الـ diff. أما «استخرجت التحقق كي تصير دالة توليد الفاتورة ذات مسؤولية واحدة وتُختبر دون عميل Supabase يعمل» فهي اللماذا — منطق القرار البنيوي، القصد الذي لا يحمله الـ diff وحده.
  • قل أي سلوك حُفظ، لا ما نُظف فحسب. «لم يتغيّر أي سلوك: الحزمة خضراء قبلُ وبعدُ، والأساس مثبَّت على المخرجات الحالية» هي الجملة التي تحوّل وصف PR الـ refactor إلى وصف آمن. إنها حزام الأمان نثرًا — يعلم المُراجِع أن الكاتب ثبّت أساسًا أخضر، لا رجاه.
  • سمِّ المشكلات البنيوية التي أُصلحت. «كانت هذه الدالة قد تضخمت إلى 380 سطرًا تدير التحقق والحساب وتوليد الـ PDF والبريد في مسار واحد — يستحيل اختبار أي جزء منها معزولًا. صارت أربع دوال مركّزة تُختبر وتُعدَّل كلٌّ على حدة.» ذلك هو القصد البنيوي — يفهم المُراجِع لا ما انتقل فحسب، بل أي مشكلة حلّها الانتقال.

تكليفك

أكمِل حلقة الـ refactor الآمن لـملف أو وحدة حقيقية واحدة لها تغطية اختبارات — على الـ codebase الخاص بك (وهذا ما ننصح به) أو دالة توليد الفواتير في «ميزان» المعروضة في هذه الوحدة. افتح مجلد المشروع في Claude Desktop وفيه CLAUDE.md واعمل داخل المحادثة — وتشغيل الحزمة قبلُ وبعدُ هو خطوة مسار الـ Power Track.

ناتج الوحدة الرابعة — refactor آمن

1. الأساس قبلُ  (نتائج الحزمة أو لصق المخرجات الخضراء)
   - أمر الاختبار الذي شُغّل، والمخرجات تُظهر الأخضر
   - مستوى التغطية مدوَّن (كي تحكم المعايير على ما يثبته الأخضر)

2. الـ refactor خطواتٍ منفصلة  (git log أو مذكرات الجلسة)
   - كل حركة بنيوية diff مقبول مستقل
   - كل واحدة ملتزَمة وحدها بمتن لماذا
   - أثر يُظهر أن كل خطوة رُوجعت قبل بدء التالية

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

4. وصف الـ PR  (صفحة واحدة)
   - أي مشكلات بنيوية كانت قائمة قبلُ
   - ما الذي أصلحته كل حركة بنيوية (لا ما يريه الـ diff — بل لماذا
     جرت الحركة)
   - تصريح صريح بأن السلوك حُفظ: أخضر قبلُ، أخضر بعدُ

كيف يجري التقييم — المعايير

معايير الـ refactor الآمن

1. الأساس الأخضر مثبَّت
   الحزمة شُغّلت قبل أي تعديل والنتيجة معروضة. ومستوى التغطية
   مدوَّن. لا مجرد ادعاء.
2. الخطوات منفصلة ومراجَعة
   كل حركة بنيوية diff مقبول مستقل، لا جدار تعديلات. وأثرُ
   مراجعةٍ خطوةً بخطوة (قُبل كل diff قبل المضي).
3. أخضر بعدُ، التغطية نفسها
   الحزمة نفسها شُغّلت بعد كل الخطوات. النتيجة نفسها. وإن احمرّ
   اختبار: الخطوة مسمّاة، والإصلاح معروض، ولا اختبار عُدّل لطمس
   إشارة حقيقية.
4. لا تغيير سلوك مخلوط
   لا خطوة ضمّت إصلاح خطأ أو إضافة حالة حدّية أو تغيير ميزة مع
   التنظيف البنيوي. همّ واحد لكل commit، حتى في خطوات الـ refactor.
5. وصف الـ PR يشرح القصد
   يشرح المشكلة البنيوية التي أُصلحت (اللماذا)، لا الـ diff
   (الماذا). ويقول صراحة إن الأخضر قبلُ + الأخضر بعدُ كان البرهان.

المستوى المطلوب، معروضًا — نموذج إجابة («ميزان»)

(السرد بالعربية؛ والأوامر ورسائل الـ commit بالإنجليزية — فهي وثائق تعيش في git.)

هدف الـ refactor:‏ src/lib/invoice.ts — 380 سطرًا، أربع مسؤوليات
(التحقق، والحساب، وتوليد الـ PDF، والبريد) في دالة واحدة.

الأساس قبلُ:
  $ npm run test:unit
  ✓ 47 tests passed ‏(src/lib/invoice.ts: أربعة اختبارات — المسار
    السعيد، والإجماليات، وصفر بنود، والعملة). التغطية: 62% من
    عبارات invoice.ts.
  ملاحظة: مسارا توليد الـ PDF والبريد بلا اختبارات وحدات (يغطيهما
  اختبارا E2E يحتاجان Playwright + بيئة Resend التجريبية).

الخطوة 1 — استخراج التحقق:
  نُقل تحقق الحمولة إلى src/lib/invoice-validate.ts.
  الـ diff:‏ invoice.ts ‏(−82 سطرًا)، invoice-validate.ts (جديد، +76).
  الحزمة: خضراء.
  الـ commit:
    refactor(invoice): extract payload validation to invoice-validate.ts

    The validation logic (field checks, client lookup, amount
    constraints) had no way to be tested without generating a full
    invoice. Now it can be unit-tested in isolation with a mock
    client lookup.

الخطوة 2 — استخراج الحساب:
  نُقل منطق الإجماليات والـ VAT والتقريب إلى src/lib/invoice-calc.ts.
  الـ diff:‏ invoice.ts ‏(−94 سطرًا)، invoice-calc.ts (جديد، +89).
  الحزمة: خضراء.
  الـ commit:
    refactor(invoice): extract calculation to invoice-calc.ts

    The AED rounding fix from #201 highlighted that the calculation
    logic needed its own test surface. Extracted so the rounding,
    VAT, and multi-line-item totals can be tested without touching
    the DB or the PDF renderer.

[الخطوتان 3 و4 على النمط نفسه لتوليد الـ PDF والبريد]

بعدُ: $ npm run test:unit ← ‏✓ 67 tests passed (‏20 اختبارًا جديدًا
للدوال المستخرجة؛ واختبارات invoice.ts الأربعة الأصلية تنجح كما هي).

مقتطف وصف الـ PR:
  كانت invoice.ts تحمل أربع مسؤوليات في دالة واحدة (التحقق،
  والحساب، وتوليد الـ PDF، وإرسال البريد) — يستحيل اختبار أي جزء
  معزولًا، وكانت الدالة ذات الـ 380 سطرًا أكثر ملف عُدّل في الربع
  الماضي. هذا الـ refactor يستخرج كل مسؤولية في وحدتها دون تغيير
  أي سلوك.

  ما الذي أصلحه الاستخراج: إصلاح تقريب الدرهم (#201) كان يستلزم
  توليد فاتورة كاملة لاختباره. invoice-calc.ts الجديدة فيها 12
  اختبار وحدة تغطي التقريب والـ VAT وحالات تعدد العملات دون قاعدة
  بيانات ولا مولّد PDF.

  السلوك محفوظ: الحزمة خضراء قبلُ (47 اختبارًا) وبعدُ (67، منها
  20 جديدًا). لم يُعدَّل اختبار. ولم يتغيّر اختبار E2E.

ما الذي أثبتّه — وما التالي

باجتيازك هذه المعايير تكون قد أظهرت الانضباط الذي يفصل refactor تقف وراءه عن إعادة كتابة تقلقك في صمت: أساس أخضر، وخطوات منفصلة، وبرهان قبلُ/بعدُ على أن السلوك لم يتحرك.

الوحدة 5 — النقلة الكبرى هي التالية: منهج الـ migration الذي يحوّل الأغلبية الآلية عبر الـ repo كله ويرفع الحالات المستلزِمة للحُكم إليك أنت لتقرر، بدل أن يخمّنها في صمت.

engineeringrefactortestingsafe-changecertificationassessmentdesktopteams

أسئلة يطرحها الناس

ما الفرق بين هذه الوحدة وplaybook الـ safe-refactor المجاني؟
الـ playbook وصفة: شغّل الحزمة قبلُ، وتحرك في خطوات صغيرة، وشغّلها بعدُ، وارجع إن احمرّ شيء. أما هذه الوحدة فهي الإتقان والإثبات معًا: الحسّ وراء لماذا اختبارات الـ characterization هي الشرط المسبق الفعلي (لا مجرد إحماء)، وماذا يعني «السلوك لم يتغيّر» تقنيًا لا عُرفيًا، وكيف تلتقط refactor يتحول إلى إعادة كتابة قبل أن تلتقطه الاختبارات، وكيف تكتب وصف PR يشرح القصد البنيوي بدل وصف الـ diff. تُقيَّم على حضور نتيجتي الحزمة قبلُ وبعدُ معًا وعلى ألا يكون تغيير سلوك تسلّل في الطريق.
ماذا لو لم يكن للكود الذي أريد إعادة هيكلته اختبارات؟
فلا تستطيع تشغيل هذه الوحدة على ذلك الكود — ليس بعد. حزمة الاختبارات هي ضمانة الأمان كلها؛ وrefactor بلا أساس أخضر إنما هو إعادة كتابة باسم ألطف. شغّل أولًا الخطوة المسبقة في playbook الـ safe-refactor: فـ playbook الـ backfill-tests يضيف اختبارات characterization تثبّت السلوك الحالي أساسًا. ومتى اخضرّت الحزمة، عُد إلى هنا. الوحدة مصممة لتصادف هذا الموقف — والتعامل الصحيح معه جزء من الحسّ المُقيَّم.