ميكروسيرفيسات بلغة Kotlin: بنية متقدمة وممارسة

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

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

ابدأ الدورة

مقدمة: لماذا Kotlin للميكروسيرفيسات؟



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



سنركز على الجوانب العملية: إعداد نقاط النهاية التفاعلية، حقن التبعيات بدون Spring، المعالجة غير المتزامنة مع coroutines، وكتابة الاختبارات. إذا كنت على دراية بأساسيات Kotlin وترغب في الانتقال إلى المستوى التالي، فهذه المادة مناسبة لك.



1. بنية الميكروسيرفيس باستخدام Ktor



اختيار الإطار: Ktor مقابل Spring Boot



للمستوى المتقدم، نختار Ktor - إطار عمل غير متزامن خفيف الوزن من JetBrains. على عكس Spring Boot، لا يستخدم Ktor الانعكاس أو التعليقات التوضيحية على غرار IoC، مما يمنح تحكمًا كاملاً في سياق التطبيق. هذا هو الخيار المثالي للميكروسيرفيسات حيث تكون سرعة البدء واستهلاك الذاكرة المنخفض مهمة.



هيكل المشروع



الهيكل الموصى به لميكروسيرفيس باستخدام Ktor:



project/├── src/│   ├── main/kotlin/com/example/│   │   ├── Application.kt        // نقطة الدخول│   │   ├── routes/               // المسارات (REST API)│   │   ├── services/             // منطق الأعمال│   │   ├── repositories/         // الوصول إلى البيانات│   │   ├── models/               // DTO والكيانات│   │   └── di/                   // وحدات حقن التبعيات│   └── test/kotlin/com/example/  // الاختبارات└── build.gradle.kts


إعداد المسارات



مثال على نقطة نهاية REST تفاعلية باستخدام coroutines:



fun Application.configureRouting() {    routing {        route("/api/v1/users") {            get("/{id}") {                val id = call.parameters["id"]?.toIntOrNull()                    ?: return@get call.respondText("معرف غير صالح", status = HttpStatusCode.BadRequest)                val user = userService.getUserById(id)                if (user != null) {                    call.respond(user)                } else {                    call.respondText("المستخدم غير موجود", status = HttpStatusCode.NotFound)                }            }            post {                val user = call.receive<UserDto>()                val created = userService.createUser(user)                call.respond(HttpStatusCode.Created, created)            }        }    }}


2. حقن التبعيات باستخدام Koin



لماذا Koin؟



Koin هي لغة خاصة بالمجال (DSL) لحقن التبعيات، متوافقة تمامًا مع Kotlin. لا تتطلب توليد كود أو انعكاس، وتعمل على مستوى المنشئات وتعبيرات lambda. هذا يسمح بإنشاء خدمات معيارية وقابلة للاختبار.



مثال على وحدة DI



val appModule = module {    single { DatabaseConnection() }    single { UserRepository(get()) }    factory { UserService(get()) }}

fun Application.configureDI() { startKoin { modules(appModule) }}


لاحظ: نستخدم factory للخدمات - كل طلب يحصل على مثيل جديد، وهو أمر مهم للسيناريوهات التفاعلية. يُستخدم single للمستودعات واتصالات قاعدة البيانات.



3. عدم التزامن و coroutines



Reactive Streams و Flow



للعمل مع تدفقات البيانات في الوقت الفعلي، استخدم kotlinx.coroutines.flow. هذا مشابه لـ Reactive Streams، ولكن مع بناء جملة أبسط ودعم كامل لـ coroutines.



مثال على خدمة تعالج البيانات من قائمة انتظار:



class OrderProcessor(private val orderRepository: OrderRepository) {

suspend fun processOrders(): Flow<OrderResult> = flow { orderRepository.getPendingOrders().coll

المدونات

توصيات الكتب