مقدمة: لماذا إعادة هيكلة الكود القديم بلغة Swift ضرورة
كل مطور iOS/macOS يواجه عاجلاً أم آجلاً كودًا قديمًا. قد يكون هذا مشروعًا مكتوبًا بلغة Objective-C ومترجمًا جزئيًا إلى Swift، أو تطبيقًا تم إنشاؤه في عصر Swift 2.0 باستخدام Massive View Controller. غالبًا ما يعمل هذا الكود، لكن صيانته تتحول إلى كابوس: أي تغيير يتطلب ساعات من الاختبار، وإضافة ميزة جديدة تكسر الميزات القديمة.
إعادة هيكلة الكود القديم بلغة Swift ليست مجرد "تمشيط" للكود. إنها عملية استراتيجية تجعل التطبيق أكثر قابلية للاختبار والتوسع والأداء. في هذه المقالة، سنشرح كيفية التعامل مع إعادة الهيكلة بشكل صحيح، مع أمثلة بلغة Swift، لضمان عدم كسر الإنتاج والحصول على نتيجة فعالة.
1. التشخيص: كيف تعرف أن الكود القديم يحتاج إلى إعادة هيكلة
قبل تغيير الكود، يجب فهم ما يحتاج إلى تعديل. العلامات الرئيسية للكود القديم بلغة Swift:
- Massive View Controller (النمط المعاكس MVC) — ملفات تحتوي على 500+ سطر، حيث يتم خلط المنطق وواجهة المستخدم وطلبات الشبكة في فئة واحدة.
- الاقتران القوي (tight coupling) — الفئات تعتمد بشكل مباشر على بعضها البعض، ولا توجد بروتوكولات أو حقن تبعيات.
- غياب الاختبارات — إذا كنت تخشى تغيير سطر من الكود لأنك لا تعرف ما سينكسر.
- المتغيرات العامة والأنماط المفردة (singletons) — استخدام
UserDefaults.standardأوNotificationCenter.defaultفي جميع أنحاء المشروع. - Force unwrapping — الاستخدام المفرط لـ
!بدلاً من الاستخراج الآمن للقيم الاختيارية.
1.1. أدوات تحليل الكود القديم بلغة Swift
لتقييم حالة الكود بشكل موضوعي، استخدم الأدوات التالية:
- SwiftLint — محلل ثابت يكشف انتهاكات أسلوب الكود.
- Xcode Instruments — للبحث عن تسرب الذاكرة ومشاكل الأداء.
- Code coverage — يوضح مقدار الكود المغطى بالاختبارات (عادة 0-10% في المشاريع القديمة).
مثال على كود قديم نموذجي يحتاج إلى إعادة هيكلة:
class LegacyViewController: UIViewController { @IBOutlet weak var label: UILabel! var data: [String] = [] override func viewDidLoad() { super.viewDidLoad() // خليط من المنطق وواجهة المستخدم let url = URL(string: "https://api.example.com/data")! let data = try! Data(contentsOf: url) let json = try! JSONSerialization.jsonObject(with: data) as! [[String: Any]] for item in json { data.append(item["name"] as! String) } label.text = data.first }}هنا عدة مشاكل: force unwrapping، طلب شبكة متزامن في الخيط الرئيسي، خليط من المنطق والعرض.
2. استراتيجية إعادة هيكلة الكود القديم بلغة Swift: خطة خطوة بخطوة
إعادة الهيكلة بدون استراتيجية هي طريق نحو الكارثة. استخدم نهج "خبير إزالة الألغام": أولاً قم بتأمين المنطقة، ثم غير الكود.
2.1. الخطوة 1: إنشاء "شبكة حماية" من الاختبارات
قبل تغيير أي شيء، اكتب اختبارات للكود الموجود. استخدم Characterization Tests — اختبارات تثبت السلوك الحالي للنظام. حتى لو كان الكود يبدو فظيعًا، ستظهر الاختبارات أنك لم تكسر المنطق.
import XCTest@testable import LegacyApp
class LegacyViewControllerTests: XCTestCase { func testViewDidLoad_SetsLabelText() { let sut = LegacyViewController() sut.loadViewIfNeeded() // نتحقق من أن label ليس nil ويحتوي على نص XCTAssertNotNil(sut.label.text) }}قد لا يكون هذا الاختبار مثاليًا، لكنه سيثبت الحالة الحالية. بعد إعادة الهيكلة، يجب أن ينجح الاختبار.