التصميم القائم على المجال في Kotlin: كيف لا تغرق في تعقيد منطق الأعمال

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

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

ابدأ الدورة

لماذا DDD وKotlin زوج مثالي

عندما ينمو المشروع وتبدأ متطلبات الأعمال تشبه كتلة متشابكة، يتوقف نهج CRUD العادي عن العمل. تجد نفسك تفكر أن نصف الكود عبارة عن فحوصات لا نهائية if-else، وأي تغيير في المنطق يؤدي إلى تعديل عشرات الملفات. هل هذا مألوف؟

هنا يظهر التصميم القائم على المجال (DDD) - وهو نهج يضع منطق الأعمال في مركز الكون. وKotlin بتركيبته المختصرة، ونظام الأنواع القوي، ودعمه للمفاهيم الوظيفية يصبح أداة مثالية لتنفيذ DDD. في هذه المقالة، سنشرح كيفية الجمع بين هاتين القوتين لجعل كودك ليس مجرد كود يعمل، بل معبرًا ومرنًا.

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



التصميم القائم على المجال: مقدمة سريعة للمشغولين

قبل الغوص في الكود، دعونا نتفق على المصطلحات. DDD ليس إطار عمل ولا مكتبة. إنها مجموعة من المبادئ التي تساعد المطورين والأعمال على التحدث بلغة واحدة.

المفاهيم الرئيسية:

  • اللغة الموحدة (Ubiquitous Language) - يجب أن تتطابق المصطلحات في الكود مع المصطلحات التي يستخدمها محللو الأعمال والعملاء.
  • السياق المحدود (Bounded Context) - حدود واضحة يكون للنموذج معنى داخلها. على سبيل المثال، "العميل" في سياق المبيعات و"العميل" في سياق الدعم هما كيانان مختلفان.
  • الكيان (Entity) - كائن بمعرف فريد يتغير بمرور الوقت.
  • كائن القيمة (Value Object) - كائن غير قابل للتغيير يُعرف بخصائصه وليس بمعرفه.
  • التجميع (Aggregate) - مجموعة من الكائنات المرتبطة التي تُعتبر وحدة واحدة.
  • المستودع (Repository) - تجريد للوصول إلى البيانات يخفي تفاصيل التخزين.

يبدو هذا مجردًا؟ الآن سنترجمه إلى Kotlin.



كائنات القيمة في Kotlin: الأناقة والأمان

لنبدأ بالأكثر متعة - كائنات القيمة (VO). في Kotlin، تنفيذها متعة بفضل data class.

تخيل أننا نعمل في نظام حجز فنادق. لدينا مفهوم "فترة الإقامة". هذا ليس كيانًا - إنها مجرد مجموعة تواريخ. مرشح مثالي لكائن القيمة.

data class StayPeriod(    val checkIn: LocalDate,    val checkOut: LocalDate) {    init {        require(checkIn.isBefore(checkOut)) {            "يجب أن يكون تاريخ الوصول قبل تاريخ المغادرة"        }    }

val totalNights: Int get() = ChronoUnit.DAYS.between(checkIn, checkOut).toInt()

fun overlapsWith(other: StayPeriod): Boolean { return !(this.checkOut.isBefore(other.checkIn) || this.checkIn.isAfter(other.checkOut)) }}

لماذا هذا رائع؟

  • عدم القابلية للتغيير - جميع الحقول val. لا أحد يغير تاريخ الوصول عن طريق الخطأ.
  • التحقق المدمج - كتلة init تضمن إنشاء الكائن فقط في حالة صحيحة.
  • السلوك - طريقة overlapsWith تغلف قاعدة العمل. لا تبحث عن تداخل التواريخ في الخدمات، بل تسأل الكائن نفسه.

في DDD، نسمي هذا النموذج الغني - الكائن لا يخزن البيانات فقط، بل يعرف كيفية تنفيذ عمليات الأعمال.



الكيان: عندما تكون الهوية مهمة

الآن ننتقل إلى الكيان. على عكس كائن القيمة، الكيان يتغير وله هوية. في Kotlin، نستخدم فئة عادية، ولكن مع التركيز على المعرف.

مثال - حجز في فندق (Booking):

class Booking(    val id: BookingId,    val roomNumber: Ro                

المدونات

توصيات الكتب