الفرق بين المراجعتين لصفحة: «Refactoring»

من موسوعة حسوب
طلا ملخص تعديل
تنسيق الصفحة وإضافة الأقسام الناقصة.
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:إعادة التصميم (Refactoring)}}</noinclude>
<noinclude>{{DISPLAYTITLE:إعادة التصميم (Refactoring)}}</noinclude>
== ما الهدف؟ ==
تهدف عملية إعادة التصميم (refactoring) للحصول على شيفرة جيّدة سهلة القراءة يسهل تطويرها والتخلُّص من المتطلَّبات التقنيّة الزائدة فيها، وهذا ما يُعرَف بالشيفرة النظيفة (clean code) لأنّ الشيفرة الرديئة لا بُدَّ وأن تنعكس سلبًا على نجاح المشروع البرمجيّ.
تهدف عملية إعادة التصميم (refactoring) للحصول على شيفرة جيّدة سهلة القراءة يسهل تطويرها والتخلُّص من المتطلَّبات التقنيّة الزائدة فيها، وهذا ما يُعرَف بالشيفرة النظيفة (clean code) لأنّ الشيفرة الرديئة لا بُدَّ وأن تنعكس سلبًا على نجاح المشروع البرمجيّ.


=== [[Refactoring/what is refactoring|كيف تكون الشيفرة نظيفة؟]] ===
== [[Refactoring/what is refactoring|كيف تكون الشيفرة نظيفة؟]] ==
* واضحةً مقروءةً
تهدف عملية إعادة التصميم (refactoring) للتخلُّص من المتطلَّبات التقنيّة الزائدة، إذ تحوِّل كلَّ الفوضى المنتشرة في الشيفرة إلى شيفرةٍ نظيفةٍ (clean code) ذات تصميمٍ مُبسَّط، وهذا -لا بُدَّ- أمرٌ رائعٌ. من مميزات الشيفرة النظيفة:
* واضحة مقروءة
* لا تكرار فيها
* لا تكرار فيها
* بأقل عددٍ ممكنٍ من الأصناف (classes)
* بأقل عددٍ ممكنٍ من الأصناف
* تجتاز الاختبارات المختلفة بنجاح
* تجتاز الاختبارات المختلفة بنجاح
* سهلة ولا تحتاج الصيانة (maintenance) المتكرِّرة
* سهلة ولا تحتاج الصيانة المتكرِّرة


=== [[Refactoring/technical debt|فخ الأعباء التقنية (Technical Debts)]] ===
== [[Refactoring/technical debt|فخ الأعباء التقنية]] ==
يقع الكثير من المبرمجين في فخ الأعباء التقنية وهذا مكلفٌ جدًا إن لم يُعالَج بفترة مبكِّرة، ومن أسبابه:
يقع الكثير من المبرمجين في فخ الأعباء التقنية وهذا مكلفٌ جدًا إن لم يُعالَج بفترة مبكِّرة، ومن أسبابه:
* '''ضغط العمل:''' مما يؤدي لنشر بعض الميّزات (features) قبل الانتهاء منها كلِّيَّا.
* '''ضغط العمل:''' مما يؤدي لنشر بعض الميّزات (features) قبل الانتهاء منها كلِّيَّا.
سطر 23: سطر 23:
* '''الإلمام غير الكافي:''' عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة.
* '''الإلمام غير الكافي:''' عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة.


=== [[Refactoring/when|متى نحتاج إعادة التصميم؟]] ===
== [[Refactoring/when|متى نحتاج إعادة التصميم؟]] ==
# عند إضافة ميّزةٍ (feature) جديدة: إذ سيصبح التحكُّم بالشيفرة النظيفة (clean code) أكثر سهولةً، وبالتالي فإنّ إجراء التغييرات سيكون أسهل بكثيرٍ مما كان عليه قبل إعادة التصميم.
نحتاج إلى إعادة التصميم:
# عند إصلاح الأخطاء (bugs): إذ ستتَّضح الأخطاء بجهدٍ ووقتٍ أقل، وستغني إعادة التصميم المبكِّرة عن الحاجةَ لإعادة التصميم المُخصَّص لاحقًا.
# '''عند إضافة ميّزةٍ (feature) جديدة''': إذ سيصبح التحكُّم بالشيفرة النظيفة (clean code) أكثر سهولةً، وبالتالي فإنّ إجراء التغييرات سيكون أسهل بكثيرٍ مما كان عليه قبل إعادة التصميم.
# أثناء مراجعة الشيفرة (code review): إذ هي الفرصةُ الأخيرة لتوضيب الشيفرة قبل نشرها للعامّة.
# '''عند إصلاح الأخطاء (bugs)''': إذ ستتَّضح الأخطاء بجهدٍ ووقتٍ أقل، وستغني إعادة التصميم المبكِّرة عن الحاجةَ لإعادة التصميم المُخصَّص لاحقًا.
# '''أثناء مراجعة الشيفرة (code review)''': إذ هي الفرصةُ الأخيرة لتوضيب الشيفرة قبل نشرها للعامّة.
 
== [[Refactoring/how to|خطوات إعادة التصميم]] ==
تجري عملية إعادة التصميم عبر عدّة خطواتٍ تُحدِث تغييرًا بسيطًا تدريجيًّا يجعل الشيفرة (مع كلِّ تغييرٍ) أفضل بقليلٍ، ولكنها لا توثر على أداء وفعاليّة البرنامج وتحافظ على استمرار عمله بشكلٍ سليمٍ، وتتلخص إعادة التصميم بالخطوات الآتية:
* '''الحصول على شيفرةٍ نظيفة'''
* ''' لا مهام وظيفيّة جديدة أثناء إعادة التصميم'''
* '''اجتياز كافة الاختبارات السابقة'''


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


== [[Refactoring/smells|مشاكل الشيفرات (Code Smells)]] ==
== [[Refactoring/smells|مشاكل الشيفرات]] ==
قد تعاني الشيفرات الكثير من الأمراض والعلل الشكلية؛ فبمجرد اكتشاف تلك العلل الظاهرية، يسهل علينا معرفة العلاج (التقنيات) وتطبيقه (إعادة التصميم) للحصول على شيفرة سليمة نظيفة. من هذه العلل:
 
=== [[Refactoring/smells/bloaters|المبالغة والإطالة]] ===
قد يزداد حجم الشيفرة ازديادًا كبيرًا ليصل لمرحلةٍ يصعُب التعامل معها، ويبدو هذا التضخم واضحًا.
=== [[Refactoring/smells/oo abusers|الاستخدام الخطأ لمبادئ البرمجة كائنية التوجه (OOP)]] ===
من مشاكل الشيفرات أيضًا التطبيقُ الخطأ وغير المكتمل لمبادئ البرمجة كائنية التوجّه (Object-Oriented).
=== [[Refactoring/smells/change preventers|عرقلة التغيير]] ===
قد يكون تطوير بعض الشيفرات مشكلةً حقيقيةً إذ عند إحداث أيّ تغييرٍ في جزءٍ منها لا بُدَّ وأن تتبعه عدّة تغييراتٍ أخرى في أجزاء متفرِّقة، وبالتالي سيصبح تطوير البرنامج شائكًا معقّدًا وبتكلفةٍ غير زهيدةٍ.
=== [[Refactoring/smells/dispensables|الأجزاء الفائضة]] ===
وهي الأجزاء عديمة النفع في الشيفرة، وسيجعلُ التخلُّصُ منها الشيفرةَ نظيفةً يسيرة الفهم وأكثر فعاليّة.
=== [[Refactoring/smells/couplers|الروابط الازدواجية]] ===
كإنشاء رابطٍ شديدٍ ازدواجيّ (ما بين صنفين [classes])، أو التفويض المفرط (excessive delegation).


=== المبالغة والإطالة ===
=== [[Refactoring/smells/other smells|مشاكل أخرى]] ===
قد يزداد حجم الشيفرة ازديادًا كبيرًا ليصل لمرحلةٍ يصعُب التعامل معها، ويبدو هذا التضخم واضحًا في:
ستجد في هذا القسم الاختلالات والمشكلات التي لا تنحصر في صنف محدَّد.
# [[Refactoring/long method|التوابع  الطويلة (long methods)]]
# [[Refactoring/large class|الأصناف الواسعة (large classes)]]
# [[Refactoring/primitive obsession|هوس الحقول الأساسيّة (primitives obsession)]]
# [[Refactoring/long parameter list|المعاملات الكثيرة في التوابع (long parameter list)]]
# [[Refactoring/data clumps|البيانات المُجمَّعة (data clumps)]]


=== الاستخدام الخطأ لمبادئ البرمجة كائنية التوجه (OOP) ===
== [[Refactoring/techniques|تقنيات إعادة التصميم]] ==
مثل:
هنالك العديد من تقنيات إعادة التصميم التي يمكن استعمالها في حالات عديدة. تنقسم هذه التقنيات إلى:
# [[Refactoring/alternative classes with different interfaces|استخدام الأصناف البديلة (alternative) ذات الواجهات (interfaces) المختلفة]]
# [[Refactoring/refused bequest|الوراثة الفائضة (refused bequest)]]
# [[Refactoring/switch statements|الشكل المعقَّد لتعليمة switch]]
# [[Refactoring/temporary field|الحقول المؤقّتة (temporary fields)]]


=== عرقلة التغيير ===
===[[Refactoring/techniques/composing methods|إنشاء التوابع]]===
إذ عند إحداث أيّ تغييرٍ في الشيفرة لا بُدَّ وأن تتبعه عدّة تغييراتٍ أخرى في أجزاء متفرِّقة، من معوِّقات التغيير:
تستهدف إعادة التصميم بشكل رئيسيٍّ إنشاء التوابع الصحيحة المناسبة، إذ تكون التوابع الطويلة سببًا للمشاكل في كثيرٍ من الحالات، وتجعل شيفرات بعض التوابع منطق التنفيذ (execution logic) غامضًا ويصبح التابع بهذا عصيَّ الفهم من جهةٍ وصعب التغييرٍ من جهة ثانية.
# [[Refactoring/divergent change|التغيير المتشعِّب (divergent change)]]
# [[Refactoring/parallel inheritance hierarchies|الهيكليّة التفرعيّة للوراثة (parallel inheritance hierarchies)]]
# [[Refactoring/shotgun surgery|تغيير الأصناف المتعدِّدة (shotgun surgery)]]


=== الأجزاء الفائضة ===
يشمل هذا القسم من الحلول كلَّ ما يتعلق بالتوابع وإزالة التكرار (duplicates) في الشيفرة ليسمح بإجراء التطويرات المستقبليّة.
وهي الأجزاء عديمة النفع في الشيفرة، وسيجعلُ التخلُّصُ منها الشيفرةَ نظيفةً يسيرة الفهم وأكثر فعاليّة، منها:
===[[Refactoring/techniques/moving features between objects|نقل الميزات ما بين الكائنات]]===
# [[Refactoring/comments|التعليقات (comments)]]
تساعد عملية إعادة التصميم في توزيع المهام بشكل مثاليّ على الأصناف المختلفة في الشيفرة، وتضمن تقنيات الحل هذه طريقةً آمنةً لنقل المهام ما بين الأصناف، وإنشاء أصناف جديدة وحماية تفاصيل عملية التنفيذ من الوصول العام.
# [[Refactoring/duplicate code|تكرار  الشيفرة (duplicates)]]
===[[Refactoring/techniques/organizing data|تنظيم البيانات]]===
# [[Refactoring/data class|أصناف البيانات (data classes)]]
تساعد تقنيات إعادة التصميم هذه بالتعامل مع البيانات، وتبديل أصناف ذات وظائف كثيرة مكان الأنواع الأساسية (primitives). نتيجة أخرى مهمة نحصل عليها بتطبيق هذه التقنيات هي فك ارتباطات صنف مما يجعل الصنف قابلًا للنقل وإعادة الاستعمال.
# [[Refactoring/dead code|الشيفرة الميتة (dead code)]]
===[[Refactoring/techniques/simplifying conditional expressions|تبسيط التعابير الشرطية]]===
# [[Refactoring/lazy class|الأصناف الخاملة (lazy classes)]]
تزداد البنية المنطقية للشروط تعقيدًا مع مرور الوقت، لذا هنالك الكثير من التقنيات لمواجهة هذا التعقيد وتبسيطه.
# [[Refactoring/speculative generality|الخيال البرمجيّ (speculative generality)]]


=== الروابط الازدواجية ===
===[[Refactoring/techniques/simplifying method calls|تبسيط استدعاءات التوابع]]===
كإنشاء رابطٍ شديدٍ ازدواجيّ (ما بين صنفين [classes])، أو التفويض المفرط (excessive delegation)، وتتمثل هذه المشكلة بالنقاط الآتية:
تجعل التقنيات التي سيشار إليها في هذا القسم استدعاءات التوابع أبسط وأسهل للفهم والاستيعاب. سيؤدي ذلك بدوره إلى تبسيط الواجهات للتفاعل بين الأصناف.
# [[Refactoring/feature envy|التسلط على الكائنات الأخرى (feature envy)]]
# [[Refactoring/inappropriate intimacy|الارتباط الوثيق غير المناسب (inappropriate intimacy)]]
# [[Refactoring/incomplete library class|أصناف المكتبة غير الكافية (incomplete library class)]]
# [[Refactoring/message chains|سلاسل الرسائل (message chains)]]
# [[Refactoring/middle man|الوسيط (middle man)]]


== تقنيات الحلول ==
===[[Refactoring/techniques/dealing with generalization|التعامل مع التعميم]]===
يملك التجريد (Abstraction) تقنيات إعادة التصميم الخاصة به والمرتبطة بشكل أساسي بوظيفة النقل على طول التسلسل الهرمي لوراثة الصنف (class inheritance hierarchy)، وبإنشاء أصناف وواجهات جديدة، وبتبديل التفويض مكان الوراثة أو العكس.


== مصادر ==
== مصادر ==
* [https://refactoring.guru/ صفحة توثيق إعادة التصميم في موقع refactoring.guru]
* [https://refactoring.guru/ صفحة توثيق إعادة التصميم في موقع refactoring.guru]
[[تصنيف:Refactoring]]
[[تصنيف:Refactoring]]

مراجعة 19:24، 27 فبراير 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)، وبإنشاء أصناف وواجهات جديدة، وبتبديل التفويض مكان الوراثة أو العكس.

مصادر