لماذا مراجعة الكود في Kotlin ليست مجرد "أنا كنت سأكتبه بشكل مختلف"؟
\n\nمراجعة الكود (Code Review) هي طقس مقدس في أي فريق يحترم نفسه. ولكن عندما يتعلق الأمر بـ Kotlin، يقع العديد من المطورين في حيرة. "كل شيء هنا موجز جدًا!"، "حسنًا، هذه لغة قائمة على التعبيرات" - هكذا تفكر وأنت تتصفح طلب السحب. وهذا خطأ.
\n\nKotlin جميل ولكنه ماكر. يمنحك أدوات قوية: دوال النطاق، الفئات المختومة، الكوروتينات. وبنفس القدر من الفرص لإطلاق النار على قدمك. في هذه المقالة، سنحلل ما يجب الانتباه إليه حقًا أثناء مراجعة الكود في Kotlin، حتى لا يتحول كودك إلى "وحش معكرونة" مع تأثيرات جانبية قابلة للصفر.
\n\nهذه المقالة ليست كتابًا دراسيًا عن بناء الجملة. إنها قائمة مراجعة حية للمراجع الذي يريد رؤية ليس فقط كودًا يعمل، بل منتجًا قابلًا للصيانة وآمنًا.
\n\n1. سلامة القيم الخالية: عندما لا تكون "?" حلاً سحريًا
\n\nKotlin تفتخر بسلامة القيم الخالية (Null Safety). وهذا صحيح. ولكن في مراجعة الكود، يجب عليك التحقق ليس فقط من وجود "!!"، بل من منطق العمل مع الأنواع القابلة للصفر.
\n\nما الذي يجب أن يثير القلق بالتأكيد؟
\n\n- \n
- الاستخدام غير المنضبط لـ "!!". إذا وضع المطور
!!- يجب عليه أن يشرح في تعليق، لماذا هذه القيمة مضمونة ألا تكون فارغة. إذا لم يكن هناك تفسير - فهذا خطأ. \n - سلاسل من الاستدعاء الآمن (?.) و elvis (?:). غالبًا ما تخفي أخطاء منطقية. مثال: \n
// المشكلة: إذا كان user?.address?.city == null،\n// فسنعيد "Unknown" بصمت دون تسجيل\nval city = user?.address?.city ?: "Unknown"\n\n\nكيف يجب أن يكون؟ إذا كانت القيمة الخالية حالة استثنائية، استخدم requireNotNull أو checkNotNull. إذا كان هذا سلوكًا طبيعيًا - قم بتسجيله.
val city = user?.address?.city\n ?: run {\n logger.warn("المستخدم $userId ليس لديه مدينة")\n "Unknown"\n }\n\n\nفي مراجعة كود kotlin، اسأل دائمًا: "ماذا لو كانت هذه القيمة الخالية هي خطأ قمنا بإسكاته الآن؟"
\n\n2. دوال النطاق: let، apply، run - استخدمها بحكمة
\n\nدوال النطاق هي قوة Kotlin. لكن في الممارسة العملية، أرى أنها تُستخدم كمطرقة لأي مسمار. فحص كود Kotlin يجب أن يتضمن تحليلًا: "لماذا هنا تحديدًا let وليس run؟"
الأخطاء النموذجية:
\n\n- \n
- let للتحقق من القيمة الخالية. حسنًا، لكن لا تتداخل مع بعضها البعض: \n
// فظيع\nuser?.let { u ->\n address?.let { a ->\n process(u, a)\n }\n}\n\n// جيد\nif (user != null && address != null) {\n process(user, address)\n}\n\n\n- \n
- apply لتعديل الكائن. هذا هو مجاله الطبيعي. لكن إذا كنت تستخدم
applyداخلlet- توقف. هذا يشبه السباغيتي. \n
تذكر: with - لتجميع الاستدعاءات، also - للتأثيرات الجانبية (التسجيل)، run - للحسابات في السياق. لا تخلط بينها.
3. الثبات: var هي قطعة قماش حمراء
\n\nKotlin تروج لـ val. وهذا رائع. لكن في مراجعة كود Kotlin، أرى غالبًا مطورين يكتبون var حيث يمكنهم استخدام val مع النسخ.
// سيء\nvar result = mutableListOf<Int>()\nitems.forEach { result.add(it * 2) }\n\n// جيد\nval result = items.map { it * 2 }\n\n\nالقاعدة بسيطة: إذا رأيت var - اسأل: "لماذا ليس val؟" في أغلب الأحيان، ستدهشك الإجابة: "لم أفكر في الأمر".
الاستثناء الوحيد هو إذا كانت التعديلات ضرورية حقًا (مثلًا في الحلقات مع التجميع). ولكن حتى هناك، يمكن غالبًا استبدالها بـ fold أو reduce.
4. الفئات المختومة و when: لا تنسَ else
\n\nالفئات المختومة (Sealed classes) هي بديل أنيق