كيف لا تغرق في السباغيتي: العمارة السداسية في C#

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

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

ابدأ الدورة

عندما يتحول المشروع إلى فوضى

\n

هل سبق لك أن فتحت مشروع C# كتبته قبل عام، وأدركت برعب أن لا شيء يمكن تغييره دون خطر كسر كل شيء؟ منطق الأعمال متشابك بإحكام مع Entity Framework، وحدات تحكم ASP.NET تخزن أسرار قاعدة البيانات، واختبارات الوحدة تتحول إلى تكامل جهنمي مع قاعدة بيانات حقيقية. هل هذا مألوف؟

\n

هذا عرض كلاسيكي لغياب العمارة. الخبر السار: هناك وصفة مجربة - العمارة السداسية (المعروفة أيضًا باسم Ports & Adapters). هذا النمط، الذي ابتكره أليستر كوكبيرن، ليس مجرد مصطلح عصري. إنه خلاص للمشاريع المتوسطة والكبيرة على C#. دعنا نفهم كيف يعمل، ونكتب الكود فورًا.

\n\n

جوهر العمارة السداسية: النواة والمحيط

\n

تخيل شكلًا سداسيًا (hexagon). في المركز - تطبيقك مع منطق أعمال نقي، مكتوب بلغة C# خالصة بدون تبعيات خارجية. على الحواف - المنافذ (واجهات)، التي تتواصل من خلالها النواة مع العالم الخارجي. المحولات (Adapters) هي التطبيقات الملموسة: وحدات تحكم ASP.NET، مستودعات EF Core، عملاء RabbitMQ.

\n

القاعدة الرئيسية: النواة لا تعرف شيئًا عن العالم الخارجي. إنها تعرف فقط منافذها. هذا يسمح بتغيير قاعدة البيانات، واجهة المستخدم، أو قوائم الرسائل دون تغيير منطق الأعمال.

\n\n

لماذا هذا مهم لمطور C#؟

\n
    \n
  • قابلية الاختبار: يمكن اختبار منطق الأعمال بدون قاعدة بيانات، HTTP، أو نظام ملفات.
  • \n
  • المرونة: هل تريد استبدال PostgreSQL بـ MongoDB؟ فقط غير المحول.
  • \n
  • قابلية القراءة: يصبح الكود أشبه بمواصفات المتطلبات، وليس كتلة من التبعيات.
  • \n
  • الالتزام بـ SOLID: خاصة مبدأ عكس التبعيات (Dependency Inversion).
  • \n
\n\n

هيكل المشروع في C#

\n

في العمارة السداسية، عادةً ما يتم تمييز ثلاث طبقات رئيسية. بالنسبة لـ C#، من المناسب تنظيمها كمشاريع منفصلة في حل واحد:

\n\n
MyApp.sln\n├── MyApp.Domain          // النواة: الكيانات، value objects، المنافذ (واجهات)\n├── MyApp.Application     // حالات الاستخدام (خدمات التطبيق)\n├── MyApp.Infrastructure  // المحولات: EF Core، واجهات برمجية خارجية، تسجيل\n└── MyApp.Api             // محول الدخول: ASP.NET Controllers / Minimal API\n
\n\n

لاحظ: Domain و Application هما مكتبات فصول نقية بدون مراجع لـ Microsoft.AspNetCore أو EntityFramework. فقط System و System.Threading.Tasks.

\n\n

نكتب الكود: مثال واقعي

\n

لنفترض أننا نبني نظام طلبات. نحتاج إلى إنشاء طلب وحفظه.

\n\n

الخطوة 1. النواة (Domain)

\n

هنا تعيش الكيانات والمنافذ - الواجهات التي تحدد كيف تتواصل النواة مع العالم.

\n\n
// MyApp.Domain/Entities/Order.cs\npublic class Order\n{\n    public Guid Id { get; private set; }\n    public string CustomerName { get; private set; }\n    public decimal TotalAmount { get; private set; }\n    public DateTime CreatedAt { get; private set; }\n\n    public Order(string customerName, decimal totalAmount)\n    {\n        Id = Guid.NewGuid();\n        CustomerName = customerName;\n        TotalAmount = totalAmount;\n        CreatedAt = DateTime.UtcNow;\n    }\n}\n\n// MyApp.Domain/Ports/IOrderRepository.cs (منفذ خروج)\npublic interface IOrderRepository\n{\n    Task<Order> GetByIdAsync(Guid id);\n    Task AddAsync(Order order);\n}\n\n// MyApp.Domain/Ports/IOrderNotifier.cs (منفذ خروج - إشعارات)\npublic interface IOrderNotifier\n{\n    Task NotifyOrderCreatedAsync(Order order);\n}\n
\n\n

لاحظ: IOrderRepository و IOrderNotifier هما منافذ. النواة تحدد ماذا تريد، ولكن ليس كيف يتم تنفيذه.

\n\n

الخطوة 2. حالات الاستخدام

المدونات

توصيات الكتب