مستشار إعادة هيكلة الكود: تحسينات قبل وبعد مع درجة مخاطرة لكل منها

Why this prompt matters
Developers now spend 23-42% of their work week dealing with technical debt and bad code — the Stripe Developer Coefficient study puts the global cost at $85 billion in lost productivity a year. The failure mode isn't not knowing code is bad; it's not knowing which fix is safe to make first. A one-standard-deviation rise in an organization's debt-to-code ratio corresponds to a 31% jump in defect density — refactoring the wrong part first, or all of it at once, is how technical debt cleanup itself introduces new bugs.
What we use it for
You've inherited a 400-line function that everyone on the team avoids touching because it 'works, mostly' and nobody remembers why it's structured the way it is. You need to clean it up before adding a new feature, but you don't have time to rewrite it from scratch and can't afford to break the parts that work.
Prompt
You are a senior software engineer with expertise in refactoring legacy code without introducing regressions. You are conservative by default — you flag risk honestly rather than being falsely reassuring. CONTEXT: Language/framework: [YOUR LANGUAGE, e.g. "TypeScript, Node.js, Express"] What this code does: [ONE-SENTENCE DESCRIPTION OF THE FUNCTION'S PURPOSE] Known problems (if any): [WHAT YOU ALREADY SUSPECT IS WRONG, e.g. "deeply nested conditionals, unclear variable names, does three unrelated things"] Test coverage: [DESCRIBE CURRENT TESTS, e.g. "one integration test covering the happy path only" or "none"] Constraints: [ANYTHING THAT CANNOT CHANGE, e.g. "the public function signature must stay identical, this is called from 40+ places"] TASK: Review the code below and identify 3-6 specific, independent refactoring opportunities. For EACH one: 1. Name the problem (e.g. "duplicated validation logic", "mixed abstraction levels", "unclear boolean flag parameter"). 2. Show the BEFORE code snippet (just the relevant lines, not the whole function). 3. Show the AFTER code snippet with the fix applied. 4. Assign a Risk Score (Low/Medium/High) based on: how much of the function's behavior the change touches, whether existing tests would catch a regression, and whether the change is purely structural (safe) or alters logic/behavior (riskier). 5. State what you'd want to verify manually or via a new test before merging this specific change. CONSTRAINTS: - Do NOT rewrite the entire function in one pass. Each refactor must be independently applicable — I need to be able to accept refactor #2 without necessarily taking #4. - Order your suggestions from LOWEST risk to HIGHEST risk, so I can bank easy wins first. - If the function is doing more than one job, say so explicitly and suggest a split — but still give me the low-risk internal cleanups first, since a full split is inherently higher-risk. - Do not suggest changes that alter the function's observable behavior unless you flag it as Medium or High risk with a clear explanation of what changes. - If test coverage is described as weak or absent, recommend which specific test(s) to write BEFORE attempting the Medium/High risk refactors, not after. OUTPUT FORMAT: ## Refactor 1: [Problem name] — Risk: [Low/Medium/High] **Before:** ``` [code] ``` **After:** ``` [code] ``` **Verify before merging:** [what to check or test] [repeat for each refactor, low to high risk] ## Summary [One paragraph: overall assessment of the function's health, and the recommended order of operations] CODE TO REVIEW: [PASTE YOUR FUNCTION OR CODE BLOCK HERE]
Result
Refactor 1: Duplicated validation logic — Risk: Low
Before:
if (!user.email || user.email.length === 0) { throw new Error('Email required'); }
if (!user.name || user.name.length === 0) { throw new Error('Name required'); }
if (!user.phone || user.phone.length === 0) { throw new Error('Phone required'); }After:
const requiredFields = ['email', 'name', 'phone'];
for (const field of requiredFields) {
if (!user[field]?.length) throw new Error(`${field} required`);
}Verify before merging: Confirm error message format isn't parsed elsewhere by exact string match — the field name capitalization changed slightly.
Refactor 2: Unclear boolean flag parameter — Risk: Low
Before:
function processOrder(order, flag) {
if (flag) { applyDiscount(order); }
...
}After:
function processOrder(order, { applyLoyaltyDiscount }) {
if (applyLoyaltyDiscount) { applyDiscount(order); }
...
}Verify before merging: Update all 6 call sites to pass a named object instead of a positional boolean — purely mechanical, no behavior change, but touches every caller.
Refactor 3: Deeply nested conditionals — Risk: Medium
Before:
if (user.active) {
if (user.subscription) {
if (user.subscription.tier === 'pro') {
// 15 more lines
}
}
}After:
if (!user.active) return;
if (!user.subscription) return;
if (user.subscription.tier !== 'pro') return;
// 15 more lines, now unindentedVerify before merging: Early returns change control flow if there's an else branch further down handling the negative case elsewhere in the original function — check for one before applying. Write a test for the non-pro-tier path specifically, since current coverage doesn't exercise it.
Refactor 4: Function does three unrelated things — Risk: High
Before: Single 400-line function handles validation, discount calculation, and email notification in sequence.
After: Split into validateOrder(), calculateDiscount(), and notifyCustomer(), called in sequence from a thin orchestrator function.
Verify before merging: This changes the function's shape enough that any code relying on partial execution (e.g. catching an error mid-function and still sending a notification) will behave differently. Do NOT attempt this split until Refactors 1-3 are merged and you have integration test coverage for all three code paths — this should be its own PR, reviewed separately.
Summary
This function is moderately unhealthy but not unsalvageable. Refactors 1-2 are safe, mechanical wins you can ship today. Refactor 3 needs one new test first but is still low-stakes. Refactor 4 (the actual split) is the real fix but should wait until the others are merged and stable — attempting all four at once is how a cleanup PR turns into a production incident.
معظم موجّهات إعادة الهيكلة تُنتج إعادة كتابة واحدة عملاقة لدالتك وتأمل أن تكون صحيحة. هذا معكوس للكود الإنتاجي الحقيقي — إعادة كتابة شاملة واحدة هي بالضبط ذلك التغيير الأصعب في المراجعة والأصعب في الاختبار والأكثر احتمالًا لإخفاء ارتداد داخل diff كبير جدًا بحيث لا يمكن لأحد فحصه بشكل صحيح. هذا الموجّه يفعل العكس: فهو يقسّم التنظيف إلى قطع مستقلة يمكن دمجها بشكل فردي، ويُصنّفها حسب مدى قدرتها على إحداث خلل.
لماذا تأتي درجة المخاطرة قبل درجة جودة الكود
إعادة هيكلة تُحسّن قابلية القراءة لكنها لا تُغيّر أي سلوك قابل للملاحظة تختلف جوهريًا عن تلك التي تلمس المنطق الفعلي، حتى لو كانت كلتاهما تبدو مثل diffs متشابهة الحجم. يُجبر الموجّه على هذا التمييز بطلب درجة مخاطرة تعتمد على ثلاثة عوامل محددة: مدى تأثير التغيير على السلوك، وما إذا كانت الاختبارات الحالية ستكشف عن ارتداد، وما إذا كان التغيير هيكليًا بحتًا أم يُغيّر المنطق. هذا يحوّل شعورًا غامضًا بأن "هذا يبدو محفوفًا بالمخاطر" إلى حكم قابل للتكرار على النموذج تبريره.
لماذا تأتي الإصلاحات منخفضة المخاطرة أولاً
ترتيب الاقتراحات من الأقل إلى الأعلى مخاطرة ليس مجرد مسألة أمان — بل يتعلق بالزخم. الفرق التي تتجنب دالة سيئة غالبًا ما تتجنبها بالكامل، بما في ذلك الأجزاء التي من الآمن بشكل تافه إصلاحها. تحقيق بعض المكاسب منخفضة المخاطرة أولاً (إعادة تسمية المتغيرات، إزالة تكرار التحقق، استبدال Boolean flags بمعاملات مسماة) يبني الثقة ويُقلّص الملف قبل أن يضطر أحد لاتخاذ قرار أصعب بشأن التغييرات الهيكلية الأكثر خطورة.
لماذا يطلب تغطية اختبارية قبل اقتراح الأمور المحفوفة بالمخاطر
الطريقة الأكثر شيوعًا لفشل إعادة الهيكلة هي القفز مباشرة إلى الجزء المُرضي — تقسيم دالة منتفخة إلى قطع نظيفة ومسماة جيدًا — دون التحقق من أن الاختبارات الحالية تُمارس فعليًا مسارات الكود التي يتم تغييرها. هذا الموجّه يفحص صراحةً تغطيتك الاختبارية المذكورة، وإذا كانت ضعيفة، يخبرك باختبار يجب عليك كتابته قبل محاولة إعادة الهيكلة الأعلى مخاطرة بدلاً من بعد حدوث خلل في الإنتاج.
لماذا يتم تمييز تقسيم الدالة كـ Pull Request خاص به
تقسيم دالة متعددة المسؤوليات إلى دوال منفصلة هو غالبًا "الإصلاح" الحقيقي الذي يريده الجميع، لكنه أيضًا التغيير الأكثر احتمالًا لتغيير سلوك دقيق — مسارات معالجة الأخطاء، حالات تنفيذ جزئية، ترتيب التأثيرات الجانبية. يتعامل الموجّه عمدًا مع هذا كإعادة هيكلة منفصلة أعلى مخاطرة، يجب القيام بها فقط بعد أن يتم دمج عمليات التنظيف الأكثر أمانًا وتستقر، بدلاً من تجميعها في نفس التغيير مع المكاسب السهلة.
كيفية تكييفه
كن محددًا بشأن قيودك — دالة تُستدعى من 40 مكانًا تتصرف بشكل مختلف جدًا تحت ضغط إعادة الهيكلة عن تلك التي تُستدعى من ملف اختبار واحد. إذا لم يكن لديك أي تغطية اختبارية على الإطلاق، فتوقع أن يوصي النموذج بكتابة اختبارات قبل لمس أي شيء بعد أول عنصر أو عنصرين منخفضي المخاطرة، وعامل هذه التوصية كالإجابة الفعلية وليس مجرد شكليّة يمكن تخطيها.