مقدمة: لماذا "الكود النظيف" ليس مسألة جمالية
عندما تبدأ للتو في الكتابة بلغة Kotlin، يبدو أن اللغة نفسها تحل نصف المشاكل. لا يوجد كود متكرر كما في Java. هناك `data class`، لامبدات، coroutines. ولكن إذا قمت ببساطة بكتابة كود "على عواهنه"، بعد شهر لن تتمكن أنت نفسك من فهمه. وإذا كان فريق يعمل على المشروع - فسيُبغضك زملاؤك (أو ستبغضهم أنت).
الكود النظيف في Kotlin ليس حول استخدام tabs بدلاً من المسافات. إنه حول كيفية تقليل العبء المعرفي، وجعل المنطق شفافاً، وتجنب الأخطاء التي تختبئ في التركيبات "المريحة". في هذه المقالة، سأعرض تقنيات محددة: من العمل مع nullable إلى استخدام scope functions و sealed classes. بدون حشو، فقط ممارسة.
1. Null Safety: كيف لا تكثر من استخدام "?" و "!!"
تفتخر Kotlin بنظام أنواعها، لكن الكثيرين يكتبون كما لو كانت Java مع "سكر نحوي". النمط المضاد الرئيسي هو سلاسل `?.let` والاستخدام المذعور لـ `!!`.
سيء (قابلية القراءة تتأثر):
user?.address?.city?.let { city -> println(city)} ?: run { println("No city")}جيد (أنيق ونظيف):
val city = user?.address?.cityprintln(city ?: "No city")استخدم `!!` فقط إذا كنت متأكداً 100% أن القيمة ليست null (مثلاً في الاختبارات أو بعد التحقق في `if`). في بيئة الإنتاج - إنها قنبلة. إذا كنت بحاجة لتحويل nullable إلى non-null ومعالجة كلتا الحالتين - استخدم when أو عامل الإلفيس.
2. Scope Functions: `apply`, `run`, `with`, `let`, `also` - متى نستخدم ماذا؟
هذه أداة قوية، لكن غالباً ما يُساء استخدامها. القاعدة الذهبية: لا تقم بتداخل scope functions داخل بعضها البعض. إذا كان لديك `list.apply { ... }.let { ... }` - فأنت تكتب كوداً معكرونياً.
قواعد الاختيار:
apply- لتكوين كائن (يعيد الكائن نفسه). مثالي للـ builders.let- لتنفيذ إجراء بقيمة non-null (غالباً مع `?.`).run- عندما تحتاج لحساب قيمة وإرجاع النتيجة.with- لتجميع استدعاءات كائن واحد دون إرجاع.also- للتأثيرات الجانبية (تسجيل، تحقق).
مثال نظيف:
data class User(var name: String, var age: Int)
fun createUser(): User = User("Unknown", 0).apply { name = "Alice" age = 30}لا تكتب user?.let { it.name } - هذا زائد عن الحاجة. فقط user?.name.
3. Extension Functions: لا تكثر من إنشاء كلاسات مساعدة
في Java كنت ستكتب StringUtils.capitalize(str). في Kotlin - str.capitalize(). دوال التوسعة هي طريقة "لإضافة" كلاس شخص آخر، دون وراثته.
مثال على extension مفيد:
fun String.isValidEmail(): Boolean { return this.contains("@") && this.contains(".")}لكن لا تفرط في استخدامها. إذا كانت دالة التوسعة تُستخدم في مكان واحد فقط - فربما يجب أن تكون خاصة. ولا تقم بعمل extension على `Any` - فهذا يكسر نظام الأنواع.
4. Sealed Classes و When: أداتك الرئيسية بدلاً من if-else
عندما يكون لديك مجموعة محدودة من الحالات (مثل نتيجة طلب API)، استخدم sealed class. هذا يضمن أنك عالجت جميع الخيارات.
النهج الصحيح:
sealed class NetworkResult<out T> { data class Success<T>(val data: T) : NetworkResult<T>() data class Error(val message: String, val code: Int) : NetworkResult<Nothing>() object Loading : NetworkResult<Nothing>()}
fun handle(result: NetworkResult<String>) { when (result) { is NetworkResult.Success -> println("Data: ${result.data}") is NetworkResult.Error -> println("Error: ${resu