كيف تجتاز مقابلة Kotlin: أهم الأسئلة المتقدمة
مقابلة منصب مطور Senior Kotlin ليست مجرد اختبار للصياغة النحوية. يريد المحاورون رؤية فهم عميق لهندسة اللغة، وخصائص التجميع، وتعدد الخيوط. في هذه المقالة، سنحلل أصعب الأسئلة وأكثرها شيوعًا والتي ستساعدك على اجتياز المقابلة الفنية بثقة. المادة موجهة للمطورين الذين لديهم بالفعل خبرة في العمل مع Kotlin وJava.
1. coroutines: التزامن المنظم (Structured Concurrency) وإلغاء المهام
تعتبر coroutines من أقوى جوانب Kotlin. غالبًا ما يتعلق السؤال المتقدم بـ التزامن المنظم (Structured Concurrency). قد يسأل المحاور: "ماذا يحدث إذا ألقت coroutine فرعية استثناءً ولم تلتقطه coroutine الأم؟"
الإجابة تكمن في التسلسل الهرمي لـ Job. إذا فشلت coroutine فرعية (تم تشغيلها عبر coroutineScope أو داخل launch) باستثناء، فإنه ينتقل إلى الأصل. يتم إلغاء coroutine الأم، وكذلك جميع مهامها الفرعية. وهذا يجعل الكود قابلاً للتنبؤ وآمنًا.
مثال يستحق العرض في المقابلة:
import kotlinx.coroutines.*
fun main() = runBlocking { try { coroutineScope { launch { delay(100) throw RuntimeException("خطأ في coroutine الفرعية") } launch { delay(200) println("هذه coroutine لن يتم تنفيذها إذا فشلت الأولى") } } } catch (e: Exception) { println("تم التقاط الاستثناء: ${e.message}") } println("يستمر البرنامج في العمل")}سؤال شائع آخر هو إلغاء coroutines. كيف تلغي coroutine بشكل صحيح؟ استخدم Job.cancel() وتحقق من الحالة عبر ensureActive() أو isActive داخل العمليات الطويلة.
2. الدوال المضمنة (inline functions) والأنواع المحققة (reified types)
يجب على المطورين المتقدمين فهم سبب الحاجة إلى الدوال inline. قد يكون السؤال: "لماذا لا يسمح Kotlin باستخدام الأنواع المحققة (reified) بدون inline؟"
الإجابة: تعمل الأنواع reified (المحققة) فقط داخل الدوال المضمنة (inline functions)، لأن كود هذه الدالة يتم تضمينه مباشرة في مكان الاستدعاء. يقوم المترجم باستبدال النوع المحدد أثناء وقت التجميع، وهو أمر مستحيل للدوال العامة العادية بسبب محو النوع (type erasure) في JVM.
مثال يوضح قوة reified:
inline fun <reified T> isInstance(value: Any): Boolean { return value is T}
fun main() { println(isInstance<String>("Hello")) // true println(isInstance<Int>("Hello")) // false}سيتم أيضًا السؤال عن noinline و crossinline. noinline يمنع تضمين معامل لامدا محدد، بينما crossinline يمنع استخدام return داخل لامدا (الإرجاع غير المحلي).
3. المفوضين (Delegates): Delegates.observable, vetoable والمفوضين المخصصين
السؤال عن المفوضين هو سؤال كلاسيكي. المستوى المتقدم لا يعني فقط معرفة المفوضين المدمجين (lazy, observable)، بل وأيضًا القدرة على كتابة مفوضين خاصين بك.
مثال: "كيف تنفذ مفوضًا يسجل كل تغيير في الخاصية؟"
import kotlin.properties.ReadWritePropertyimport kotlin.reflect.KProperty
class LoggingDelegate<T>(private val initialValue: T) : ReadWriteProperty<Any?, T> { private var value = initialValue
override fun getValue(thisRef: Any?, property: KProperty<*>): T { println("قراءة ${property.name}: $value") return value }
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { println("كتابة ${property.name}: $value") this.value = value }}
class User { var