Refactoring.
A controlled technique for improving the design of existing code. Browse by group, see the code smells these techniques treat, the test smells in your test suite, or the smells of AI-generated code.
المشكلة: لا تمتلك الدالة البيانات الكافية لتنفيذ إجراءات معينة. الحل: قم بإنشاء معامل جديد لتمرير البيانات اللازمة.
المشكلة: لا يتم استخدام الدالة بواسطة فئات أخرى أو تُستخدم فقط داخل التسلسل الهرمي لفئتها الخاصة. الحل: اجعل الدالة خاصة (private) أو محمية (protected).
المشكلة: تحتوي توابعك على مجموعة متكررة من المعاملات. الحل: استبدل هذه المعاملات بكائن.
المشكلة: تقوم توابع متعددة بإجراءات متشابهة تختلف فقط في قيمها الداخلية أو أرقامها أو عملياتها. الحل: اجمع هذه التوابع معاً باستخدام معامل يمرر القيمة الخاصة المطلوبة.
المشكلة: تحصل على قيم متعددة من كائن ثم تمررها كمعاملات إلى تابع. الحل: بدلاً من ذلك، جرب تمرير الكائن بأكمله.
المشكلة: لا يُستخدم المعامل داخل متن التابع. الحل: أزل المعامل غير المستخدم.
المشكلة: يجب تعيين قيمة الحقل فقط عند إنشائه، ولا تتغير في أي وقت بعد ذلك. الحل: لذا احذف التوابع التي تقوم بتعيين قيمة هذا الحقل.
المشكلة: لا يوضح اسم التابع ما يفعله التابع. الحل: أعد تسمية التابع.
المشكلة: لديك باني (Constructor) معقد يقوم بشيء أكثر من مجرد تعيين قيم المعاملات في حقول الكائن. الحل: أنشئ تابعاً مصنعاً (Factory Method) واستخدمه لاستبدال استدعاءات الباني.
المشكلة: دالة تعيد قيمة خاصة تشير إلى وجود خطأ؟ الحل: قم برمي استثناء (exception) بدلاً من ذلك.
المشكلة: تقوم برمي استثناء في مكان يمكن لاختبار بسيط فيه القيام بالمهمة؟ الحل: استبدل الاستثناء باختبار شرطي.
المشكلة: تنقسم الدالة إلى أجزاء، يتم تشغيل كل منها اعتمادًا على قيمة معامل (parameter). الحل: استخلص الأجزاء الفردية من الدالة إلى دوال خاصة بها واستدعها بدلاً من الدالة الأصلية.
المشكلة: استدعاء دالة استعلام (query method) وتمرير نتائجها كمعاملات لدالة أخرى، في حين أن هذه الدالة يمكنها استدعاء الاستعلام مباشرة. الحل: بدلاً من تمرير القيمة عبر معامل، حاول وضع استدعاء الاستعلام داخل جسم الدالة.
المشكلة: هل لديك دالة تعيد قيمة ولكنها تغير أيضًا شيئًا ما داخل الكائن؟ الحل: قسّم الدالة إلى دالتين منفصلتين. كما تتوقع، يجب أن تعيد إحداهما القيمة والأخرى تعدل الكائن.
المشكلة: لديك ارتباط ثنائي الاتجاه بين فئات، ولكن إحدى الفئات لا تستخدم ميزات الفئة الأخرى. الحل: قم بإزالة الارتباط غير المستخدم.
المشكلة: لديك كائن مرجعي (reference object) صغير جداً ونادراً ما يتغير، مما لا يبرر إدارة دورة حياته. الحل: قم بتحويله إلى كائن قيمة (value object).
المشكلة: لديك فئتان تحتاج كل منهما إلى استخدام ميزات الفئة الأخرى، ولكن الارتباط بينهما أحادي الاتجاه فقط. الحل: قم بإضافة الارتباط المفقود إلى الفئة التي تحتاجه.
المشكلة: لديك العديد من النسخ المتطابقة لفئة واحدة تحتاج إلى استبدالها بكائن واحد. الحل: قم بتحويل الكائنات المتطابقة إلى كائن مرجعي واحد.
المشكلة: هل يتم تخزين بيانات النطاق (domain data) في فئات مسؤولة عن واجهة المستخدم الرسومية (GUI)؟ الحل: إذن فمن الجيد فصل البيانات في فئات منفصلة، مع ضمان الاتصال والمزامنة بين فئة النطاق وواجهة المستخدم الرسومية.
المشكلة: تحتوي فئة على حقل مجموعة (collection field) ودوال الحصول والتعيين (getter and setter) بسيطة للعمل مع المجموعة. الحل: اجعل القيمة التي تعيدها دالة الحصول للقراءة فقط، وأنشئ دوال لإضافة/حذف عناصر المجموعة.
المشكلة: لديك حقل عام (public field). الحل: اجعل الحقل خاصاً (private) وأنشئ دوال وصول (access methods) له.
المشكلة: لديك مصفوفة تحتوي على أنواع مختلفة من البيانات. الحل: استبدل المصفوفة بكائن يحتوي على حقول منفصلة لكل عنصر.
المشكلة: فئة (أو مجموعة فئات) تحتوي على حقل بيانات. هذا الحقل له سلوكه الخاص وبياناته المرتبطة به. الحل: إنشاء فئة جديدة، ووضع الحقل القديم وسلوكه في هذه الفئة، ثم تخزين كائن الفئة في الفئة الأصلية.
المشكلة: يستخدم الكود الخاص بك رقمًا له معنى معين. الحل: استبدل هذا الرقم بثابت له اسم مقروء ومفهوم يوضح معنى الرقم.
المشكلة: لديك فئات فرعية تختلف فقط في دوالها (التي تعيد قيمًا ثابتة). الحل: استبدل الدوال بحقول في الفئة الأب واحذف الفئات الفرعية.
المشكلة: تحتوي فئة ما على حقل يحتوي على كود نوع (type code). قيم هذا النوع لا تُستخدم في شروط العوامل ولا تؤثر على سلوك البرنامج. الحل: قم بإنشاء فئة جديدة واستخدم كائناتها بدلاً من قيم كود النوع.
المشكلة: لديك نوع مرمز يؤثر على السلوك ولكن لا يمكنك استخدام فئات فرعية للتخلص منه. الحل: استبدل كود النوع بكائن حالة (state object). إذا كان من الضروري استبدال قيمة حقل بكود نوع، يتم "توصيل" كائن حالة آخر.
المشكلة: لديك نوع مرمز يؤثر بشكل مباشر على سلوك البرنامج (تؤدي قيم هذا الحقل إلى تشغيل أكواد برمجية مختلفة في الجمل الشرطية). الحل: أنشئ فئات فرعية (subclasses) لكل قيمة من قيم النوع المرمز. ثم استخلص السلوكيات ذات الصلة من الفئة الأصلية إلى هذه الفئات الفرعية. واستبدل كود تدفق التحكم بتعدد الأشكال (polymorphism).
المشكلة: تستخدم الوصول المباشر إلى الحقول الخاصة داخل الفئة. الحل: أنشئ دالة جلب (getter) ودالة تعيين (setter) للحقل، واستخدمهما فقط للوصول إلى الحقل.
المشكلة: لديك تسلسل هرمي للفئات (class hierarchy) تكون فيه الفئة الفرعية (subclass) مطابقة تقريباً للفئة العليا (superclass). الحل: ادمج الفئة الفرعية والفئة العليا.
المشكلة: يستخدم عملاء متعددون نفس الجزء من واجهة الفئة. حالة أخرى: جزء من الواجهة في فئتين متطابق. الحل: انقل هذا الجزء المتطابق إلى واجهة مستقلة خاصة به.
المشكلة: تحتوي فئة على ميزات تُستخدم فقط في حالات معينة. الحل: أنشئ فئة فرعية واستخدمها في هذه الحالات.
المشكلة: لديك فئتان تحتويان على حقول ودوال مشتركة. الحل: أنشئ فئة عليا (superclass) مشتركة لهما وانقل إليها جميع الحقول والدوال المتطابقة.
المشكلة: تنفذ فئاتك الفرعية خوارزميات تحتوي على خطوات متشابهة بنفس الترتيب. الحل: انقل هيكل الخوارزمية والخطوات المتطابقة إلى فئة عليا، واترك تنفيذ الخطوات المختلفة في الفئات الفرعية.
المشكلة: تحتوي فئاتك الفرعية (Subclasses) على بانيات (Constructors) بها كود متطابق غالباً. الحل: أنشئ بانيًا للفئة الفائقة (Superclass) وانقل الكود المشترك في الفئات الفرعية إليه. واستدعِ باني الفئة الفائقة في بانيات الفئات الفرعية.
المشكلة: فئتان تحتويان على نفس الحقل. الحل: أزل الحقل من الفئات الفرعية وانقله إلى الفئة الفائقة.
المشكلة: تحتوي فئاتك الفرعية على توابع تؤدي عملاً متشابهاً. الحل: اجعل التوابع متطابقة ثم انقلها إلى الفئة الفائقة المناسبة.
المشكلة: هل يُستخدم الحقل في عدد قليل فقط من الفئات الفرعية؟ الحل: انقل الحقل إلى هذه الفئات الفرعية.
المشكلة: هل السلوك المطبق في الفئة الفائقة يُسخدم من قِبل فئة فرعية واحدة فقط (أو عدد قليل منها)؟ الحل: انقل هذا السلوك إلى الفئات الفرعية.
المشكلة: تحتوي فئة ما على العديد من الدوال البسيطة التي تفوض العمل إلى جميع دوال فئة أخرى. الحل: جعل الفئة وارثة للفئة المفوضة، مما يجعل دوال التفويض غير ضرورية.
المشكلة: لديك فئة فرعية تستخدم جزءًا فقط من دوال فئتها الفائقة (أو لا يمكنها وراثة بيانات الفئة الفائقة). الحل: قم بإنشاء حقل وضع فيه كائن الفئة الفائقة، وفوّض الدوال إلى كائن الفئة الفائقة، وتخلص من الوراثة.
المشكلة: لديك شروط متعددة تؤدي إلى نفس النتيجة أو الإجراء. الحل: ادمج كل هذه الشروط في تعبير شرطي واحد.
المشكلة: يمكن العثور على كود متطابق في جميع فروع الشرط. الحل: انقل الكود خارج الشرط.
المشكلة: لديك تعبير شرطي معقد (if-then/else أو switch). الحل: قم بتفكيك الأجزاء المعقدة من التعبير الشرطي إلى دوال منفصلة: الشرط (condition)، وثم (then)، وإلا (else).
المشكلة: لكي يعمل جزء معين من الكود بشكل صحيح، يجب أن تكون شروط أو قيم معينة صحيحة. الحل: استبدل هذه الافتراضات بفحوصات توكيد (assertions) محددة.
المشكلة: نظراً لأن بعض التوابع تعيد قيمة null بدلاً من كائنات حقيقية، فإن لديك العديد من فحوصات التحقق من null في الكود. الحل: بدلاً من null، أعد كائناً فارغاً (Null Object) يقدم السلوك الافتراضي.
المشكلة: لديك متغير منطقي (Boolean) يعمل كراية تحكم لتعبيرات منطقية متعددة. الحل: بدلاً من هذا المتغير، استخدم break و continue و return.
المشكلة: لديك جملة شرطية تؤدي إجراءات مختلفة اعتماداً على نوع الكائن أو خصائصه. الحل: أنشئ فئات فرعية (Subclasses) تطابق فروع الجملة الشرطية. وفيها، أنشئ تابعاً مشتركاً وانقل الكود من الفرع المقابل للجملة الشرطية إليه. ثم استبدل الجملة الشرطية باستدعاء التابع المعني. وتكون النتيجة هي الوصول للتطبيق الصحيح عبر تعدد الأشكال (Polymorphism) اعتماداً على فئة الكائن.
المشكلة: لديك مجموعة من الجمل الشرطية المتداخلة ويصعب تحديد التدفق الطبيعي لتنفيذ الكود. الحل: اعزل جميع الفحوصات الخاصة والحالات الاستثنائية في عبارات منفصلة وضعها قبل الفحوصات الرئيسية. من الناحية المثالية، يجب أن تحصل على قائمة مسطحة من الشروط، واحدًا تلو الآخر.
المشكلة: عندما تقوم فئة واحدة بعمل فئتين، ينتج عن ذلك ارتباك وتعقيد. الحل: بدلاً من ذلك، أنشئ فئة جديدة وضع فيها الحقول والدوال المسؤولة عن الوظائف ذات الصلة.
المشكلة: يحصل العميل على الكائن B من حقل أو دالة في الكائن A. ثم يقوم العميل باستدعاء دالة في الكائن B. الحل: أنشئ دالة جديدة في الفئة A تفوض الاستدعاء إلى الكائن B. الآن لا يعرف العميل الفئة B ولا يعتمد عليها.
المشكلة: الفئة لا تفعل شيئاً تقريباً وليست مسؤولة عن أي شيء، ولا توجد مسؤوليات إضافية مخططة لها. الحل: انقل جميع الميزات من الفئة إلى فئة أخرى.
المشكلة: لا تحتوي فئة أدوات (Utility Class) على التابع الذي تحتاجه ولا يمكنك إضافة التابع إلى الفئة. الحل: أضف التابع إلى فئة عميلة (Client Class) ومرر كائناً من فئة الأدوات إليها كمعامل.
المشكلة: لا تحتوي فئة أدوات (Utility Class) على بعض التوابع التي تحتاجها. ولكن لا يمكنك إضافة هذه التوابع إليها. الحل: أنشئ فئة جديدة تحتوي على التوابع المطلوبة واجعلها إما فئة فرعية (Subclass) أو فئة مغلفة (Wrapper) لفئة الأدوات.
المشكلة: يتم استخدام حقل في فئة أخرى أكثر من استخدامه في الفئة الخاصة به. الحل: أنشئ حقلاً في فئة جديدة ووجّه جميع مستخدمي الحقل القديم إليه.
المشكلة: يتم استخدام تابع في فئة أخرى أكثر من استخدامه في الفئة الخاصة به. الحل: أنشئ تابعاً جديداً في الفئة التي تستخدم التابع بشكل أكبر، ثم انقل الكود من التابع القديم إلى هناك. حوّل كود التابع الأصلي إلى إشارة مرجعية للتابع الجديد في الفئة الأخرى أو احذفه تماماً.
المشكلة: تحتوي الفئة على عدد كبير جداً من التوابع التي تقوم ببساطة بالتفويض لكائنات أخرى. الحل: احذف هذه التوابع واجبر العميل على استدعاء التوابع النهائية مباشرة.
المشكلة: لديك جزء من الكود يمكن تجميعه معاً. الحل: انقل هذا الكود إلى دالة جديدة منفصلة واستبدل الكود القديم باستدعاء لهذه الدالة.
المشكلة: لديك تعبير برمجى يصعب فهمه. الحل: ضع نتيجة التعبير أو أجزائه في متغيرات منفصلة توضح نفسها بنفسها.
المشكلة: عندما يكون متن التابع أكثر وضوحاً من التابع نفسه، استخدم هذه التقنية. الحل: استبدل استدعاءات التابع بمحتوى التابع واحذف التابع نفسه.
المشكلة: لديك متغير مؤقت يتم تعيين نتيجة تعبير بسيط له فقط ولا شيء غير ذلك. الحل: استبدل الإشارات إلى المتغير بالتعبير نفسه.
المشكلة: يتم تعيين قيمة معينة لمعامل داخل متن التابع. الحل: استخدم متغيراً محلياً بدلاً من المعامل.
المشكلة: لديك دالة طويلة تتشابك فيها المتغيرات المحلية لدرجة أنه لا يمكنك تطبيق تقنية استخلاص الدالة (Extract Method). الحل: قم بتحويل الدالة إلى فئة منفصلة بحيث تصبح المتغيرات المحلية حقولاً في هذه الفئة. بعد ذلك، يمكنك تقسيم الدالة إلى عدة دوال فرعية داخل نفس الفئة.
المشكلة: تضع نتيجة تعبير في متغير محلي لاستخدامه لاحقًا في الكود الخاص بك. الحل: انقل التعبير بالكامل إلى دالة منفصلة وأعد النتيجة منها. استعلم من الدالة بدلاً من استخدام المتغير. وادمج الدالة الجديدة في دوال أخرى، إذا لزم الأمر.
المشكلة: لديك متغير محلي يُستخدم لتخزين قيم وسيطة مختلفة داخل دالة (باستثناء متغيرات حلقات التكرار). الحل: استخدم متغيرات مختلفة للقيم المختلفة. يجب أن يكون كل متغير مسؤولاً عن شيء معين واحد فقط.
المشكلة: إذن تريد استبدال خوارزمية موجودة بأخرى جديدة؟ الحل: استبدل جسم الدالة التي تنفذ الخوارزمية بالخوارزمية الجديدة.