CQRS و Event Sourcing في Swift: بنية معمارية للمشاريع المعقدة

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

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

ابدأ الدورة

لماذا لا تتعامل البنية التقليدية مع المهام الحديثة؟

\n\n

هل سبق لك أن واجهت موقفًا حيث تتحول إضافة ميزة بسيطة إلى تطبيق Swift إلى كابوس؟ تظهر الأخطاء، وتُفقد البيانات، وينمو المنطق إلى أبعاد لا تُصدق؟ هل هذا مألوف؟ مرحبًا بك في عالم يصبح فيه CQRS و Event Sourcing أفضل أصدقائك.

\n\n

هذه الأنماط ليست مجرد كلمات رنانة. إنها طريقة تفكير تغير جذريًا نهج بناء التطبيقات في Swift. واليوم سنقوم بتحليلها بأمثلة حقيقية. بدون حشو، بدون نظريات معقدة - فقط ممارسة.

\n\n

ما هو CQRS؟ فرق تسد

\n\n

CQRS (Command Query Responsibility Segregation) هو مبدأ يقول: "كفى خلطًا بين القراءة والكتابة في نفس الفئة". يبدو الأمر بسيطًا، لكن العواقب هائلة.

\n\n

في البنية التقليدية CRUD (إنشاء، قراءة، تحديث، حذف)، تستخدم نموذجًا واحدًا لكل شيء. على سبيل المثال، User. يتم حفظه وقراءته وتحديثه. ماذا لو كانت القراءة تحتاج إلى حقول مختلفة عن الكتابة؟ تبدأ الحلول المؤقتة: الحقول الاختيارية، الأعلام، التعيينات...

\n\n

يقترح CQRS فصل المسؤوليات:

\n
    \n
  • الأوامر (Commands) — تغير الحالة. إنها تحوّر البيانات، لكنها لا تُرجع شيئًا.
  • \n
  • الاستعلامات (Queries) — تقرأ البيانات. إنها لا تغير الحالة، فقط تُرجع النتيجة.
  • \n
\n\n

في Swift قد يبدو هذا كالتالي:

\n\n
// أمر — تحوير فقط\nstruct CreateUserCommand {\n    let id: UUID\n    let name: String\n    let email: String\n}\n\n// استعلام — قراءة فقط\nstruct GetUserQuery {\n    let userId: UUID\n}\n\n// معالج الأمر\nclass CreateUserCommandHandler {\n    func handle(_ command: CreateUserCommand) {\n        // منطق إنشاء المستخدم\n        print("تم إنشاء المستخدم: \\(command.name)")\n    }\n}\n\n// معالج الاستعلام\nclass GetUserQueryHandler {\n    func handle(_ query: GetUserQuery) -> User? {\n        // منطق الحصول على المستخدم\n        return User(id: query.userId, name: "أليكسي", email: "alex@example.com")\n    }\n}
\n\n

هل ترى؟ لا خلط. كل فئة تقوم بشيء واحد بالضبط. هذا يبسط الاختبار والصيانة والتوسع.

\n\n

Event Sourcing: نخزن التاريخ، وليس الحالة

\n\n

الآن ننتقل إلى Event Sourcing — النمط الذي لا يخزن الحالة الحالية للكائن، بل يخزن التسلسل الكامل للأحداث التي أدت إليها.

\n\n

تخيل حسابًا بنكيًا. بدلاً من تخزين الرصيد (1000 روبل)، تخزن قائمة الأحداث: "فتح الحساب"، "إيداع 500"، "سحب 200"، "إيداع 700". لمعرفة الرصيد الحالي، تقوم ببساطة بإعادة تشغيل جميع الأحداث. هذا يوفر إمكانيات لا تصدق: التدقيق، التراجع عن التغييرات، التحليلات.

\n\n

لننفذ هذا في Swift:

\n\n
// حدث\nprotocol Event {}\n\nstruct AccountCreated: Event {\n    let accountId: UUID\n    let initialBalance: Double\n}\n\nstruct MoneyDeposited: Event {\n    let accountId: UUID\n    let amount: Double\n}\n\nstruct MoneyWithdrawn: Event {\n    let accountId: UUID\n    let amount: Double\n}\n\n// المُجمّع — يستعيد الحالة من الأحداث\nclass BankAccount {\n    private(set) var balance: Double = 0\n    private(set) var isActive: Bool = false\n    private(set) var accountId: UUID?\n\n    func apply(_ event: Event) {\n        switch event {\n        case let created as AccountCreated:\n            accountId = created.accountId\n            balance = created.initialBalance\n            isActive = true\n        case let deposited as MoneyDeposited:\n            balance += deposited.amount\n        case let withdrawn as MoneyWithdrawn:\n            balance -= withdrawn.amount\n        default:\n            break\n        }\n    }\n\n    // استعادة من تاريخ الأحداث\n    static func load(from history: [Event]) -> BankAccount {\n        l                

المدونات

توصيات الكتب