Code Smell في التطوير المحمول: ماهيته وأنواعه ومبادئ الإصلاح

المؤلف: IT Sectr نُشر: 2026-05-13 وقت القراءة: 9 دق

Code Smell هو مؤشر سطحي في الكود يشير إلى مشكلة محتملة في تصميم أو بنية التطبيق. صاغ المصطلح كينت بيك وروج له مارتن فاولر في كتاب «Refactoring: Improving the Design of Existing Code». وفقاً لـ Martin Fowler، رائحة الكود لا تعني بالضرورة خطأ، لكنها تشير دائماً تقريباً إلى الحاجة لإعادة الهيكلة لتحسين قابلية الصيانة.

النقاط الرئيسية

  • Code Smell — مؤشر سطحي لمشكلة في الكود ليست خطأ لكنها تعقد الصيانة والتطوير
  • Long Method — الرائحة الأكثر شيوعاً: طريقة تفعل الكثير وتحتاج للتقسيم إلى عدة طرق
  • Large Class — صنف ينتهك مبدأ المسؤولية الواحدة ويحتوي على منطق من مجالات مختلفة
  • Duplicate Code — أجزاء كود متكررة تتطلب التصحيح في عدة أماكن عند التغيير
  • Feature Envy — طريقة تستخدم بيانات صنف آخر أكثر من بيانات صنفها الخاص

ما هو Code Smell

Code Smell هو استعارة للدلالة على أعراض في الكود المصدري تشير باحتمالية عالية إلى مشاكل أعمق. المصطلح نفسه ليس له تعريف رسمي — إنه استرشاد مبني على خبرة المطورين. قام مارتن فاولر وكينت بيك أول مرة بتنظيم 22 رائحة في عام 1999 في كتاب «Refactoring»، ومعظمها لا يزال ذا صلة بعد عقود.

من المهم فهم الفرق بين Code Smell والخطأ. الرائحة ليست خطأ: الكود يترجم ويعمل وينتج نتائج صحيحة. المشكلة أن مثل هذا الكود يصعب قراءته وتعديله واختباره. مع الوقت، تزداد تكلفة كل تغيير وتقل الثقة في صحة إعادة الهيكلة. أدوات التحليل الثابت (SonarQube، Detekt، SwiftLint) تكتشف تلقائياً العديد من الروائح.

الطبيعة الاسترشادية لـ Code Smell تعني أنه ليس كل طريقة طويلة يجب تقسيمها، وليس كل صنف كبير يحتاج إعادة هيكلة. القرار يتخذه المطور بتقييم السياق: تكرار التغييرات، أهمية الوحدة، خطط التطوير. المهندسون ذوو الخبرة يشعرون بالرائحة حدسياً — الكود «رائحته كريهة» رغم أن جميع القواعد الرسمية مطبقة.

الأنواع الرئيسية لـ Code Smell

حدد فاولر 22 رائحة مقسمة إلى عدة فئات. للتطوير المحمول، الأكثر أهمية هي الروائح الهيكلية، وروائح التصميم كائني التوجه، والمشاكل المحددة المتعلقة بقيود المنصة. دعنا نفحص كل مجموعة بأمثلة من الواقع العملي.

الروائح الهيكلية

Long Method هي الرائحة الأكثر شيوعاً في التطبيقات المحمولة. شاشة نموذج التسجيل غالباً تحتوي على طريقة setupUI واحدة بطول 200+ سطر تنشئ كل الـ Views، وتضبط القيود، وتشترك في الأحداث، وتعالج الأخطاء. الحل: التقسيم إلى طرق حسب الكتل المنطقية — configureEmailField، configurePasswordField، setupConstraints، bindViewModel.

Large Class — Activity أو ViewController مسؤولة عن العرض والتنقل ومنطق الأعمال والتفاعلات الشبكية كلها معاً. هذا الصنف ينتهك مبدأ المسؤولية الواحدة ويحتوي على عشرات الحقول والطرق. في Android، غالباً ما يكون Fragment بـ 1000+ سطر يحتوي على منطق شاشات مختلفة. الحل: استخراج presenter/ViewModel، ونقل كود الشبكة إلى repository، والتنقل إلى coordinator.

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

روائح التصميم كائني التوجه

Feature Envy — طريقة من صنف تستخدم بكثافة بيانات صنف آخر. في Android، يظهر هذا عندما تصل ViewModel مباشرة إلى حقول نموذج User بدلاً من استدعاء طريقة النموذج. الإشارة: إذا كان يمكن نقل طريقة إلى الصنف الذي تستخدم بياناته — انقلها. Switch Statements (سلاسل الشروط) — بناء switch أو سلسلة if-else تتحقق من نوع الكائن. بدلاً من ذلك، استخدم تعدد الأشكال أو نمط الاستراتيجية.

Data Class — صنف يخزن البيانات فقط لكنه لا يحتوي على سلوك. data classes في Kotlin أو الهياكل في Swift ليست رائحة بحد ذاتها. المشكلة تنشأ عندما يكون منطق الأعمال الذي يعمل مع هذه البيانات مبعثراً في قاعدة الكود بدلاً من أن يكون مغلفاً. Refused Bequest — صنف فرعي لا يستخدم معظم طرق الصنف الأب ويتجاوزها بأكواد وهمية فارغة. علامة على وراثة غير صحيحة: استبدل الوراثة بالتركيب.

الروائح في التطوير المحمول

God Activity / God Fragment — Activity أو Fragment تعرف كل شيء: دورة الحياة، البيانات، التنقل، الأذونات، حقن التبعيات. هذا هو أغلى صنف في الصيانة في التطبيق. الحل: أنماط معمارية MVVM أو MVI أو Clean Architecture تفصل المسؤوليات. Giant ViewController — المكافئ في iOS، حيث UIViewController يحتوي على كل منطق الشاشة ويتجاوز غالباً 500 سطر.

Hardcoded Resources — نصوص وألوان وأحجام وعناوين API مضمنة مباشرة في الكود. في Android، هذا ينتهك نظام الموارد R؛ في iOS، NSLocalizedString و Asset Catalog. الإصلاح: نقل كل النصوص إلى strings.xml أو Localizable.strings، والعناوين إلى ملف إعدادات، والأحجام إلى dimens. Leaking Context — الاحتفاظ بمرجع إلى Activity أو ViewController لفترة أطول من عمر المكون نفسه. يؤدي إلى تسرب الذاكرة وتعطل التطبيق. الحل: مراجع ضعيفة، Jetpack Lifecycle، RxSwift DisposeBag.

الرائحةأين تظهرالحل
Long MethodAndroid/iOSExtract Method، التقسيم
Large ClassActivity، ViewControllerMVVM، VIPER، Clean Arch
Duplicate Codeأي شاشةمكون مشترك، DRY
Feature EnvyViewModel، PresenterMove Method
Leaking ContextAndroidمكونات Lifecycle-aware

كيفية العثور على Code Smell

مراجعة الكود هي الطريقة الأكثر موثوقية لاكتشاف الروائح. العين البشرية تلاحظ التركيبات غير الطبيعية التي تفوتها المحللات الآلية. تتحسن فعالية مراجعة الكود عندما يستخدم الفريق قائمة تحقق من الروائح النموذجية. يُنصح بمراجعة ما لا يزيد عن 200–400 سطر كود في الجلسة الواحدة — بعد هذا الحد ينخفض الانتباه وتبدأ الروائح في التسلل.

التحليل الثابت يؤتمت البحث عن الروائح الهيكلية. لنظام Android، الأدوات القياسية هي Detekt (Kotlin) و Android Lint؛ لنظام iOS، SwiftLint و SonarQube. تجد هذه الأدوات الطرق الطويلة والأصناف الكبيرة والكود المكرر والعديد من المشاكل الأخرى. من المهم ضبط القواعد حسب المشروع — الإعدادات الافتراضية غالباً ما تكون صارمة جداً أو على العكس تغفل روائح حرجة.

مقاييس الكود توفر معايير موضوعية: التعقيد الدوري (الحد >10 يتطلب انتباهاً)، أسطر الكود لكل طريقة (الحد >30)، عمق الوراثة (>3 — سبب للتفكير). أدوات مثل CodeMetrics (Xcode) و Gradle Metrics Plugin تبني رسوماً بيانية لتغير المقاييس مع الوقت. إذا نما تعقيد طريقة من 5 إلى 15 بعد آخر commit — فهذه إشارة لإعادة الهيكلة.

kotlin
// مثال: طريقة بتعقيد دوري = 7 (فوق الحد 5)
fun processOrder(order: Order) {
    if (order.status == Status.NEW) { /* 10 أسطر */ }
    else if (order.status == Status.PAID) { /* 15 سطراً */ }
    else if (order.status == Status.SHIPPED) { /* 20 سطراً */ }
    else if (order.status == Status.DELIVERED) { /* 8 أسطر */ }
    else if (order.status == Status.CANCELLED) { /* 5 أسطر */ }
    else { throw IllegalStateException() }
}

// الحل: تعدد الأشكال بدلاً من switch
interface OrderHandler {
    fun handle(order: Order)
}

الكشف الآلي عن الروائح لا يغني عن مراجعة الكود: المحللات الثابتة تجد فقط المشاكل الهيكلية لكنها لا تلتقط الروائح الدلالية (Feature Envy، Inappropriate Intimacy). مزيج الأدوات الآلية والمراجعة البشرية يعطي أفضل النتائج. هيئ خط أنابيب CI/CD بحيث يفشل البناء عند تجاوز حدود التعقيد أو طول الطريقة.

كيفية إصلاح Code Smell

إعادة الهيكلة هي الطريقة الأساسية للتخلص من روائح الكود. يصف فاولر عشرات تقنيات إعادة الهيكلة، كل منها ينطبق على رائحة معينة. Extract Method — للطرق الطويلة، Extract Class — للأصناف الكبيرة، Move Method — لـ Feature Envy. من المهم تنفيذ إعادة الهيكلة بخطوات صغيرة مع الحفاظ على عمل الكود بعد كل تغيير.

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

التدرج هو مفتاح النجاح في إصلاح الروائح في التطوير المحمول. لا تحاول إعادة كتابة God Activity بالكامل. استخرج أولاً طبقة التنقل، ثم طبقة البيانات، ثم منطق العرض. كل خطوة يصاحبها commit وتشغيل اختبارات. استخدم مفاتيح الميزات لتفعيل إعادة الهيكلة لجزء من المستخدمين والتراجع عند ظهور مشاكل.

  • Extract Method — تقسيم طريقة طويلة إلى عدة طرق قصيرة بأسماء واضحة
  • Extract Class — استخراج مجموعة ذات صلة من الحقول والطرق إلى صنف منفصل
  • Replace Conditional with Polymorphism — استبدال switch بتسلسل هرمي للأصناف
  • Introduce Parameter Object — دمج مجموعة من المعاملات في كائن واحد
  • Replace Inheritance with Delegation — استبدال extends بالتركيب

أدوات بيئة التطوير تؤتمت العديد من تقنيات إعادة الهيكلة. Android Studio و IntelliJ IDEA تقدم إعادة هيكلة مدمجة: Extract Method، Extract Interface، Pull Members Up، Encapsulate Fields. Xcode (ابتداءً من الإصدار 14) حسّن دعم إعادة الهيكلة لـ Swift. استخدام إعادة الهيكلة الآلية يقلل من خطر الأخطاء مقارنة بنسخ الكود يدوياً.

Code Smell في التطوير المحمول

التطوير المحمول يضيف روائحه الخاصة المرتبطة بقيود المنصة. في Android، تشمل تسرب Context، وعدم إغلاق Cursor، واستخدام غير صحيح لدورة الحياة. في iOS، دورات الاحتفاظ عبر closures، والتعامل غير الصحيح مع Auto Layout، و ViewControllers العملاقة. هذه الروائح لا تؤثر فقط على قابلية الصيانة بل تؤثر مباشرة على أداء وثبات التطبيق.

Callback Hell — رائحة مميزة للكود الذي يعمل مع العمليات غير المتزامنة. الاستدعاءات المتداخلة تجعل الكود غير قابل للقراءة وصعب التصحيح. الحل: coroutines (Kotlin)، async/await (Swift 5.5+)، RxJava/RxSwift أو Combine. وفقاً لـ Google I/O 2023، المشاريع التي انتقلت من نمط الاستدعاءات إلى coroutines خفضت عدد الأخطاء بنسبة 30% وسرعت إضافة الميزات الجديدة.

Platform Coupling — ارتباط وثيق لمنطق الأعمال بمكونات المنصة. اختبار مثل هذا المنطق يتطلب تشغيل محاكي مما يبطئ دورة التغذية الراجعة. الحل: Clean Architecture تفصل الكود إلى طبقات Domain (Kotlin/Swift نقي بدون تبعيات منصة) و Data/UI (مع تبعيات منصة). يتم اختبار منطق الأعمال على JVM بدون محاكي.

الأسئلة الشائعة

هل Code Smell هو نفس الشيء مثل الخطأ؟

لا — Code Smell ليس خطأ. الكود ذو الرائحة يعمل بشكل صحيح، لكن من الصعب صيانته وتعديله واختباره. الخطأ هو سلوك غير صحيح؛ الرائحة هي تحذير من مشاكل محتملة في المستقبل.

كم رائحة حددها مارتن فاولر؟

22 رائحة في الطبعة الثانية من كتاب «Refactoring» (2019). من بينها Long Method، Large Class، Primitive Obsession، Data Clumps، Switch Statements، Speculative Generality وغيرها. أضاف المجتمع عشرات الروائح الجديدة للنماذج والمنصات الحديثة.

ما هي أفضل أداة للعثور على Code Smell؟

مزيج يعطي أفضل نتيجة: Detekt (Android/Kotlin)، SwiftLint (iOS)، SonarQube (كلاهما) للتحليل الآلي ومراجعة الكود للروائح الدلالية. لا توجد أداة واحدة تجد 100% من المشاكل — الخبرة البشرية تبقى حاسمة.

هل يمكن تجاهل Code Smell؟

نعم، إذا كان الكود يتغير نادراً أو ستتم إعادة كتابته بالكامل قريباً. لكن تراكم الروائح يتحول إلى دين تقني: كل تغيير جديد يصبح أصعب، وتكلفة الإصلاح تنمو بشكل هائل.

هل هناك روائح خاصة بـ SwiftUI و Jetpack Compose؟

نعم — الأطر التصريحية ولدت روائح جديدة: كتل @State عملاقة، معالجة غير صحيحة لإعادة التصيير، إعادة تركيب مفرطة، وعدم استخراج إلى Views منفصلة. لـ SwiftUI، الرائحة النموذجية هي Massive View بعشرات متغيرات @State.

الخلاصة

  • Code Smell — مؤشر سطحي لمشكلة عميقة في الكود، ليس خطأ لكنه يقلل قابلية الصيانة
  • Long Method و Large Class — أكثر الروائح شيوعاً في التطوير المحمول، تتطلب Extract Method و Extract Class
  • Duplicate Code — منطق مكرر يضاعف العمل مع كل تغيير
  • Feature Envy و Switch Statements — علامات توزيع غير صحيح للمسؤوليات بين الأصناف
  • روائح محددة — God Activity، Giant ViewController، Leaking Context — فريدة للمنصات المحمولة
  • إعادة الهيكلة بدون اختبارات خطيرة: أولاً اختبارات التوصيف، ثم خطوات صغيرة مع commits
  • التحليل الثابت (Detekt، SwiftLint) يؤتمت الكشف لكنه لا يغني عن مراجعة الكود

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا