الصباح لا يبدأ بالقهوة، بل بـ Merge Request
\n\nالساعة 7:45 صباحًا. الهاتف يهتز - ليس المنبه، بل إشعار من GitLab: طلب الدمج (Merge Request) الذي أرسلته أمس اجتاز خط أنابيب CI/CD. بينما يغلي الغلاية، أفتح الكمبيوتر المحمول وأرى علامة خضراء. أول انتصار في اليوم. صباح الخير، Kotlin.
\n\nاسمي أليكسي، أنا مطور Kotlin في شركة منتجات. في السنوات الثلاث الماضية، أكتب بلغة Kotlin لتطبيقات Android وقليلًا على الخادم الخلفي باستخدام Ktor. إذا كنت تعتقد أن عمل المبرمج هو "Hello World" لا نهاية له، فسأكسر هذه الأسطورة اليوم. مرحبًا بك في يوم عملي الحقيقي.
\n\n8:30 — Daily Standup: التزامن والسياق
\n\nأول ما يحدث هو الاجتماع اليومي. نجتمع عبر Zoom، ولكن بدون "أمس-اليوم-مشاكل" الزائدة. لدينا أسلوب موجز: ما تم إنجازه، ما هو مخطط له، هل هناك عوائق. اليوم أعمل على ميزة الإشعارات الفورية (Push) للمستخدمين.
\n\n- بالأمس أنهيت إعادة هيكلة NotificationService، وأعدت كتابته باستخدام الكوروتينات. اليوم سأقوم بتوصيل Firebase Cloud Messaging واختبار Flow. لا توجد عوائق.
بالمناسبة، غالبًا ما تولد أفضل أفكار الهندسة المعمارية في هذه الاجتماعات. على سبيل المثال، في الأسبوع الماضي اقترح زميل استبدال RxJava بـ Kotlin Flow - وقللنا كمية الكود النمطي (boilerplate) بنسبة 40%. إليك كيف يبدو ذلك الآن:
\n\n// بدلاً من RxJava القديم:\n// Observable.just(data).subscribeOn(Schedulers.io())\n\n// نستخدم Kotlin Flow:\nfun observeNotifications(): Flow<Notification> = flow {\n val service = NotificationService()\n while (true) {\n emit(service.getNextNotification())\n delay(5000) // استطلاع كل 5 ثوانٍ\n }\n}.flowOn(Dispatchers.IO)\n\nالفرق واضح: قابلية القراءة، أمان الأنواع، ولا جحيم الاستدعاءات (callback hell).
\n\n9:15 — التطوير: كتابة كود بلغة Kotlin
\n\nبعد الاجتماع، أغوص في الكود. مهمة اليوم هي تنفيذ معالجة الإشعارات الفورية الواردة. أستخدم Kotlin Coroutines و StateFlow لإدارة حالة واجهة المستخدم. إليك كيف يبدو ViewModel الخاص بي:
\n\nclass PushViewModel(\n private val repository: NotificationRepository\n) : ViewModel() {\n\n private val _uiState = MutableStateFlow<PushUiState>(PushUiState.Loading)\n val uiState: StateFlow<PushUiState> = _uiState.asStateFlow()\n\n fun loadNotifications() {\n viewModelScope.launch {\n repository.getNotifications()\n .catch { e ->\n _uiState.value = PushUiState.Error(e.message ?: "خطأ غير معروف")\n }\n .collect { notifications ->\n _uiState.value = PushUiState.Success(notifications)\n }\n }\n }\n}\n\nsealed class PushUiState {\n object Loading : PushUiState()\n data class Success(val data: List<Notification>) : PushUiState()\n data class Error(val message: String) : PushUiState()\n}\n\nلاحظ: أستخدم sealed class لحالة واجهة المستخدم. هذه ممارسة قياسية في تطوير Android الحديث بلغة Kotlin. لا سلاسل if-else - فقط كتابة نقية.
\n\nبالمناسبة، إذا كنت مبتدئًا في Kotlin، أنصحك بالانتباه إلى دوال النطاق (Scope functions): let، apply، also. فهي تجعل الكود أكثر إيجازًا. على سبيل المثال:
// بدون دوال النطاق\nval user = User()\nuser.name = "Alex"\nuser.age = 30\nsaveUser(user)\n\n// مع apply\nval user = User().apply {\n name = "Alex"\n age = 30\n}\nsaveUser(user)\n\n11:00 — مراجعة الكود: نتعلم من الزملاء
\n\nبعد الغداء (نعم، أتناول الغداء في الساعة 11 - عادة من العمل عن بُعد)، أفتح طلب دمج (Merge Request) من زميل. يعيد كتابة وحدة المصادقة باستخدام Kotlin Multiplatform. أقرأ الكود وأرى نقطة مثيرة للاهتمام:
\n\n// كان (\n