عبدالله الكندي: خمس لحظات حرجة في تطبيقات Offline-first
عبدالله الكندي يشرح خمس لحظات حرجة في تطبيقات Offline-first: الحفظ بلا شبكة، ومعرّفات السجلات، وطابور المزامنة، وحل التعارضات، والحذف بعد غياب طويل.

تطبيق يعمل بدون إنترنت
عبدالله الكندي
مندوب مبيعات يسجّل طلب عميل في مستودع بآخر المدينة، والشبكة شرطة وحدة. أو مشرف ميداني يوثّق زيارة لموقع مشروع تحت الإنشاء ما يوصله الإنترنت. التطبيق العادي هنا يعرض دائرة تحميل ورسالة «تحقق من اتصالك». والتطبيق المبني بفكرة Offline-first يحفظ ويكمل، ويزامن لما ترجع الشبكة. عبدالله الكندي يبني تطبيقات Flutter، ويعرف إن الحفظ المحلي هو الجزء السهل. الصعب هو اللحظات اللي تجي بعده، وهذي أهمها.
اللحظة الأولى: المستخدم يضغط «حفظ» بدون شبكة
الفكرة الأساسية إن التطبيق يكتب أولاً في قاعدة بيانات على الجهاز، مثل SQLite عبر مكتبة drift في Flutter، والواجهة تقرأ من هذي القاعدة المحلية دائماً، مو من الشبكة. وفي نفس اللحظة تنضاف العملية لطابور صادر (outbox): «أنشئ طلباً بهذي البيانات». المستخدم يشوف طلبه في القائمة فوراً، مع علامة صغيرة تقول إنه بانتظار المزامنة. وهذي العلامة أهم مما تتوقع: بدونها يفترض المستخدم إن الطلب وصل، أو يخاف إنه ضاع فيسجّله مرة ثانية.
ولأن البيانات صارت تعيش على الجهاز، صار لها عمر أطول من نسخة التطبيق. لما تنزل تحديثاً يغيّر شكل الجداول المحلية، لازم يكون معه ترحيل (migration) ينقل بيانات المستخدم القديمة للشكل الجديد بدون ما يمسحها. والأخطر: طلبات في الطابور ما انرسلت بعد، انحفظت بالشكل القديم. لو التحديث مسح القاعدة وبدأ من جديد، ضاعت شغلة يوم كامل لمندوب كان بدون شبكة.
اللحظة الثانية: مين يعطي السجل الجديد رقمه؟
في التطبيق العادي، الخادم يعطي كل سجل رقماً تسلسلياً: ١٠٠١، ١٠٠٢. لكن بدون شبكة ما فيه خادم تسأله. ولو التطبيق اخترع رقماً، ممكن جهازين يخترعون نفس الرقم. الحل إن كل سجل ينولد على الجهاز بمعرّف فريد عالمياً، مثل UUID، يبقى معه للأبد، والخادم يقبله كما هو. وإذا كان النشاط يحتاج أرقام فواتير متسلسلة لأسباب نظامية، فهذي تنصدر من الخادم بعد المزامنة، كحقل منفصل عن المعرّف.
اللحظة الثالثة: الشبكة رجعت، أو هكذا يبان
أشهر خطأ: الاعتماد على حالة الاتصال اللي يقولها النظام. مكتبة مثل connectivity_plus تقول لك إن الجهاز متصل بشبكة واي فاي أو بيانات، مو إن الإنترنت يشتغل فعلاً. ممكن يكون واي فاي فندق يطلب تسجيل دخول، أو شبكة متصلة بلا إنترنت. الأسلم إن التطبيق يحاول يزامن، ويحكم من النتيجة. وطابور المزامنة نفسه يحتاج قواعد:
- العمليات تنرسل بنفس ترتيب حدوثها، لأن تعديل طلب قبل إنشائه ما له معنى عند الخادم.
- كل عملية تحمل معرّفاً فريداً، والخادم يتجاهل المكرر، لأن الشبكة ممكن تنقطع بعد ما وصل الطلب وقبل ما يرجع الرد، فيعيد التطبيق الإرسال.
- إعادة المحاولة بفواصل متزايدة، مو كل ثانية، عشان ما تستنزف البطارية وتضغط الخادم.
- العملية اللي يرفضها الخادم لسبب منطقي، مثل منتج انحذف، ما تنعاد للأبد. تُعزل وتنعرض للمستخدم يقرر فيها.
- في آيفون بالذات، المزامنة في الخلفية ما لها توقيت مضمون، والنظام يقرر متى يعطي التطبيق فرصة. فخطّط إن المزامنة الأساسية تصير لما يفتح المستخدم التطبيق.
اللحظة الرابعة: شخصان عدّلا نفس السجل
هذي قلب الموضوع. المشرف عدّل عنوان العميل وهو بدون شبكة، وفي نفس الوقت زميله في المكتب عدّل رقم جواله. لما يزامن المشرف، وش يصير؟ فيه أكثر من استراتيجية، والأصح تختار وحدة لكل نوع بيانات، مو وحدة للتطبيق كله:
- آخر كتابة تفوز: أبسط حل، يعتمد التعديل الأحدث. مناسب لبيانات قليلة الأهمية مثل تفضيلات العرض، لكنه يمسح تعديل أحدهم بصمت. وساعات الأجهزة ممكن تكون غلط، فالأفضل الاعتماد على رقم إصدار للسجل مو على ساعة الجوال.
- الدمج على مستوى الحقل: إذا واحد عدّل العنوان والثاني الجوال، يُحفظ الاثنان. وهذا يحل أغلب التعارضات الفعلية، لأن الناس نادراً يعدّلون نفس الحقل في نفس الوقت.
- الخادم هو الحكم: في المخزون والأرصدة، الجهاز يرسل «نقّص ٣» مو «الكمية صارت ٧»، والخادم يطبّقها على الرقم الحقيقي عنده ويرفض لو ما يكفي.
- اسأل الإنسان: لما يتعارض نفس الحقل في بيانات مهمة، اعرض النسختين وخلّ المستخدم يختار.
اللحظة الخامسة: الحذف، والجهاز اللي غاب أسبوعاً
سجل انحذف على جهاز، كيف تعرف الأجهزة الثانية إنه انحذف، مو إنها ما استلمته بعد؟ الحل إن الحذف ما يمسح السجل فوراً، يحط عليه علامة حذف (tombstone) تنتقل مع المزامنة، وتنظَّف بعد فترة. وجهاز غاب أسبوعاً يحتاج يسحب كل اللي تغيّر من آخر مزامنة ناجحة، فكل سجل يحمل وقت آخر تعديل من الخادم، والجهاز يحفظ آخر نقطة وصلها. وانتبه لحجم البيانات: مو لازم كل جهاز ينزّل كل شي. المندوب يحتاج عملاءه هو، مو عملاء الشركة كلها، وهذا يخفف التطبيق ويخدم الخصوصية في نفس الوقت. ونفس المنطق عند تسجيل الخروج: البيانات المحلية لازم تنمسح، لكن بعد ما يتأكد التطبيق إن الطابور فاضي. ولو فيه عمليات ما انرسلت، نبّه المستخدم قبل ما يخرج، لأن الخروج وقتها يعني ضياع شغل ما وصل للخادم.
Offline-first ما يناسب كل تطبيق، وتكلفته الحقيقية في هذي اللحظات الخمس، مو في الحفظ المحلي. لكن لو مستخدمينك يشتغلون في الميدان أو في أماكن تغطيتها ضعيفة، فهو الفرق بين تطبيق يعتمدون عليه وتطبيق يتجنبونه. وفي منصة أزهل الرقمية يُطرح سؤال الاتصال قبل التصميم: وين بيكون المستخدم لما يفتح التطبيق؟ وإذا كان الجواب «مو دايماً قدام واي فاي»، فنصيحة عبدالله عبدالرحيم بن سنكر الكندي إن المزامنة تنبني جزءاً من المعمار من أول يوم، لأن إضافتها لتطبيق مكتمل تعني إعادة كتابة طبقة البيانات كلها تقريباً.
عندك فكرة؟ الاستشارة الأولى علينا
كلّم عبدالله مباشرة على واتساب — رسالتك توصل له هو، مو لرد آلي. نسمع فكرتك ونقول لك وش تحتاج وكم تكلّف، ببلاش.
مقالات ذات صلة
كل المقالات
المخرجات المنظمة
عبدالله بن سنكر
المخرجات المنظّمة JSON: عبدالله بن سنكر يشرح ليش تهم أي نظام إنتاج
عبدالله بن سنكر يقارن أربع طرق لإخراج JSON من نموذج الذكاء الاصطناعي، من الطلب بالكلام إلى المخطط الملزم، وكيف تصمّم المخطط وتتحقق منه وتتعامل مع الفشل.
اقرأ المقال
سكيلز كلود
عبدالله الكندي
Agent Skills سؤال وجواب: عبدالله الكندي وتعليم الوكيل مهارة مرة وحدة
أسئلة وأجوبة مع عبدالله الكندي عن Agent Skills: وش هو ملف SKILL.md، وكيف يقرر الوكيل متى يستخدم المهارة، والفرق بينها وبين MCP، وكيف تكتب أول مهارة لك.
اقرأ المقال
أدوات مجانية للتسويق
عبدالله عبدالرحيم الكندي
عبدالله عبدالرحيم الكندي: ليش تعطي أزهل أدوات مجانية؟ الكرم كاستراتيجية
عبدالله عبدالرحيم الكندي يشرح منطق الكرم كاستراتيجية تسويق، وستة أخطاء تحوّل الأداة المجانية من بناء ثقة إلى خسارة: الطعم، والبعد عن خدمتك، وجمع البيانات، وتكلفة التشغيل.
اقرأ المقال