مقدمة: لماذا مشروع Go الخاص بك يحتاج إلى DDD؟
\n\nهل سبق لك أن كتبت خدمة بلغة Go بدأت ببضع نقاط نهاية وثلاثة جداول في قاعدة البيانات، وبعد ستة أشهر تحولت إلى وحش بملفات handler.go بطول كيلومترات وأرقام سحرية متناثرة في جميع أنحاء الكود؟ مألوف. لقد مررت بهذا أيضاً.
مشكلة التطوير الكلاسيكي بلغة Go هي أننا نفكر مبكراً جداً في قواعد البيانات و JSON، متناسين الشيء الرئيسي: منطق الأعمال. يأتي التصميم القائم على المجال (DDD) للمساعدة تحديداً عندما تريد إحلال النظام في الفوضى. ولكن كيف نطبق DDD على Go، إذا كانت اللغة لا تمنحنا الفئات والوراثة؟ دعنا نكتشف ذلك.
\n\nفي هذه المقالة، سأريكم كيفية تطبيق التصميم القائم على المجال في مشاريع Go بدون تعصب مفرط، مع أمثلة كود عملية وهيكل واضح. ستتعلم كيفية فصل القمح عن التبن وجعل الكود مفهوماً ليس فقط للآلة ولكن أيضاً لمحلل الأعمال.
\n\nما هو DDD ولماذا هو ضروري لمطور Go؟
\n\nالتصميم القائم على المجال ليس عن التقنيات. إنه عن اللغة. عن جعل الكود يتحدث لغة الأعمال. إذا كان مجال عملك هو متجر إلكتروني، فيجب أن يكون في الكود Order و Product و Cart، وليس DataTransferObject و EntityManager.
Go، ببساطته وغياب السحر، مثالي لـ DDD. لا توجد هنا فئات وكيل أو انعكاس يخفي الجوهر. في Go، أنت مضطر لأن تكون صادقاً: إذا كان لديك تجميع، فهو هيكل واضح، وإذا كان لديك مستودع، فهو واجهة.
\n\nاللبنات الأساسية لـ DDD التي سننظر فيها:
\n- \n
- Entity (كيان) — كائن بمعرف فريد (مثل
User). \n - Value Object (كائن القيمة) — كائن غير قابل للتغيير يصف الخصائص (مثل
Address). \n - Aggregate (تجميع) — مجموعة من الكيانات تضمن الاتساق (مثل
OrderمعOrderItem). \n - Repository (مستودع) — مجموعة من الكائنات تخفي تفاصيل التخزين. \n
- Domain Service (خدمة المجال) — عملية لا تتناسب مع كيان واحد. \n
الآن دعنا نترجم هذا إلى Go.
\n\nهيكل المشروع: كيف لا تضيع في المجلدات
\n\nالخبر الجيد: Go لا يفرض أي هيكل. الخبر السيئ: بدون هيكل ستغرق بسرعة. لـ DDD في Go أوصي بتنظيم الكود التالي:
\n\nyour-project/\n├── cmd/\n│ └── server/\n│ └── main.go\n├── internal/\n│ ├── domain/ # النواة النقية: الكيانات، القواعد\n│ │ ├── order.go\n│ │ ├── product.go\n│ │ └── errors.go\n│ ├── application/ # حالات الاستخدام / خدمات التطبيق\n│ │ ├── order_service.go\n│ │ └── product_service.go\n│ └── infrastructure/ # قواعد البيانات، واجهات برمجة التطبيقات الخارجية، معالجات HTTP\n│ ├── postgres/\n│ │ └── order_repository.go\n│ └── http/\n│ └── handler.go\n└── go.mod\n\nلاحظ: domain لا يستورد infrastructure. هذه هي القاعدة الذهبية لـ DDD — المجال لا يعرف شيئاً عن قواعد البيانات و HTTP. إنه يعيش في فراغ من الهياكل والواجهات النقية.
كتابة المجال: Order و Value Objects
\n\nلنبدأ بالنواة. لنفترض أننا نبني نظام إدارة طلبات. إليك كيف قد يبدو كيان Order:
// internal/domain/order.go\npackage domain\n\nimport (\n "errors"\n "time"\n)\n\ntype OrderStatus string\n\nconst (\n OrderStatusPending OrderStatus = "pending"\n OrderStatusConfirmed OrderStatus = "confirmed"\n OrderStatusCancelled OrderStatus = "cancelled"\n)\n\ntype OrderID string\n\ntype Order struct {\n ID OrderID\n CustomerID string\n Items []OrderItem\n Status OrderStatus\n CreatedAt time.Time\n Upd