Skip to content

تتبع البيانات: تسجيل ما يفعله المستخدمون في التطبيق

🎯 المشكلة التي يحلها هذا الفصل

كيف نعرف ما يفعله المستخدمون في تطبيقنا؟

تخيل أنك فتحت متجر شاي بالحليب فعلي. يمكنك الوقوف خلف الكاشير ومراقبة كل عميل مباشرة: كم من الوقت نظر إلى القائمة بعد دخوله؟ ماذا طلب؟ هل تردد ثم غادر بدون طلب؟

لكن إذا كان "متجرك" تطبيق هاتف أو موقع ويب، فلا يمكنك رؤية أفعال المستخدمين مباشرة. هنا تحتاج إلى وسيلة تقنية لـ "تثبيت" نقاط تسجيل في الأماكن الرئيسية بالتطبيق، تسجّل تلقائيًا كل خطوة يقوم بها المستخدم. هذا هو تتبع البيانات (Event Tracking).

مصطلح "التتبع" يبدو تقنيًا جدًا، لكن فكرته الأساسية بسيطة: في كل مكان قد يتصرف فيه المستخدم، ضع "مسجّلاً" يدوّن ما فعله المستخدم.

سيشرح هذا الفصل العملية في أربع خطوات:

  1. اختيار مخطط الجمع — تحديد أين نضع المسجّلات وكيف
  2. تصميم تنسيق البيانات — تحديد المعلومات التي يجب أن يحتويها كل سجل
  3. النقل والتخزين المؤقت — إيصال السجلات من هاتف المستخدم إلى الخادم بأمان
  4. التنظيف والتخزين — ترتيب البيانات وإزالة التكرارات والأخطاء وحفظها في قاعدة البيانات

الخطوة 1: اختيار مخطط الجمع — أين نضع المسجّلات؟

الهدف: تحديد الطريقة المستخدمة لتسجيل أفعال المستخدمين.

على سبيل المثال: مدير المنتج يريد معرفة "كم مستخدمًا نقر على زر الشراء". للإجابة، يحتاج المطورون إلى إضافة منطق تسجيل في كود "زر الشراء" — في كل مرة ينقر فيها المستخدم على هذا الزر، يُسجَّل ذلك تلقائيًا.

لكن هناك خيار: هل نضع مسجّلات فقط في الأماكن المهمة (مثل تسجيل "الشراء" و"التسجيل" فقط)، أم في كل مكان (تسجيل كل نقرة وانزلاق وبقاء)؟

اختيارات مختلفة تقابل مخططات تتبع مختلفة.

场景:用户在电商 App 点击了「加入购物车」按钮
捕获到的信息代码埋点可视化埋点全埋点
点击了哪个按钮
点击发生的时间
用户停留了多久
商品名称 / 价格
用了哪张优惠券
账户余额
页面滑动轨迹

💡 ثلاث طرق تتبع رئيسية

ثلاثة مخططات تتبع شائعة في المجال، لكل منها مزايا وعيوب:

الطريقة الأولى: التتبع بالكود (Code Tracking) — تسجيل يدوي دقيق

يحدد المطور يدويًا في الكود: عندما يقوم المستخدم بفعل ما، سجّل بيانات.

بالتشبيه: هذا مثل تعيين شخص في كاشير متجر الشاي بالحليب، يسجّل فقط "من اشترى ماذا وكم دفع". المعلومات المسجلة مفصلة ودقيقة للغاية.

  • الميزة: يمكن تسجيل معلومات أعمال مفصلة جدًا، مثل أي كوبون استخدمه المستخدم وما رصيده
  • التكلفة: كل نقطة تسجيل جديدة تحتاج من المطور كتابة كود واختباره ونشر نسخة جديدة — عملية طويلة

الطريقة الثانية: التتبع المرئي (Visual Tracking) — التحديد بالنقر

لا تحتاج لكتابة كود. يوفر النظام أداة مرئية يمكن لفريق العمليات من خلالها "تحديد" الأزرار أو المناطق مباشرة على واجهة التطبيق، ويبدأ النظام التسجيل تلقائيًا.

بالتشبيه: هذا مثل على شاشة مراقبة المتجر، تحديد بمنطقة "الكاشير" بالماوس، فيبدأ النظام تلقائيًا عد حركة الناس في تلك المنطقة.

  • الميزة: لا تحتاج مشاركة المطورين؛ فريق العمليات يُعدّها بنفسه بكفاءة عالية
  • التكلفة: يمكن فقط تسجيل أفعال الواجهة مثل "ماذا نقر المستخدم"، ولا يمكن تسجيل بيانات الأعمال العميقة مثل "مبلغ الطلب"

الطريقة الثالثة: التتبع الشامل (Auto Tracking) — تسجيل كل شيء تلقائيًا

يتم دمج SDK (يمكن فهمه كـ "حزمة أدوات") في التطبيق، والذي يسجّل تلقائيًا كل أفعال المستخدم: كل نقرة، كل انزلاق، كم بقي في كل صفحة.

بالتشبيه: هذا مثل تركيب كاميرات في كل زاوية من المتجر، تسجّل كل حركة للعملاء.

  • الميزة: لا تفوت أي فعل، التغطية الأكمل
  • التكلفة: حجم البيانات ضخم جدًا، الكثير منها معلومات غير مفيدة (مثل انزلاقات المستخدم اللاواعية)، تتطلب جهدًا كبيرًا للفرز والتنظيف لاحقًا

ملخص هذه الخطوة: بعد اختيار طريقة التتبع، أصبح تطبيقنا قادرًا على "تسجيل أفعال المستخدم".

لكن تبرز مشكلة جديدة: المسجّلات قادرة على التقاط أفعال المستخدم، لكن إذا كان كل مسجّل يسجّل بتنسيق مختلف (مثلاً بعضها يكتب "معرّف المستخدم" وبعضها "userID" وبعضها لا يسجّل أصلًا)، فلا يمكن تحليلها بشكل موحد. لذلك في الخطوة التالية، نحتاج لوضع تنسيق تسجيل موحد.


الخطوة 2: تصميم تنسيق البيانات — ماذا يجب أن يحتوي كل سجل؟

المتطلبات المسبقة: اخترنا طريقة التتبع (مثل التتبع بالكود)، والتطبيق قادر على التقاط أفعال المستخدم.

هدف هذه الخطوة: وضع "قالب تسجيل" موحد لتحافظ كل سجلات التتبع على تنسيق متسق.

لماذا نحتاج تنسيقًا موحدًا؟ تخيل: إذا كان في متجر الشاي بالحليب ثلاثة موظفين يسجّلون المبيعات في آنٍ واحد: واحد يكتب "أحمد اشترى شاي بالحليب بـ 15 ريالًا"، وآخر يكتب "15، شاي، حليب"، وثالث يكتب "كوب شاي بالحليب". عند التجميع نهاية الشهر، هذه التنسيقات المختلفة تمامًا تجعل التجميع صعبًا جدًا. لذلك نحتاج "استمارة تسجيل" موحدة تحدد الحقول التي يجب ملؤها في كل سجل.

What"event": "add_to_cart"
Who"user_id": "u_98765"
When"time": "2025-08-12T10:33:09Z"
Where"device": "iPhone 15", "network": "5G"
What"product": "新款手机", "price": 2999
点击上方按钮,观察一条埋点记录是如何被组装出来的

💡 المبدأ الأساسي: قالب 4W1H

بغض النظر عن الفعل المسجّل، كل بيانات يجب أن تجيب على خمسة أسئلة (تُعرف اختصارًا بـ 4W1H):

Who — مَن فعله؟

نحتاج معرفة أي مستخدم أنشأ هذا السجل.

  • إذا كان المستخدم قد سجّل دخوله، نستخدم معرّف حسابه (مثل user_id: "ahmed123")
  • إذا لم يسجّل الدخول، نستخدم المعرّف الفريد للجهاز (مثل الرقم التسلسلي للهاتف)، لتمييز أن "هذه الأفعال من نفس الهاتف" على الأقل

When — متى فعله؟

تسجيل الوقت الدقيق للفعل، بدقة الملي ثانية.

هناك تفصيل: إذا كان تطبيقك له مستخدمون في الخارج، الساعة 3 عصرًا بتوقيت بكين والساعة 3 عصرًا بتوقيت نيويورك تختلفان بـ 13 ساعة. لتجنب الخلط، كل الأوقات تُحوَّل إلى UTC (التوقيت العالمي المنسق).

Where & How — في أي بيئة فعله؟

هذا الجزء يسجّل بيئة الجهاز والشبكة عند قيام المستخدم بالفعل، ويُسمى السمات المشتركة. سُميت "مشتركة" لأنه بغض النظر عن فعل المستخدم، تُرفق هذه المعلومات تلقائيًا. على سبيل المثال:

  • طراز الجهاز: iPhone 15 / Xiaomi 14
  • نوع الشبكة: WiFi / 5G / 4G
  • نسخة التطبيق: v1.2.3
  • نظام التشغيل: iOS 18 / Android 15

قيمة هذه المعلومات: إذا اكتُشف خطأ يظهر فقط على طراز معين، السمات المشتركة تساعد في تحديد المشكلة بسرعة.

What — ماذا فعل بالضبط؟

هذا الجزء يسجّل تفاصيل الأعمال المحددة للفعل، وتُسمى السمات المخصصة. أفعال مختلفة تحتاج تسجيل معلومات مختلفة. على سبيل المثال:

  • المستخدم نقر "أضف إلى السلة": يجب تسجيل اسم المنتج وسعره وكميته
  • المستخدم أكمل الدفع: يجب تسجيل مبلغ الطلب وطريقة الدفع ورقم الكوبون

ملخص هذه الخطوة: من خلال قالب 4W1H، حوّلنا كل فعل للمستخدم إلى سجل بيانات بتنسيق موحد. في التنفيذ التقني، يُخزَّن هذا السجل عادةً بتنسيق JSON (JSON هو تنسيق بيانات عام، والمكون التفاعلي أعلاه يعرض شكله).

لكن تبرز مشكلة أخرى: تنسيق البيانات أصبح موحدًا، لكن إذا كان عدد المستخدمين كبيرًا (مثلًا خلال حملة ترويجية قد تُولَّد عشرات الآلاف من السجلات في الثانية)، فإن هاتف المستخدم لا يمكنه إرسال كل سجل فور تكوّنه — هذا يستهلك البطارية وبيانات الشبكة، والخادم لا يتحمله. لذلك في الخطوة التالية، نحتاج تصميم طريقة نقل أذكى.


الخطوة 3: النقل والتخزين المؤقت — كيف ننقل البيانات بأمان إلى الخادم؟

المتطلبات المسبقة: كل فعل للمستخدم سُجِّل كبيانات JSON بتنسيق موحد.

هدف هذه الخطوة: نقل هذه البيانات من هاتف (أو متصفح) المستخدم إلى الخادم بشكل موثوق، حتى في ظروف الشبكة السيئة دون فقدان بيانات.

لماذا لا نرسلها مباشرة؟ إذا أُرسل كل سجل فور تكوّنه كطلب شبكة، فذلك مثل الذهاب لمكتب البريد مع كل رسالة تكتبها — غير فعال جدًا. الأفضل: تجميع مجموعة رسائل وإرسالها دفعة واحدة.

📱
手机
📦
打包
🌐
发送
🚦
排队
🗄️
入库
产生数据攒一批网络传输消息队列数据仓库

💡 المبدأ الأساسي: ضمانات النقل الثلاثة

البيانات، من هاتف المستخدم إلى الخادم، تحتاج لتمرير عبر ثلاث آليات ضمان لضمان الفعالية وعدم فقدان البيانات:

الضمانة الأولى: تجميع دفعة قبل الإرسال (التجميع بالدفعات)

SDK (حزمة أدوات التتبع) لا يرسل سجلاً كلما تكوّن واحد، بل يخزّنه مؤقتًا في ذاكرة الهاتف. عندما يتجمع عدد معين (مثلاً 30 سجلاً)، أو ينقضي وقت معين (مثلاً 5 ثوانٍ)، يُحزَّم ويرسل دفعة واحدة.

مثل إرسال الطرود: لا تذهب لمكتب البريد مع كل شيء تشتريه، بل تجمع عدة أشياء وترسلها معًا، موفرًا الوقت والجهد. بالنسبة للهاتف، هذا يقلل عدد طلبات الشبكة، موفرًا البطارية والبيانات.

الضمانة الثانية: بدون شبكة لا تضيع البيانات (التخزين المحلي)

في المصعد أو نفق المترو، غالبًا ما يفقد الهاتف إشارة الشبكة. إذا كانت البيانات في الذاكرة فقط، ستُفقد عند إغلاق التطبيق.

لذلك يخزّن SDK البيانات غير المُرسلة في التخزين المحلي للهاتف (مثل حفظ الرسائل في الدرج أولًا). عند عودة الشبكة، يُعيد إرسالها تلقائيًا. هكذا حتى لو انقطعت الشبكة مؤقتًا، البيانات لا تضيع.

الضمانة الثالثة: ألّا ينهار الخادم (طابور الرسائل)

عندما تصل البيانات للخادم، لا تُكتب مباشرة في قاعدة البيانات. لماذا؟ لأنه خلال ذروة الحملات الترويجية قد تتدفق عشرات الآلاف من البيانات في الثانية، وقاعدة البيانات قد تنهار إذا عالجت هذا الحجم مباشرة.

الحل هو إضافة "منطقة عازلة" في المنتصف، تُسمى تقنيًا طابور الرسائل (أداة شائعة هي Kafka). وظيفتها مثل نظام أخذ الأرقام في المطعم: في أوقات الذروة، الزبائن (البيانات) ينتظرون في الطابور، والمطبخ (قاعدة البيانات) يعالج وتيرته الخاصة دون أن يُغمر بالطلبات المتزامنة.

ملخص هذه الخطوة: عبر الضمانات الثلاث "تجميع دفعة قبل الإرسال → تخزين محلي بدون شبكة → طابور رسائل عازل"، وصلت البيانات بأمان إلى الخادم.

لكن تبقى مشكلة: نظرًا لأن البيانات تُعاد إرسالها تلقائيًا عند إعادة الاتصال، قد يُرسل نفس السجل مرتين. إذا لم يُعالج قبل التخزين، ستتكرر البيانات (مثلاً طلب بقيمة 100 ريال يُحسب كطلبين، والمبيعات تتضخم). لذلك في الخطوة التالية، نحتاج "تنظيف" البيانات.


الخطوة 4: التنظيف والتخزين — ترتيب البيانات وإزالة "البيانات المتسخة"

المتطلبات المسبقة: البيانات وصلت بأمان إلى الخادم عبر خط النقل.

هدف هذه الخطوة: قبل تخزين البيانات في قاعدة البيانات رسميًا، إجراء "فحص صحة" — إزالة المكررات وإصلاح ذات التنسيق الخاطئ، لضمان أن البيانات النهائية نظيفة ودقيقة.

لماذا نحتاج التنظيف؟ مثل استلام صندوق طرود، تحتاج أن تتحقق: هل هناك طرود مكررة؟ هل أُرسل شيء بالخطأ؟ هل هناك تغليف تالف؟ البيانات أيضًا تحتاج فحصًا وترتيبًا قبل التخزين.

هذه العملية تُسمى تقنيًا ETL، اختصار لثلاث كلمات إنجليزية:

  • Extract (الاستخراج): سحب البيانات من طابور الرسائل
  • Transform (التحويل): فحص وإصلاح تنسيق البيانات
  • Load (التحميل): كتابة البيانات النظيفة في قاعدة البيانات
原始数据(服务器收到的)
id-001 userId: "zhang" add_to_cart ¥2999
id-001 userId: "zhang" add_to_cart ¥2999重复
id-002 user_id: "li" click_buy ¥0
id-003 userId: "wang" pay 1970-01-01时间异常
id-004 user_id: "zhao" click_buy ¥599
ETL 清洗
清洗后(写入数据仓库的)
id-001 user_id: "zhang" add_to_cart ¥2999
id-002 user_id: "li" click_buy ¥0
id-004 user_id: "zhao" click_buy ¥599

💡 المبدأ الأساسي: العمليتان الرئيسيتان في تنظيف البيانات

العملية 1: إزالة التكرار — حذف السجلات المكررة

كما ذكرنا، يعيد SDK إرسال البيانات تلقائيًا عند إعادة الاتصال، مما قد يتسبب في إرسال نفس السجل عدة مرات. كيف نتعرف على المكررات؟

الطريقة بسيطة: عند حزم البيانات في العميل، يُعطى كل سجل معرّف فريد عالمي (يُسمى dedup_id، مثل رقم تتبع الطرد). قبل التخزين، يتحقق الخادم إن كان هذا المعرّف موجودًا سلفًا — إذا كان كذلك، فالسجل مكرر ويُتجاهل.

العملية 2: التحقق وتوحيد التنسيق — إصلاح السجلات غير المنتظمة

التطبيق يُحدَّث باستمرار، وقد يكون لكود التتبع في النسخ المختلفة اختلافات طفيفة. مثلاً:

  • النسخة القديمة تسمي حقل معرّف المستخدم userId، والنسخة الجديدة غيّرته إلى user_id
  • بعض السجلات لها طوابع زمنية غير منطقية (مثل عرض 1970)
  • بعض الحقول لها قيم غير قابلة للتعرف

في هذه الخطوة، يطبق النظام قواعد تحويل: يوحّد أسماء الحقول غير المتسقة، ويتجاهل السجلات ذات الطوابع الزمنية الشاذة، ويُعلّم القيم غير المعروفة كـ unknown.

ملخص هذه الخطوة: بعد إزالة التكرار والتحقق من التنسيق، تُكتب البيانات بشكل نظيف وموحد في مستودع البيانات (قاعدة بيانات متخصصة في تخزين وتحليل كميات كبيرة من البيانات، أشهرها ClickHouse وHive). يمكن للمحللين الاستعلام مباشرة عن هذه البيانات باستخدام SQL والحصول على نتائج تحليل موثوقة.


مراجعة العملية الكاملة

فيما يلي ملخص لعملية التتبع من الجمع إلى التخزين في أربع خطوات:

الخطوةماذا فعلناماذا حصلناما المشكلة المتبقية
1. اختيار مخطط الجمعتحديد كيفية تسجيل أفعال المستخدمالتطبيق أصبح قادرًا على التسجيلتنسيق بيانات المسجّلات غير موحد
2. تصميم تنسيق البياناتتوحيد التنسيق بقالب 4W1Hكل سجل هو JSON قياسيمع كثرة المستخدمين، الإرسال الفردي لا يُطاق
3. النقل والتخزين المؤقتإرسال بالدفعات، تخزين محلي بدون شبكة، طابور عازلالبيانات وصلت بأمان للخادمإعادة المحاولة قد تسبب تكرار البيانات
4. التنظيف والتخزينإزالة التكرار، التحقق، توحيد التنسيق✅ بيانات نظيفة محفوظة في مستودع البيانات

خاتمة

عندما ينقر المستخدم على زر في التطبيق، يبدو الأمر كلحظة عابرة على السطح. لكن خلف الكواليس، بدأت سلسلة بيانات كاملة في العمل:

  1. كود التتبع يلتقط هذه النقرة ويُنشئ سجلاً قياسيًا وفق قالب 4W1H
  2. السجل يُخزَّن مؤقتًا محليًا على الهاتف، وعند تجميع دفعة يُرسل إلى الخادم
  3. الخادم يستقبل بشكل مستقر عبر طابور الرسائل، ثم يمرره لإزالة التكرار والتحقق من التنسيق
  4. أخيرًا، سجل بيانات نظيف ودقيق يُكتب في مستودع البيانات

هذه هي العملية الكاملة لتتبع البيانات. إنها تحوّل أفعال المستخدمين المتفرقة وغير المرئية إلى بيانات مهيكلة قابلة للاستعلام والتحليل. يمكن لمديري المنتجات معرفة أي الميزات يحبها المستخدمون وأين يتخلون عن المنتج؛ ويمكن لفريق العمليات تقييم فعالية الحملات؛ ويمكن للمطورين تحديد المشاكل في أي نسخة ظهرت.

هذا النظام من "الجمع ← النمذجة ← النقل ← التنظيف" هو البنية التحتية الأساسية لاتخاذ القرارات المبنية على البيانات.