مقدمة: لماذا Kotlin هي اللغة المثالية للخدمات المصغرة
تتجه تطوير الواجهة الخلفية الحديثة بشكل متزايد بعيدًا عن الحلول المتجانسة نحو بنية الخدمات المصغرة. Kotlin، كونها لغة مكتوبة بشكل ثابت تعمل فوق JVM، تقدم للمطورين مزيجًا فريدًا من الإيجاز والأمان والأداء. على عكس Java، تسمح Kotlin بكتابة كود أكثر تعبيرًا وأمانًا دون الحاجة إلى كود نمطي متكرر، وهو أمر بالغ الأهمية عند بناء أنظمة موزعة معقدة.
في هذه المقالة، سنستعرض الدورة الكاملة لإنشاء خدمة مصغرة باستخدام Kotlin: بدءًا من اختيار الإطار وحتى النشر في حاوية. ستتعلم كيفية استخدام Ktor لخادم HTTP، وKoin لحقن التبعيات، وExposed للتعامل مع قاعدة البيانات. جميع أمثلة الكود جاهزة للاستخدام في المشاريع الحقيقية.
1. تصميم بنية الخدمة المصغرة
الخطوة الأولى هي تحديد حدود الخدمة. على عكس التطبيق المتجانس، كل خدمة مصغرة مسؤولة عن قدرة عمل واحدة. لنأخذ مثالاً على خدمة إدارة المستخدمين (User Service).
هيكل المشروع
الهيكل الموصى به لخدمة مصغرة بلغة Kotlin:
user-service/
├── src/
│ ├── main/kotlin/com/example/userservice/
│ │ ├── application/ # طبقة التطبيق (حالات الاستخدام)
│ │ ├── domain/ # نماذج المجال
│ │ ├── infrastructure/ # المستودعات، قاعدة البيانات، واجهات API الخارجية
│ │ └── presentation/ # المتحكمات (مسارات Ktor)
│ └── resources/
│ └── application.conf
└── build.gradle.kts
تتبع هذه البنية مبادئ Clean Architecture وDomain-Driven Design، مما يسهل الاختبار والصيانة.
اختيار مجموعة التقنيات
- إطار HTTP: Ktor (خفيف، غير متزامن، coroutines)
- حقن التبعيات: Koin (بسيط، بدون انعكاس)
- ORM: Exposed (DSL أصلي لـ Kotlin لـ SQL)
- قاعدة البيانات: PostgreSQL
- الحاويات: Docker + Docker Compose
2. تنفيذ الخدمة المصغرة باستخدام Kotlin مع Ktor وKoin
إعداد ملف build.gradle.kts
نقوم بإضافة التبعيات اللازمة:
plugins {
kotlin("jvm") version "1.9.22"
id("io.ktor.plugin") version "2.3.7"
kotlin("plugin.serialization") version "1.9.22"
}
dependencies {
implementation("io.ktor:ktor-server-core:2.3.7")
implementation("io.ktor:ktor-server-netty:2.3.7")
implementation("io.ktor:ktor-server-content-negotiation:2.3.7")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")
implementation("org.jetbrains.exposed:exposed-core:0.44.1")
implementation("org.jetbrains.exposed:exposed-dao:0.44.1")
implementation("org.jetbrains.exposed:exposed-jdbc:0.44.1")
implementation("org.postgresql:postgresql:42.6.0")
implementation("io.insert-koin:koin-ktor:3.5.0")
}
إنشاء نموذج المجال والمستودع
// domain/User.kt
data class User(
val id: Long,
val name: String,
val email: String
)
// infrastructure/UserRepository.kt
interface UserRepository {
suspend fun getAll(): List<User>
suspend fun getById(id: Long): User?
suspend fun create(user: User): User
}
تنفيذ المستودع باستخدام Exposed
// infrastructure/UserRepositoryImpl.kt
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.transaction
object UsersTable : Table("users") {
val id = long("id").autoIncrement()
val name = varchar("name", 255)
val email = varchar("email", 255)
override val primaryKey = PrimaryKey(id)
}
class UserRepositoryImpl(private val database: Database) : UserRepository {
override suspend fun getAll(): List<User> =
```