الهندسة السداسية في Swift: منطق نقي بدون تبعيات

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

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

ابدأ الدورة

عندما تتوقف MVVM و MVC عن الإنقاذ، وتتحول الاختبارات إلى جحيم



هل سبق لك أن كتبت تطبيقًا بلغة Swift، وبعد ستة أشهر كان إضافة ميزة واحدة يكسر ثلاث ميزات أخرى، وكان عليك إعادة كتابة الاختبارات بالكامل لأن قاعدة البيانات تغيرت من Core Data إلى Realm؟ إذا كانت الإجابة بنعم، فأنت لست وحدك. الهندسات المعمارية الطبقية التقليدية (MVC, MVVM) تعمل بشكل رائع في البداية، لكنها تتحول إلى "فوضى" مع نمو المشروع.



سأريكم الهندسة السداسية (المعروفة أيضًا باسم Ports & Adapters) - وهو نهج جاء من عالم Java و DDD، ولكنه يتناسب تمامًا مع Swift. سنقوم بتحليلها بأمثلة حقيقية، بدون "User" و "Manager" المجردين. سترى كيف تفصل منطق الأعمال عن قاعدة البيانات، واجهة المستخدم، والشبكة بحيث يمكن تغييرها دون لمس نواة التطبيق.



هذه ليست نظرية أخرى - إنها ممارسة يمكنك تطبيقها في مشروعك اليوم.



ما هي الهندسة السداسية؟ بكلمات بسيطة



تخيل شكلًا سداسيًا (ومن هنا جاء الاسم). في المنتصف - منطق أعمالك النقي (المجال). على الحواف - المنافذ (الواجهات) التي يتواصل من خلالها العالم الخارجي مع النواة. المحولات هي تطبيقات محددة: قاعدة البيانات، API، واجهة المستخدم، نظام الملفات.



القاعدة الأساسية: النواة لا تعرف شيئًا عن العالم الخارجي. لا عن UIKit، ولا عن URLSession، ولا عن Core Data. إنها تعرف فقط واجهاتها (المنافذ).



مثال من الحياة الواقعية: تخيل متجرًا إلكترونيًا. النواة تعرف أن هناك "سلة تسوق" و "إتمام الطلب". لا يهمها من أين تأتي البيانات - من WebSocket، من JSON محلي، أو من لوحة المفاتيح. تتصل المحولات بالمنافذ وتترجم الإشارات الخارجية إلى أوامر مجال.



لماذا يجب استخدام هذا في مشاريع Swift؟



  • قابلية الاختبار - تختبر المجال بدون قاعدة بيانات حقيقية أو شبكة. فقط تستبدل المحولات بـ mocks.
  • المرونة - أردت الانتقال من Firebase إلى خادمك الخاص؟ تغير محولًا واحدًا، وليس نصف التطبيق.
  • قابلية القراءة - منطق الأعمال غير مبعثر عبر ViewControllers. إنه موجود في مكان واحد.
  • الاستقلال عن الأطر - نواتك لا تستورد UIKit أو Combine أو Alamofire.


هيكل المشروع على الهندسة السداسية في Swift



دعنا ننتقل مباشرة إلى الكود. لنفترض أننا نكتب تطبيقًا لإدارة المهام (Todolist). إليك كيف سيكون شكل هيكل المجلدات:



App/├── Domain/│   ├── Entity/│   │   └── Task.swift│   ├── UseCase/│   │   └── CreateTaskUseCase.swift│   └── Port/│       ├── TaskRepository.swift│       └── TaskOutputPort.swift├── Adapter/│   ├── Persistence/│   │   └── CoreDataTaskRepository.swift│   ├── Network/│   │   └── APITaskRepository.swift│   └── Presentation/│       └── TaskListViewModel.swift└── Main/    └── AppDelegate.swift


لاحظ: Domain لا يستورد أي شيء باستثناء Foundation. Adapter يمكنه استيراد CoreData، UIKit، Alamofire - أي شيء.



الخطوة 1: كيانات المجال والمنافذ



لنبدأ بالأهم - نموذج المجال. هذا هو struct أو enum يصف كيان الأعمال. لا NSManagedObject، لا Codable.



// Domain/Entity/Task.swiftstruct Task {    let id: UUID    var title: String    var isCompleted: Bool    let createdAt: Date}


الآن نحدد منفذ المستودع (منفذ الإخراج). هذا بروتوكول يصف كيف نحفظ ونحمل المهام.



// Domain/Port/TaskRepository.swiftprotocol TaskRepository {    func fetchAll() async throws -> [Task]    func save(task: Task) async throws    func delete(taskID: UUID) async throws}


و منفذ الإدخال - وهو ما يتفاعل من خلاله العالم الخارجي (UI، API) مع النواة. عادةً ما يكون UseCase.



// Domain/Us                

المدونات

توصيات الكتب