الفرق بين المراجعتين لصفحة: «Refactoring»
طلا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) تنسيق الصفحة وإضافة الأقسام الناقصة. |
||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE:إعادة التصميم (Refactoring)}}</noinclude> | <noinclude>{{DISPLAYTITLE:إعادة التصميم (Refactoring)}}</noinclude> | ||
تهدف عملية إعادة التصميم (refactoring) للحصول على شيفرة جيّدة سهلة القراءة يسهل تطويرها والتخلُّص من المتطلَّبات التقنيّة الزائدة فيها، وهذا ما يُعرَف بالشيفرة النظيفة (clean code) لأنّ الشيفرة الرديئة لا بُدَّ وأن تنعكس سلبًا على نجاح المشروع البرمجيّ. | تهدف عملية إعادة التصميم (refactoring) للحصول على شيفرة جيّدة سهلة القراءة يسهل تطويرها والتخلُّص من المتطلَّبات التقنيّة الزائدة فيها، وهذا ما يُعرَف بالشيفرة النظيفة (clean code) لأنّ الشيفرة الرديئة لا بُدَّ وأن تنعكس سلبًا على نجاح المشروع البرمجيّ. | ||
== [[Refactoring/what is refactoring|كيف تكون الشيفرة نظيفة؟]] == | |||
* | تهدف عملية إعادة التصميم (refactoring) للتخلُّص من المتطلَّبات التقنيّة الزائدة، إذ تحوِّل كلَّ الفوضى المنتشرة في الشيفرة إلى شيفرةٍ نظيفةٍ (clean code) ذات تصميمٍ مُبسَّط، وهذا -لا بُدَّ- أمرٌ رائعٌ. من مميزات الشيفرة النظيفة: | ||
* واضحة مقروءة | |||
* لا تكرار فيها | * لا تكرار فيها | ||
* بأقل عددٍ ممكنٍ من الأصناف | * بأقل عددٍ ممكنٍ من الأصناف | ||
* تجتاز الاختبارات المختلفة بنجاح | * تجتاز الاختبارات المختلفة بنجاح | ||
* سهلة ولا تحتاج الصيانة | * سهلة ولا تحتاج الصيانة المتكرِّرة | ||
== [[Refactoring/technical debt|فخ الأعباء التقنية]] == | |||
يقع الكثير من المبرمجين في فخ الأعباء التقنية وهذا مكلفٌ جدًا إن لم يُعالَج بفترة مبكِّرة، ومن أسبابه: | يقع الكثير من المبرمجين في فخ الأعباء التقنية وهذا مكلفٌ جدًا إن لم يُعالَج بفترة مبكِّرة، ومن أسبابه: | ||
* '''ضغط العمل:''' مما يؤدي لنشر بعض الميّزات (features) قبل الانتهاء منها كلِّيَّا. | * '''ضغط العمل:''' مما يؤدي لنشر بعض الميّزات (features) قبل الانتهاء منها كلِّيَّا. | ||
سطر 23: | سطر 23: | ||
* '''الإلمام غير الكافي:''' عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة. | * '''الإلمام غير الكافي:''' عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة. | ||
== [[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|مشاكل الشيفرات ( | == [[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/techniques|تقنيات إعادة التصميم]] == | ||
هنالك العديد من تقنيات إعادة التصميم التي يمكن استعمالها في حالات عديدة. تنقسم هذه التقنيات إلى: | |||
=== | ===[[Refactoring/techniques/composing methods|إنشاء التوابع]]=== | ||
تستهدف إعادة التصميم بشكل رئيسيٍّ إنشاء التوابع الصحيحة المناسبة، إذ تكون التوابع الطويلة سببًا للمشاكل في كثيرٍ من الحالات، وتجعل شيفرات بعض التوابع منطق التنفيذ (execution logic) غامضًا ويصبح التابع بهذا عصيَّ الفهم من جهةٍ وصعب التغييرٍ من جهة ثانية. | |||
=== | يشمل هذا القسم من الحلول كلَّ ما يتعلق بالتوابع وإزالة التكرار (duplicates) في الشيفرة ليسمح بإجراء التطويرات المستقبليّة. | ||
===[[Refactoring/techniques/moving features between objects|نقل الميزات ما بين الكائنات]]=== | |||
تساعد عملية إعادة التصميم في توزيع المهام بشكل مثاليّ على الأصناف المختلفة في الشيفرة، وتضمن تقنيات الحل هذه طريقةً آمنةً لنقل المهام ما بين الأصناف، وإنشاء أصناف جديدة وحماية تفاصيل عملية التنفيذ من الوصول العام. | |||
===[[Refactoring/techniques/organizing data|تنظيم البيانات]]=== | |||
تساعد تقنيات إعادة التصميم هذه بالتعامل مع البيانات، وتبديل أصناف ذات وظائف كثيرة مكان الأنواع الأساسية (primitives). نتيجة أخرى مهمة نحصل عليها بتطبيق هذه التقنيات هي فك ارتباطات صنف مما يجعل الصنف قابلًا للنقل وإعادة الاستعمال. | |||
===[[Refactoring/techniques/simplifying conditional expressions|تبسيط التعابير الشرطية]]=== | |||
تزداد البنية المنطقية للشروط تعقيدًا مع مرور الوقت، لذا هنالك الكثير من التقنيات لمواجهة هذا التعقيد وتبسيطه. | |||
=== | ===[[Refactoring/techniques/simplifying method calls|تبسيط استدعاءات التوابع]]=== | ||
تجعل التقنيات التي سيشار إليها في هذا القسم استدعاءات التوابع أبسط وأسهل للفهم والاستيعاب. سيؤدي ذلك بدوره إلى تبسيط الواجهات للتفاعل بين الأصناف. | |||
== | ===[[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): وهذا يعني زيادة عدد الشيفرات التي سيُعاد العمل عليها مستقبلًا.
- لا رقابة للالتزام بالنمط المُوحَّد: عندما يكتب كلُّ شخصٍ شيفرةً بحسب نظرته وطريقته الخاصّة.
- الإلمام غير الكافي: عندما لا يعرف المُطوِّر كيفيّة كتابة شيفرة فعّالةً ومناسبة.
متى نحتاج إعادة التصميم؟
نحتاج إلى إعادة التصميم:
- عند إضافة ميّزةٍ (feature) جديدة: إذ سيصبح التحكُّم بالشيفرة النظيفة (clean code) أكثر سهولةً، وبالتالي فإنّ إجراء التغييرات سيكون أسهل بكثيرٍ مما كان عليه قبل إعادة التصميم.
- عند إصلاح الأخطاء (bugs): إذ ستتَّضح الأخطاء بجهدٍ ووقتٍ أقل، وستغني إعادة التصميم المبكِّرة عن الحاجةَ لإعادة التصميم المُخصَّص لاحقًا.
- أثناء مراجعة الشيفرة (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)، وبإنشاء أصناف وواجهات جديدة، وبتبديل التفويض مكان الوراثة أو العكس.