إعادة هيكلة الكود القديم (Legacy) في Kotlin: استراتيجية وأمثلة
العمل مع الكود القديم (legacy) هو جزء لا مفر منه في حياة أي مطور. غالبًا ما يكون هذا الكود مكتوبًا بلغة Java، ولكن حتى المشاريع في الإصدارات المبكرة من Kotlin قد تحتوي على "روائح كود" (code smells) وأخطاء معمارية. في هذه المقالة، سنقوم بتحليل استراتيجية خطوة بخطوة لإعادة هيكلة الكود القديم في Kotlin، وسنقدم أمثلة محددة للتحويلات، وسنشرح كيفية تجنب الأخطاء النموذجية.
1. التحضير لإعادة الهيكلة: السلامة أولاً
المرحلة الأولى والأكثر أهمية هي ضمان سلامة التغييرات. بدون تغطية اختبارية جيدة، تتحول أي إعادة هيكلة إلى لعبة روليت روسية.
- أضف اختبارات الوحدة. إذا لم تكن هناك اختبارات، فاكتبها للأجزاء الحرجة من الكود. استخدم أطر العمل
JUnit 5وMockKالخاصة بـ Kotlin. - ثبّت السلوك. اكتب اختبارات تتحقق من السلوك الحالي للنظام (characterization tests)، حتى لو بدا غير صحيح. سيسمح لك ذلك بعدم كسر المنطق أثناء إعادة الهيكلة.
- استخدم نظام التحكم في الإصدارات. قم بعمل commits بعد كل خطوة مكتملة منطقيًا، حتى تتمكن من التراجع.
مثال على اختبار بسيط لدالة قديمة في Kotlin:
import org.junit.jupiter.api.Testimport kotlin.test.assertEquals
class LegacyServiceTest { @Test fun `test calculateTotal`() { val service = LegacyService() val result = service.calculateTotal(listOf(10.0, 20.0, 30.0)) assertEquals(60.0, result) }}2. الترحيل التدريجي من Java إلى Kotlin
إذا كان الكود القديم الخاص بك مكتوبًا بلغة Java، فلا تحاول إعادة كتابة كل شيء دفعة واحدة. استخدم المحولات التلقائية (على سبيل المثال، المضمنة في IntelliJ IDEA: Code → Convert Java File to Kotlin File)، ثم قم بتحسين النتيجة يدويًا.
النقاط الرئيسية التي يجب الانتباه إليها بعد التحويل:
- Null safety. استبدل
@Nullableو@NonNullبعوامل التشغيل?و!!(الأخير فقط إذا كنت متأكدًا من عدم وجود null). - Data classes. بدلاً من فئات Java التي تحتوي على
equals()وhashCode()، استخدمdata class. - دوال الإضافة (Extension functions). قم بنقل الأساليب الثابتة (static methods) المساعدة إلى extension functions.
مثال على تحويل فئة Java إلى Kotlin:
// Javapublic class User { private String name; private int age;
public User(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; } public int getAge() { return age; }}
// Kotlin (بعد إعادة الهيكلة)data class User(val name: String, val age: Int)3. تحسين البنية: التخلص من كود "المعكرونة" (Spaghetti code)
غالبًا ما يعاني الكود القديم من انتهاك مبادئ SOLID. فيما يلي ثلاث تقنيات محددة ستساعد في ترتيب الكود:
3.1. فصل المسؤوليات (Single Responsibility)
ابحث عن الفئات التي تفعل الكثير. على سبيل المثال، "الكائن الإلهي" (God Object) الذي يخزن البيانات، ويتحقق من صحتها، ويرسل الطلبات. قم بتقسيمه إلى عدة فئات ذات منطقة مسؤولية واضحة.
3.2. استبدال سلاسل if-else الطويلة بـ when
توفر Kotlin عامل التشغيل القوي when، مما يجعل الكود أكثر قابلية للقراءة:
// قبل إعادة الهيكلةfun getStatusText(status: Int): String { if (status == 0) return "Pending" else if (status == 1) return "Active" else if (status == 2) return "Blocked" else return "Unknown"}
// بعد إعادة الهيكلةfun getStatusText(status: Int): String = when (status) { 0 -> "Pending" 1 -> "Active" 2 -> "Blocked" else -> "Unknown"}