مستودع أحادي مع Kotlin: تنظيم الكود عمليًا

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

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

ابدأ الدورة

مقدمة: لماذا المستودع الأحادي في Kotlin؟

\n

في التطوير الحديث باستخدام Kotlin، غالبًا ما تنشأ معضلة: هل يتم تخزين عدة مشاريع مترابطة (الخلفية، الخدمات المصغرة، المكتبات، تطبيقات Android) في مستودعات منفصلة (متعددة المستودعات) أم دمجها في مستودع أحادي واحد. المستودع الأحادي هو استراتيجية لتخزين الكود حيث توجد جميع المكونات في نظام تحكم إصدار واحد. بالنسبة لمشاريع Kotlin، هذا مهم بشكل خاص بفضل نظام البناء القوي Gradle والدعم المدمج للتعددية الوحداتية.

\n

في هذه المقالة، سنناقش الجوانب العملية لتنظيم المستودع الأحادي مع Kotlin: من هيكل الدلائل إلى إعداد CI/CD وإدارة التبعيات. ستتعلم كيفية تجنب الأخطاء الشائعة والحصول على أقصى استفادة من مستودع الكود الموحد.

\n\n

1. هيكل المستودع الأحادي: من النظرية إلى التطبيق

\n

الهيكل الصحيح هو أساس المستودع الأحادي الناجح. لنفكر في مشروع نموذجي يتضمن REST API على Ktor، مكتبة للعمل مع قاعدة البيانات وتطبيق Android. إليك التسلسل الهرمي الموصى به:

\n
my-monorepo/\n├── build.gradle.kts          # ملف البناء الجذري\n├── settings.gradle.kts       # إعداد الوحدات\n├── gradle.properties         # الخصائص المشتركة\n├── gradle/\n│   └── libs.versions.toml    # كتالوج الإصدارات (Version Catalog)\n├── libs/                     # المكتبات المشتركة\n│   ├── common-utils/         # الأدوات المساعدة، الامتدادات\n│   ├── common-db/            # العمل مع قاعدة البيانات (Exposed)\n│   └── common-dto/           # كائنات نقل البيانات\n├── services/                 # تطبيقات الخادم\n│   ├── user-service/         # خدمة المستخدمين المصغرة\n│   └── order-service/        # خدمة الطلبات المصغرة\n└── apps/                     # تطبيقات العميل\n    └── android-app/          # تطبيق Android\n
\n

العنصر الأساسي هو settings.gradle.kts. يتضمن جميع الوحدات:

\n
rootProject.name = "my-monorepo"\n\ninclude("libs:common-utils")\ninclude("libs:common-db")\ninclude("libs:common-dto")\ninclude("services:user-service")\ninclude("services:order-service")\ninclude("apps:android-app")\n
\n

يسمح هذا الهيكل بإعادة استخدام الكود بسهولة بين الخدمات والعميل، بالإضافة إلى إدارة إصدارات التبعيات بشكل مركزي.

\n\n

1.1. كتالوج الإصدارات: إدارة التبعيات

\n

في المستودع الأحادي، من المهم للغاية تجنب تكرار إصدارات المكتبات. استخدم كتالوج الإصدارات (ملف gradle/libs.versions.toml):

\n
[versions]\nkotlin = "2.0.21"\nktor = "3.0.3"\nexposed = "0.57.0"\n\n[libraries]\nktor-server-core = { module = "io.ktor:ktor-server-core", version.ref = "ktor" }\nexposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }\n\n[plugins]\nkotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }\n
\n

الآن في أي وحدة يمكنك كتابة:

\n
dependencies {\n    implementation(libs.ktor.server.core)\n    implementation(libs.exposed.core)\n}\n
\n

يضمن هذا أن جميع الوحدات تستخدم نفس الإصدارات، ويبسط التحديث الشامل.

\n\n

2. التنظيم العملي للوحدات: Gradle Multi-Project

\n

كل وحدة في المستودع الأحادي هي مشروع فرعي مستقل لـ Gradle مع ملف build.gradle.kts الخاص بها. لننظر في إعداد المكتبة common-utils:

\n
// libs/common-utils/build.gradle.kts\nplugins {\n    alias(libs.plugins.kotlin.jvm)\n}\n\ngroup = "com.mycompany.common"\nversion = "1.0.0"\n\ndependencies {\n    implementation(kotlin("stdlib"))\n    implementation(libs.kotlinx.coroutines)\n}\n
\n

وهذا مثال على خدمة مصغرة نموذجية على Ktor:

\n
// services/user-service/build.gradle.kts\nplugins {\n    alias(libs.plugins.kotlin.jvm)\n    alias(libs.plugins.ktor)\n}\n\ndependencies {\n    implementation(project(":libs:common-utils"))\n    implementation(project(":libs:common-dto"))\n    impl                

المدونات

توصيات الكتب