Clean Code في Swift: المبادئ والأمثلة العملية
\n\nالكود النظيف (Clean Code) ليس مجرد مصطلح عصري، بل هو مهارة أساسية للمطور المحترف. في نظام Swift البيئي (iOS/macOS)، تؤثر جودة الكود بشكل مباشر على سرعة التطوير، وعدد الأخطاء، وسهولة صيانة المشروع. في هذه المقالة، سنستعرض المبادئ الأساسية لـ Clean Code فيما يتعلق بـ Swift ونعرض تطبيقها بأمثلة عملية.
\n\n1. التسمية: تحدث بلغة مجال الموضوع
\n\nالاسم الجيد للمتغير أو الدالة أو الفئة يغني عن التعليقات. في Swift، مع نظام الأنواع الغني والقيم الاختيارية، يصبح التسمية الصحيحة أكثر أهمية.
\n\nمثال سيء:
\nfunc calc(a: [String: Any]) -> Double {\n var x = 0.0\n for (_, v) in a {\n if let n = v as? Double {\n x += n\n }\n }\n return x\n}\n\nمثال جيد (Clean Code):
\nfunc calculateTotalPrice(of products: [Product]) -> Double {\n return products.reduce(0) { $0 + $1.price }\n}\n\nمبادئ التسمية في Swift:
\n- \n
- الوضوح أهم من الاختصار:
remove(at:)أفضل منrem(at:). \n - استخدم الأسماء للأنواع:
UserViewController،NetworkManager. \n - الأفعال للدوال:
fetchData()،saveToCache(). \n - المتغيرات المنطقية: ابدأ بـ
is،has،should—isEnabled،hasContent. \n - تجنب الاختصارات:
backgroundColorبدلاً منbgColor. \n
2. مبدأ المسؤولية الواحدة (SRP) في Swift
\n\nيجب أن يكون لكل فئة أو هيكل أو دالة سبب واحد فقط للتغيير. في تطوير iOS، ينطبق هذا بشكل خاص على ViewController التي غالبًا ما تتحول إلى "كائنات إلهية".
\n\nانتهاك SRP (ViewController نموذجي):
\nclass ProfileViewController: UIViewController {\n @IBOutlet weak var nameLabel: UILabel!\n @IBOutlet weak var avatarImageView: UIImageView!\n \n override func viewDidLoad() {\n super.viewDidLoad()\n // تحميل البيانات\n let url = URL(string: "https://api.example.com/user")!\n let data = try! Data(contentsOf: url)\n let json = try! JSONSerialization.jsonObject(with: data) as! [String: Any]\n nameLabel.text = json["name"] as? String\n \n // تحميل الصورة الرمزية\n let imageUrl = URL(string: json["avatar"] as! String)!\n let imageData = try! Data(contentsOf: imageUrl)\n avatarImageView.image = UIImage(data: imageData)\n \n // حفظ في الكاش\n UserDefaults.standard.set(json, forKey: "cachedUser")\n }\n}\n\nإعادة الهيكلة مع الالتزام بـ SRP:
\n// 1. خدمة منفصلة للتعامل مع الشبكة\nclass UserNetworkService {\n func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {\n // ... منطق الشبكة\n }\n}\n\n// 2. مدير كاش منفصل\nclass UserCacheManager {\n func saveUser(_ user: User) {\n // ... منطق التخزين المؤقت\n }\n}\n\n// 3. ViewModel للمنطق التجاري\nclass ProfileViewModel {\n private let networkService = UserNetworkService()\n private let cacheManager = UserCacheManager()\n \n func loadProfile(completion: @escaping (User) -> Void) {\n networkService.fetchUser { [weak self] result in\n switch result {\n case .success(let user):\n self?.cacheManager.saveUser(user)\n completion(user)\n case .failure:\n // تحميل من الكاش عند الخطأ\n if let cachedUser = self?.cacheManager.lo