إعادة التصميم (Refactoring)

من موسوعة حسوب
مراجعة 22:28، 30 مارس 2019 بواسطة عاطف-بن-علي (نقاش | مساهمات) (استبدال لفظة بسيط بطفيف، لأن البساطة في اللغة العربية هي الامتداد (ومنه يقال للأرض الممتدة بسيطة).)
اذهب إلى التنقل اذهب إلى البحث

تهدف عملية إعادة التصميم (refactoring) للحصول على شيفرة جيّدة سهلة القراءة يسهل تطويرها والتخلُّص من المتطلَّبات التقنيّة الزائدة فيها، وهذا ما يُعرَف بالشيفرة النظيفة (clean code) لأنّ الشيفرة الرديئة لا بُدَّ من انعكاسها سلبًا على نجاح المشروع البرمجيّ.

كيف تكون الشيفرة نظيفة؟

هدف عملية إعادة التصميم (refactoring) هو التخلُّص من المتطلَّبات التقنيّة الزائدة، إذ تحوِّل كلَّ الفوضى المنتشرة في الشيفرة إلى شيفرةٍ نظيفةٍ (clean code) ذات تصميمٍ سهل، وهذا -لا بُدَّ- أمرٌ رائعٌ. من مميزات الشيفرة النظيفة:

  • واضحة ومقروءة
  • لا تكرار فيها
  • بأقل عددٍ ممكنٍ من الأصناف
  • تجتاز الاختبارات المختلفة بنجاح
  • سهلة ولا تحتاج الصيانة المتكرِّرة

فخ الأعباء التقنية

يقع الكثير من المبرمجين في فخ الأعباء التقنية وهذا مكلفٌ جدًا إن لم يُعالَج في وقت مبكِّر، ومن أسبابه:

  • ضغط العمل: مما يؤدي لنشر بعض الميّزات (features) قبل الانتهاء منها كلِّيَّا.
  • التغافل عن عواقب الأعباء التقنيّة: لأنّ الأعباء التقنيّة ستحدُّ من سرعة التطوير البرمجيّ.
  • الفشل بمعالجة الترابط الشديد ما بين المكونات البرمجيّة: وذلك عندما يبدو المشروع كتلةً واحدةً بدلًا من وحداتٍ مستقلةٍ.
  • إهمال إجراء الاختبارات: وتكون النتائج حينئذٍ كارثيّة!
  • صياغة توثيقيّة هزيلة: تكون سببًا للكثير من المشاكل لدى المبرمجين الجُدد.
  • غياب التواصل الفعّال بين أعضاء الفريق: كأن يتابع المبرمجون والمطورون العمل وفقًا لمعلوماتٍ وعملياتٍ قديمةٍ من المشروع.
  • التطوير بعيد الأمد لعدّة فروع بوقتٍ واحدٍ: وخاصّة عندما يكون هنالك تغييرات إفراديّة.
  • تسويف عملية إعادة التصميم (refactoring): وهذا يعني زيادة عدد الشيفرات التي سيُعاد العمل عليها مستقبلًا.
  • لا رقابة للالتزام بالنمط المُوحَّد: عندما يكتب كلُّ شخصٍ شيفرةً بحسب نظرته وطريقته الخاصّة.
  • الإلمام غير الكافي: عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة.

متى نحتاج إعادة التصميم؟

نحتاج إلى إعادة التصميم:

  1. عند إضافة ميّزةٍ (feature) جديدة: إذ سيصبح التحكُّم بالشيفرة النظيفة (clean code) أكثر سهولةً، وبالتالي فإنّ إجراء التغييرات سيكون أسهل بكثيرٍ مما كان عليه قبل إعادة التصميم.
  2. عند إصلاح الأخطاء (bugs): إذ ستتَّضح الأخطاء بجهدٍ ووقتٍ أقل، وستغني إعادة التصميم المبكِّرة عن الحاجةَ لإعادة التصميم المُخصَّص لاحقًا.
  3. أثناء مراجعة الشيفرة (code review): إذ هي الفرصةُ الأخيرة لتوضيب الشيفرة قبل نشرها للعامّة.

خطوات إعادة التصميم

تجري عملية إعادة التصميم عبر عدّة خطواتٍ تُحدِث تغييرًا طفيفا تدريجيًّا يجعل الشيفرة (مع كلِّ تغييرٍ) أفضل بقليلٍ، ولكنها لا توثر على أداء وفعاليّة البرنامج وتحافظ على استمرار عمله بشكلٍ سليمٍ، وتتلخص إعادة التصميم بالخطوات الآتية:

  • الحصول على شيفرةٍ نظيفة
  •  لا مهام وظيفيّة جديدة أثناء إعادة التصميم
  • اجتياز كافة الاختبارات السابقة

مثال

تفيد عملية إعادة التصميم في تبسيط التعليمات الشرطيّة المعقَّدة وذلك عبر عزل عملياتها في توابع مستقلَّة كما في المثال الآتي.

الشيفرة قبل إعادة التصميم

if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
    charge = quantity * winterRate + winterServiceCharge;
}
else {
    charge = quantity * summerRate;
}

الشيفرة بعد التصميم

if (notSummer(date)) {
    charge = winterCharge(quantity);
}
else {
    charge = summerCharge(quantity);
}

والفرق واضحٌ ما بين الشيفرتين من ناحية التنظيم (organization) وسهولة كشف الأخطاء (bug detects) وقابليّة القراءة (readability) والصيانة (maintenance).

مشاكل الشيفرات

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

المبالغة والإطالة

قد يزداد حجم الشيفرة ازديادًا كبيرًا ليصل لمرحلةٍ يصعُب التعامل معها، ويبدو هذا التضخم واضحًا.

الاستخدام الخطأ لمبادئ البرمجة كائنية التوجه (OOP)

من مشاكل الشيفرات أيضًا التطبيقُ الخطأ وغير المكتمل لمبادئ البرمجة كائنية التوجّه (Object-Oriented).

عرقلة التغيير

قد يكون تطوير بعض الشيفرات مشكلةً حقيقيةً إذ عند إحداث أيّ تغييرٍ في جزءٍ منها لا بُدَّ وأن تتبعه عدّة تغييراتٍ أخرى في أجزاء متفرِّقة، وبالتالي سيصبح تطوير البرنامج شائكًا معقّدًا وبتكلفةٍ غير زهيدةٍ.

الأجزاء الفائضة

وهي الأجزاء عديمة النفع في الشيفرة، وسيجعلُ التخلُّصُ منها الشيفرةَ نظيفةً يسيرة الفهم وأكثر فعاليّة.

الروابط الازدواجية

كإنشاء رابطٍ شديدٍ ازدواجيّ (ما بين صنفين [classes])، أو التفويض المفرط (excessive delegation).

مشاكل أخرى

ستجد في هذا القسم الاختلالات والمشكلات التي لا تنحصر في صنف محدَّد.

تقنيات إعادة التصميم

هنالك العديد من تقنيات إعادة التصميم التي يمكن استعمالها في حالات عديدة. تنقسم هذه التقنيات إلى:

إنشاء التوابع

تستهدف إعادة التصميم بشكل رئيسيٍّ إنشاء التوابع الصحيحة المناسبة، إذ تكون التوابع الطويلة سببًا للمشاكل في كثيرٍ من الحالات، وتجعل شيفرات بعض التوابع منطق التنفيذ (execution logic) غامضًا ويصبح التابع بهذا عصيَّ الفهم من جهةٍ وصعب التغييرٍ من جهة ثانية.

يشمل هذا القسم من الحلول كلَّ ما يتعلق بالتوابع وإزالة التكرار (duplicates) في الشيفرة ليسمح بإجراء التطويرات المستقبليّة.

نقل الميزات ما بين الكائنات

تساعد عملية إعادة التصميم في توزيع المهام بشكل مثاليّ على الأصناف المختلفة في الشيفرة، وتضمن تقنيات الحل هذه طريقةً آمنةً لنقل المهام ما بين الأصناف، وإنشاء أصناف جديدة وحماية تفاصيل عملية التنفيذ من الوصول العام.

تنظيم البيانات

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

تبسيط التعابير الشرطية

تزداد البنية المنطقية للشروط تعقيدًا مع مرور الوقت، لذا هنالك الكثير من التقنيات لمواجهة هذا التعقيد وتبسيطه.

تبسيط استدعاءات التوابع

تجعل التقنيات التي سيشار إليها في هذا القسم استدعاءات التوابع أبسط وأسهل للفهم والاستيعاب. سيؤدي ذلك بدوره إلى تبسيط الواجهات للتفاعل بين الأصناف.

التعامل مع التعميم

يملك التجريد (Abstraction) تقنيات إعادة التصميم الخاصة به والمرتبطة بشكل أساسي بوظيفة النقل على طول التسلسل الهرمي لوراثة الصنف (class inheritance hierarchy)، وبإنشاء أصناف وواجهات جديدة، وبتبديل التفويض مكان الوراثة أو العكس.

مصادر