إعادة هيكلة الكود القديم بلغة Swift: من الألف إلى الياء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

إعادة هيكلة الكود القديم بلغة Swift: من الألف إلى الياء

\n

العمل مع الكود القديم (legacy code) هو جزء لا مفر منه في حياة مطور iOS/macOS. غالبًا ما يكون هذا الكود مكتوبًا بإصدارات قديمة من Swift أو حتى Objective-C، خاليًا من الاختبارات، مع "أرقام سحرية" و UIViewController ضخمة. في هذه المقالة، سنقوم بتحليل استراتيجية خطوة بخطوة لإعادة هيكلة هذا الكود، وتحويله إلى مشروع حديث، قابل للصيانة والاختبار.

\n\n

1. التحضير والأمان: قبل لمس الكود

\n

أهم قاعدة في إعادة الهيكلة: لا تكسر ما يعمل. بدون اختبارات، أي تغيير هو قفزة في المجهول.

\n
    \n
  • تغطية بالاختبارات (Characterization Tests): اكتب اختبارات تثبت السلوك الحالي. حتى لو بدا الكود خاطئًا، قم أولاً بتوثيق عمله.
  • \n
  • نظام التحكم بالإصدارات: قم بعمل commit للحالة الحالية. استخدم feature branch.
  • \n
  • الأدوات: Xcode مع Edit > Refactor (Rename, Extract Method)، بالإضافة إلى أدوات التحليل (SwiftLint) لضمان نمط موحد.
  • \n
\n\n
// مثال "تجميد" السلوك لطريقة قديمة\nclass LegacyCalculator {\n    func calculateTotal(items: [Int]) -> Int {\n        // منطق قديم غير قابل للقراءة\n        var result = 0\n        for i in items {\n            result += i * 2\n        }\n        return result + 10\n    }\n}\n\n// اختبار يثبت السلوك\nfunc testCalculateTotal() {\n    let sut = LegacyCalculator()\n    let result = sut.calculateTotal(items: [1, 2, 3])\n    XCTAssertEqual(result, 22) // (1+2+3)*2 + 10 = 22\n}\n
\n\n

2. استراتيجية "كبش الفداء": المتغيرات العامة و Singleton

\n

يشتهر الكود القديم بحالاته العامة و Singleton. هذا يجعل الكود مقترنًا بشدة وغير قابل للتنبؤ.

\n

المشكلة:

\n
class NetworkManager {\n    static let shared = NetworkManager()\n    var baseURL: String = "http://old.api.com"\n    func fetchData() { ... }\n}\n
\n

الحل: حقن التبعيات (Dependency Injection). نقوم بإنشاء بروتوكول وتمرير التبعيات عبر المُهيئ.

\n
protocol NetworkService {\n    func fetchData()\n}\n\nclass ModernViewModel {\n    private let network: NetworkService\n    \n    init(network: NetworkService) {\n        self.network = network\n    }\n    \n    func load() {\n        network.fetchData()\n    }\n}\n
\n

هذا النهج يسمح بتبديل الخدمات بسهولة في الاختبارات ويجعل الكود معياريًا.

\n\n

3. مكافحة "وحدة التحكم الضخمة" (Massive View Controller)

\n

كلاسيكيات iOS القديمة: UIViewController الذي يتحمل كل شيء - من طلبات الشبكة إلى تنسيق واجهة المستخدم. تتم إعادة الهيكلة من خلال فصل المسؤوليات (SRP).

\n\n

الخطوة 1: افصل منطق الأعمال في نموذج منفصل (ViewModel).

\n
// كان في وحدة التحكم\nfunc buttonTapped() {\n    let data = fetchData()\n    let total = data.reduce(0, +)\n    label.text = "المجموع: \\(total)"\n}\n\n// أصبح: ViewModel\nclass MyViewModel {\n    func calculateTotal(data: [Int]) -> String {\n        let total = data.reduce(0, +)\n        return "المجموع: \\(total)"\n    }\n}\n
\n\n

الخطوة 2: انقل إعداد واجهة المستخدم إلى طرق أو مصانع منفصلة.

\n
    \n
  • أنشئ فئة ViewBuilder للتسلسلات الهرمية المعقدة.
  • \n
  • استخدم UICollectionViewDiffableDataSource بدلاً من dataSource القديم.
  • \n
\n\n

4. التحديث: من Objective-C إلى Swift وواجهات برمجة التطبيقات الجديدة

\n

غالبًا ما يحتوي الكود القديم على مزيج من Objective-C و Swift. عند إعادة الهيكلة، من المهم تحديث الهياكل القديمة:

\n\n
    \n
  • استبدال NSError بـ throws: يستخدم Swift الحديث الاستثناءات لمعالجة الأخطاء.
  • \n
  • التخلي عن ! (

المدونات

توصيات الكتب