قياس تأثير الأداء الفعلي للعاملين في مجال تقديم الخدمات

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

تطبيق الويب Google I/O (اختصاره IOWA) هو تطبيق تقدّمي على الويب استفاد من معظم الإمكانات الجديدة التي يوفّرها عاملو الخدمات لتقديم تجربة غنية تشبه التطبيقات للمستخدمين. واستخدَم أيضًا "إحصاءات Google" لتسجيل بيانات الأداء الرئيسية وأنماط الاستخدام من جمهورها الكبير والمتنوّع.

تستكشف دراسة الحالة هذه كيفية استخدام IOWA لخدمة "إحصاءات Google" للإجابة عن أسئلة الأداء الرئيسية وإعداد تقارير عن التأثير الفعلي للعاملين في الخدمات.

البدء بالأسئلة

في أي وقت تقوم فيه بتنفيذ تحليلات في موقع ويب أو تطبيق، من المهم أن تبدأ بتحديد الأسئلة التي تحاول الإجابة عنها من البيانات التي ستجمعها.

في حين كان لدينا العديد من الأسئلة التي أردنا الإجابة عنها، لأغراض دراسة الحالة هذه، دعونا نركز على اثنين من أكثر إثارة للاهتمام.

1. هل يعمل التخزين المؤقت لعامل الخدمة على أداء أفضل من آليات التخزين المؤقت الحالية عبر HTTP والمتاحة في جميع المتصفحات؟

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

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

ولكن هل سيكون هذا الجهد أفضل مما يفعله المتصفّح حاليًا بشكلٍ تلقائي؟ وإذا كان الأمر كذلك، إلى أي مدى؟ 1

2. كيف يؤثر عامل الخدمة في تجربة تحميل الموقع الإلكتروني؟

بمعنى آخر، ما مدى سرعة الشعور بتحميل الموقع الإلكتروني، بصرف النظر عن أوقات التحميل الفعلية التي يتم قياسها بواسطة المقاييس التقليدية لتحميل الصفحات؟

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

اختيار المقياس الصحيح

يتتبع Google Analytics افتراضيًا أوقات تحميل الصفحة (عبر واجهة برمجة تطبيقات وقت التنقل) لنسبة 1% من زوّار الموقع، كما يجعل هذه البيانات متاحة عبر مقاييس مثل متوسط وقت تحميل الصفحة

متوسّط إنّ وقت تحميل الصفحة هو مقياس جيد للإجابة عن سؤالنا الأول، ولكنّه ليس مقياسًا جيدًا للإجابة عن السؤال الثاني. السبب الأول هو أنّ حدث load لا يتطابق بالضرورة مع اللحظة التي يمكن للمستخدم فيها التفاعل مع التطبيق. علاوة على ذلك، قد يشعر تطبيقان أنهما يتم تحميلهما بشكل مختلف تمامًا في وقت التحميل نفسه بالضبط. على سبيل المثال، إذا كان الموقع الإلكتروني يعرض شاشة بداية أو مؤشر تحميل، يبدو أنّه يتم تحميله بسرعة أكبر بكثير مقارنةً بالموقع الذي لا يعرض سوى صفحة فارغة لعدة ثوانٍ.

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

بعد أن قرّرنا الأسئلة التي أردنا الإجابة عنها وتحديد المقاييس التي ستكون مفيدة في الإجابة عنها، حان الوقت لبدء استخدام "إحصاءات Google" وبدء القياس.

تنفيذ التحليلات

إذا كنت قد استخدمت "إحصاءات Google" من قبل، فمن المحتمل أن تكون على دراية بمقتطف تتبُّع JavaScript الذي يُنصح به. تبدو هكذا:

<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>

يبدأ السطر الأول في الرمز البرمجي أعلاه في إعداد دالة ga() عمومية (إذا لم تكن موجودة)، وينزِّل السطر الأخير مكتبة analytics.js بشكل غير متزامن.

يحتوي الجزء الأوسط على هذين السطرين:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

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

بالنسبة إلى IOWA، أردنا تتبع شيئين إضافيين:

  • الوقت المنقضي بين وقت بدء تحميل الصفحة لأول مرة ووقت ظهور وحدات البكسل على الشاشة.
  • ما إذا كان عامل الخدمة يتحكّم في الصفحة أم لا باستخدام هذه المعلومات، يمكننا تقسيم تقاريرنا لمقارنة النتائج مع مشغّل الخدمات أو بدونه.

جارٍ تسجيل الوقت اللازم لطلاء المنتج لأول مرة

وتسجّل بعض المتصفّحات الوقت الدقيق الذي يتم فيه عرض أول بكسل على الشاشة، وتوفِّر هذا الوقت للمطوّرين. وتمنحنا هذه القيمة، مقارنةً بقيمة navigationStart المعروضة عبر واجهة برمجة تطبيقات وقت التنقل، حسابًا دقيقًا للغاية للمدة الزمنية بين الوقت الذي طلب فيه المستخدم الصفحة في البداية ووقت مشاهدته لأول مرة.

كما ذكرتُ سابقًا، يُعتبر الوقت اللازم لتصوير موقعك الإلكتروني مقياسًا مهمًا لقياسه، فهو النقطة الأولى التي يجرِّب فيها المستخدم سرعة تحميل موقعك الإلكتروني. هذا أول انطباع يحصل عليه المستخدمون، ويمكن أن يؤثر انطباع أول جيد في بقية تجربة المستخدم.2

للحصول على أول قيمة لسرعة عرض محتوى الصفحة في المتصفحات التي تعرضها، أنشأنا دالة الأداة getTimeToFirstPaintIfSupported:

function getTimeToFirstPaintIfSupported() {
  // Ignores browsers that don't support the Performance Timing API.
  if (window.performance && window.performance.timing) {
    var navTiming = window.performance.timing;
    var navStart = navTiming.navigationStart;
    var fpTime;

    // If chrome, get first paint time from `chrome.loadTimes`.
    if (window.chrome && window.chrome.loadTimes) {
      fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
    }
    // If IE/Edge, use the prefixed `msFirstPaint` property.
    // See http://msdn.microsoft.com/ff974719
    else if (navTiming.msFirstPaint) {
      fpTime = navTiming.msFirstPaint;
    }

    if (fpTime && navStart) {
      return fpTime - navStart;
    }
  }
}

وبهذا، يمكننا الآن كتابة دالة أخرى تُرسل حدثًا بلا تفاعل مع توفير وقت رسم أول مرة كقيمة له:3

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    ga('send', 'event', {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    });
  }
}

بعد كتابة هاتين الدالتين، تظهر شفرة التتبع على النحو التالي:

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview for the initial pageload.
ga('send', 'pageview');

// Sends an event with the time to first paint data.
sendTimeToFirstPaint();

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

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

يشير الرمز أعلاه إلى firstpaint مرة في "إحصاءات Google"، ولكن هذا النصف فقط هو نصف القصة. ما زلنا بحاجة إلى تتبّع حالة مشغّل الخدمات؛ وإلا فلن نكون قادرين على مقارنة أوقات العرض الأولى لصفحة يتحكم فيها مشغّل الخدمات وصفحة لا يتم التحكم فيها.

تحديد حالة مشغّل الخدمات

لتحديد الحالة الحالية لمشغِّل الخدمات، أنشأنا دالة منفعة تُرجع إحدى القيم الثلاث التالية:

  • خاضع لتحكّم: عامل خدمة يتحكّم في الصفحة. في حالة IOWA، يعني ذلك أيضًا تخزين جميع مواد العرض في ذاكرة التخزين المؤقت وأن الصفحة تعمل بلا اتصال بالإنترنت.
  • متوافق: يدعم المتصفح عامل الخدمة، ولكن عامل الخدمة لا يتحكم في الصفحة بعد. وهذه هي الحالة المتوقّعة للزوّار لأول مرة.
  • غير متوافق: لا يدعم متصفح المستخدم عامل الخدمة.
function getServiceWorkerStatus() {
  if ('serviceWorker' in navigator) {
    return navigator.serviceWorker.controller ? 'controlled' : 'supported';
  } else {
    return 'unsupported';
  }
}

حصلت هذه الدالة على حالة مشغّل الخدمات لنا؛ كانت الخطوة التالية هي ربط هذه الحالة بالبيانات التي كنا نرسلها إلى "إحصاءات Google".

تتبُّع البيانات المخصّصة باستخدام السمات المخصّصة

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

إنّ حالة مشغِّل الخدمة ليست سمة توفّرها "إحصاءات Google" بشكل تلقائي. مع ذلك، تمنحك خدمة "إحصاءات Google" إمكانية إنشاء سمات مخصّصة بنفسك وتحديدها على النحو الذي تريده.

بالنسبة إلى IOWA، أنشأنا بُعدًا مخصصًا باسم حالة مشغّل الخدمات واضبط نطاقه على النتيجة (أي لكل تفاعل).4 يتم تخصيص فهرس فريد لكل مكوّن مخصّص تنشئه في "إحصاءات Google" داخل ذلك الموقع، ويمكنك الرجوع إلى هذه السمة في رمز التتبّع من خلال الفهرس. على سبيل المثال، إذا كان فهرس البُعد الذي أنشأناه للتو يساوي 1، يمكننا تعديل منطقنا على النحو التالي لإرسال حدث firstpaint لتضمين حالة مشغّل الخدمات:

ga('send', 'event', {
  eventCategory: 'Performance',
  eventAction: 'firstpaint',
  // Rounds to the nearest millisecond since
  // event values in Google Analytics must be integers.
  eventValue: Math.round(timeToFirstPaint)
  // Sends this as a non-interaction event,
  // so it doesn't affect bounce rate.
  nonInteraction: true,

  // Sets the current service worker status as the value of
  // `dimension1` for this event.
  dimension1: getServiceWorkerStatus()
});

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

ولتضمين هذه المعلومات في جميع النتائج (مثل جميع مشاهدات الصفحة على الويب والأحداث وما إلى ذلك)، يتم إعداد قيمة البُعد المخصّص في عنصر التتبُّع نفسه، قبل إرسال أي بيانات إلى "إحصاءات Google".

ga('set', 'dimension1', getServiceWorkerStatus());

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

ملاحظة سريعة بشأن مدى وضوح الرمز البرمجي وسهولة قراءته: بما أنّ الأشخاص الآخرين الذين يطّلعون على هذا الرمز قد لا يعرفون ما يشير إليه dimension1، من الأفضل دائمًا إنشاء متغيّر يربط أسماء سمات ذات معنى بالقيم التي ستستخدمها analytics.js.

// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1'
};

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

كما ذكرتُ سابقًا، يسمح لنا إرسال بُعد حالة مشغّل الخدمات مع كل نتيجة باستخدامه عند إعداد التقارير عن أي مقياس.

وكما ترى، فإنّ ما يقرب من% 85 من جميع مشاهدات صفحات IOWA كانت من متصفِّحات تتوافق مع مشغّلي الخدمات.

النتائج: الإجابة عن أسئلتنا

بمجرد أن نبدأ في جمع البيانات للإجابة عن أسئلتنا، يمكننا إعداد تقرير عن تلك البيانات لرؤية النتائج. (ملاحظة: تمثل جميع بيانات "إحصاءات Google" المعروضة هنا عدد الزيارات الفعلية إلى موقع IOWA الإلكتروني خلال الفترة من 16 إلى 22 أيار (مايو) 2016).

كان السؤال الأول الذي طرحناه هو: هل يُجري عامل الخدمة ذاكرة التخزين المؤقت أداءً أفضل من آليات التخزين المؤقت الحالية عبر HTTP المتوفّرة في جميع المتصفّحات؟

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

الأبعاد التي اخترناها هي:

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

للتحكم في احتمال أن تكون العوامل غير المتعلقة بالعاملين المتعلقين بالخدمات تغيّر نتائج وقت التحميل، حصرنا طلب البحث ليتضمّن فقط المتصفّحات التي تتوافق مع مشغّل الخدمات.

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

"...يتم تحميل زيارات تطبيقنا عندما يكون التحكم فيها من قِبل عامل خدمة، أسرع قليلاً من الزيارات غير الخاضعة للرقابة..."

يمكنك الاطّلاع على مزيد من التفاصيل في الجدولَين التاليَين:

ومتوسّط وقت تحميل الصفحة (على الكمبيوتر)
حالة مشغّل الخدمات نوع المستخدِم متوسط وقت تحميل الصفحة (بالميلي ثانية) حجم العينة
تم التحكم فيه الزائر مكرر الزيارة 2568 30860
معلومات معتمَدة الزائر مكرر الزيارة 3612 1289
معلومات معتمَدة زائر جديد 4664 21991
ومتوسّط وقت تحميل الصفحة (الأجهزة الجوّالة)
حالة مشغّل الخدمات نوع المستخدِم متوسط وقت تحميل الصفحة (بالميلي ثانية) حجم العينة
تم التحكم فيه الزائر مكرر الزيارة 3760 8162
معلومات معتمَدة الزائر مكرر الزيارة 4843 676
معلومات معتمَدة زائر جديد 6158 5779

قد تتساءل كيف يُحتمل أن يكون زائر متكرر في حالة غير خاضعة للرقابة، إذا كان متصفحه يدعم عامل الخدمة. هناك بضعة تفسيرات محتملة لذلك:

  • غادر المستخدم الصفحة عند الزيارة الأولى قبل أن يتمكن عامل الخدمة من إنهاء الإعداد.
  • ألغى المستخدم تثبيت مشغّل الخدمات عبر أدوات المطوّرين.

كلتا الحالتين نادرتان نسبيًا. ويمكننا رؤية ذلك في البيانات بالاطّلاع على قيم نموذج تحميل الصفحة في العمود الرابع. لاحظ أن الصفوف الوسطى تحتوي على عينة أصغر بكثير من الصفين الآخرين.

وكان السؤال الثاني هو: كيف يؤثر عامل الخدمة في تجربة تحميل الموقع الإلكتروني؟

للإجابة عن هذا السؤال، أنشأنا تقريرًا مخصّصًا آخر للمقياس متوسط قيمة الحدث وفلتر النتائج لتشمل أحداث firstpaint فقط. استخدمنا المكوّنَين فئة الجهاز وسمة حالة مشغّل الخدمات المخصّصة.

على عكس ما كنت أتوقّعه، كان لعامل الخدمة على الأجهزة الجوّالة تأثير أقل بكثير في الوقت اللازم لسرعة عرض محتوى الصفحة مقارنةً بتأثيره على إجمالي تحميل الصفحة.

"...كان تأثير عامل الخدمة على الأجهزة الجوّالة في وقت عرض محتوى الصفحة أقل بكثير من تأثيره في إجمالي تحميل الصفحة".

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

الحصول على توزيع مقياس في "إحصاءات Google"

للحصول على توزيع firstpaint مرة، نحتاج إلى الوصول إلى النتائج الفردية لكل حدث. لا يتيح لك "إحصاءات Google" تنفيذ ذلك بسهولة.

تتيح لنا "إحصاءات Google" تقسيم أي تقرير حسب البُعد الذي نريده، ولكنها لا تسمح باستخدامه في تقسيم التقرير حسب المقاييس. وهذا لا يعني مستحيلاً، بل يشير فقط إلى أنّه كان علينا تخصيص عملية التنفيذ أكثر قليلاً للحصول على النتيجة المرجوّة.

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

var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1',
  <strong>METRIC_VALUE: 'dimension2'</strong>
};

// ...

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    var fields = {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    }

    <strong>// Sets the event value as a dimension to allow for breaking down the
    // results by individual metric values at reporting time.
    fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>

    ga('send', 'event', fields);
  }
}

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

على سبيل المثال، تم استخدام إعدادات طلب واجهة برمجة التطبيقات التالية لتوزيع قيم firstpaint على جهاز كمبيوتر مكتبي من خلال مشغِّل خدمات غير خاضع للرقابة.

{
  dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
  metrics: [{expression: 'ga:totalEvents'}],
  dimensions: [{name: 'ga:dimension2'}],
  dimensionFilterClauses: [
    {
      operator: 'AND',
      filters: [
        {
          dimensionName: 'ga:eventAction',
          operator: 'EXACT',
          expressions: ['firstpaint']
        },
        {
          dimensionName: 'ga:dimension1',
          operator: 'EXACT',
          expressions: ['supported']
        },
        {
          dimensionName: 'ga:deviceCategory',
          operator: 'EXACT',
          expressions: ['desktop']
        }
      ],
    }
  ],
  orderBys: [
    {
      fieldName: 'ga:dimension2',
      orderType: 'DIMENSION_AS_INTEGER'
    }
  ]
}

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

نتائج استجابة واجهة برمجة التطبيقات (أول خمسة صفوف)
ga:الأبعاد2 ga:totalEvents
4 3
5 2
6 10
7 8
8 10

في ما يلي شرح لمعنى هذه النتائج باللغة الإنجليزية البسيطة:

  • كان هناك 3 أحداث كانت قيمة firstpaint فيها 4 ملي ثانية.
  • كان هناك حدثان كانت قيمة firstpaint فيهما 5 ملي ثانية.
  • كان هناك 10 أحداث كانت قيمة firstpaint فيها 6 ملي ثانية.
  • كان هناك 8 أحداث كانت قيمة firstpaint فيها 7 ملي ثانية.
  • كان هناك 10 أحداث كانت مدة value في firstpaint خلالها 8 ملي ثانية.
  • إلخ

ومن هذه النتائج، يمكننا استقراء القيمة firstpaint لكل حدث على حدة وإنشاء مدرّج تكراري للتوزيع. لقد فعلنا ذلك لكل من الاستعلامات التي قمنا بتشغيلها.

وفي ما يلي شكل التوزيع على أجهزة الكمبيوتر المكتبي مع مشغّل خدمات غير متحكّم (ولكنه متوافق):

وقت توزيع العرض الأول على الكمبيوتر المكتبي (تتوفّر هذه الميزة)

متوسط وقت firstpaint للتوزيع أعلاه هو 912 ملي ثانية.

وشكل هذا المنحنى هو الشكل المعتاد لتوزيعات وقت التحميل. تباين تلك البيانات مع المدرّج التكراري أدناه الذي يوضّح توزيع أحداث الرسم الأولى للزيارات التي كان فيها عامل خدمة يتحكّم في الصفحة.

وقت توزيع العرض الأول على الكمبيوتر المكتبي (يتم التحكّم به)

يُرجى العلم أنّه عندما كان عامل خدمة يتحكّم في الصفحة، تم عرض سرعة عرض الصفحة بشكل شبه فوري لدى العديد من الزائرين، وبلغ متوسطها 583 ملي ثانية.

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

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

وقت توزيع سرعة عرض الصفحة على الكمبيوتر المكتبي

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

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

وكما ترى من عملية التوزيع، حتى مع هذا التأخير المبدئي، عرضت المتصفّحات التي بها مشغّل الخدمات محتوى أسرع من المتصفّحات التي تمرّ عبر الشبكة.

في ما يلي كيفية ظهور المحتوى على الأجهزة الجوّالة:

وقت عرض محتوى الصفحة الأول على الأجهزة الجوّالة

بينما لا تزال لدينا زيادة كبيرة في أوقات الطلاء الأولى شبه الفورية، كان الذيل أكبر وأطول قليلاً. من المحتمل أن يرجع ذلك إلى أنّ بدء سلسلة تعليمات عامل خدمة غير نشِطة على الأجهزة الجوّالة يستغرق وقتًا أطول من الوقت على سطح المكتب. ويفسّر أيضًا سبب عدم ازدياد الفرق بين متوسط وقت firstpaint بالمقدار الذي كنت أتوقعه (تمت مناقشته أعلاه).

"...على الأجهزة الجوّالة، يستغرق بدء سلسلة تعليمات عامل خدمة غير نشِطة وقتًا أطول من الوقت على الكمبيوتر المكتبي".

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

متوسط وقت سرعة العرض (بالملّي ثانية)
حالة مشغّل الخدمات الكمبيوتر المكتبي الأجهزة الجوّالة
تم التحكم فيه 583 1634
متوافقة (لا يمكن التحكّم بها) 912 1933

على الرغم من أن إنشاء هذه الرسوم البيانية للتوزيع استغرق وقتًا وجهدًا أكثر قليلاً من إنشاء تقرير مخصص في Google Analytics، إلا أنها تمنحنا فكرة أفضل بكثير عن كيفية تأثير عاملي الخدمات في أداء موقعنا من المتوسطات وحدها.

تأثير آخر من مشغِّلي الخدمات

بالإضافة إلى تأثير الأداء، يؤثر عاملو الخدمة أيضًا في تجربة المستخدم بعدة طرق أخرى قابلة للقياس باستخدام "إحصاءات Google".

الوصول إلى المحتوى بلا إنترنت

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

يتطلب إرسال البيانات إلى "إحصاءات Google" اتصالاً بالإنترنت، ولكنه لا يتطلب إرسال البيانات في الوقت المحدّد الذي حدث فيه التفاعل. تتيح "إحصاءات Google" إرسال بيانات التفاعل بعد حدوثها من خلال تحديد معادلة الوقت (عبر مَعلمة qt).

على مدار العامَين الماضيَين، كان IOWA يستخدم نصًا برمجيًا لمشغّل الخدمات يرصد نتائج فاشلة في "إحصاءات Google" عندما يكون المستخدم غير متصل بالإنترنت ويعيد تشغيلها لاحقًا باستخدام المَعلمة qt.

لتتبُّع ما إذا كان المستخدِم متصلاً بالإنترنت أو غير متصل بالإنترنت، أنشأنا سمة مخصَّصة باسم على الإنترنت واضبطها على القيمة navigator.onLine، ثم استمعنا إلى الحدثَين online وoffline وعدّلنا السمة وفقًا لذلك.

وللتعرّف على مدى شيوع انقطاع اتصال المستخدم بالإنترنت أثناء استخدام IOWA، أنشأنا شريحة تستهدف المستخدمين من خلال تفاعل واحد على الأقل بلا اتصال بالإنترنت. اتضح أن هذه النسبة كانت حوالي 5٪ من المستخدمين.

الإشعارات الفورية

يتيح مشغّلو الخدمات للمستخدمين إمكانية تلقّي إشعارات فورية. في IOWA، تم إشعار المستخدمين عندما كانت إحدى الجلسات في جدولهم على وشك البدء.

كما هو الحال مع أي شكل من الإشعارات، من المهم إيجاد التوازن بين تقديم قيمة للمستخدم وإزعاجه. للتعرّف بشكل أفضل على التغييرات التي تحدث، من المهم تتبُّع ما إذا كان المستخدمون قد وافقوا على تلقّي هذه الإشعارات، وما إذا كانوا يتفاعلون معها عند وصولهم، وما إذا كان أي مستخدم سبق له الموافقة على هذه الإشعارات تغيير إعداداتها المفضّلة وإيقافها.

في IOWA، أرسلنا فقط الإشعارات المتعلقة بالجدول الزمني المخصّص للمستخدم، أي شيء يمكن للمستخدمين الذين سجّلوا دخولهم فقط إنشاؤه. وأدى ذلك إلى الحدّ من مجموعة المستخدمين الذين يمكنهم تلقّي إشعارات للمستخدمين الذين سجّلوا دخولهم (يتم تتبّعه عبر مكوّن مخصّص يُعرف باسم تسجيل الدخول) والذين كانت متصفّحاتهم توفّر الإشعارات الفورية (يتم تتبّعها من خلال سمة مخصّصة أخرى تُعرف باسم إذن إرسال الإشعارات).

يستند التقرير التالي إلى مقياس المستخدمون والسمة المخصّصة لإذن الإشعارات، والتقسيم حسب المستخدمين الذين سجّلوا الدخول في وقت ما والذين تتوافق متصفّحاتهم مع الإشعارات الفورية.

من الرائع أن ترى أنّ أكثر من نصف المستخدمين الذين سجّلوا الدخول قد اختاروا تلقّي الإشعارات الفورية.

بانرات تثبيت التطبيقات

إذا كان تطبيق ويب تقدّمي يستوفي المعايير ويستخدمه المستخدم بشكل متكرّر، قد يظهر له بانر لتثبيت التطبيق يطلب منه إضافة التطبيق إلى الشاشة الرئيسية.

في IOWA، تتبّعنا عدد مرات عرض هذه الطلبات للمستخدم (وما إذا كان قد تم قبولها) بالرمز التالي:

window.addEventListener('beforeinstallprompt', function(event) {
  // Tracks that the user saw a prompt.
  ga('send', 'event', {
    eventCategory: 'installprompt',
    eventAction: 'fired'
  });

  event.userChoice.then(function(choiceResult) {
    // Tracks the users choice.
    ga('send', 'event', {
      eventCategory: 'installprompt',
      // `choiceResult.outcome` will be 'accepted' or 'dismissed'.
      eventAction: choiceResult.outcome,
      // `choiceResult.platform` will be 'web' or 'android' if the prompt was
      // accepted, or '' if the prompt was dismissed.
      eventLabel: choiceResult.platform
    });
  });
});

من المستخدمين الذين شاهدوا إعلان بانر لتثبيت التطبيق، اختار حوالي 10٪ إضافته إلى الشاشة الرئيسية.

تحسينات التتبع المحتملة (في المرة القادمة)

كانت بيانات التحليلات التي جمعناها من IOWA هذا العام لا تقدر بثمن. لكن الرؤية الثاقبة دائمًا ما تكشف عن الثقوب والفرص لتحسين الأمور في المرة القادمة. بعد الانتهاء من تحليل بيانات هذا العام، إليك أمران أتمنى لو كنّا قد نفّذنا بشكل مختلف هذا الأمر الذي قد يحتاج القرّاء الذين يريدون تنفيذ استراتيجية مشابهة إلى أخذه في الاعتبار:

1. تتبُّع المزيد من الأحداث ذات الصلة بتجربة التحميل

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

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

2. تخزين معرِّف عميل "إحصاءات Google" في IndexedDB

تخزِّن analytics.js بشكلٍ تلقائي حقل معرِّف العميل في ملفات تعريف الارتباط للمتصفِّح. للأسف، لا يمكن للنصوص البرمجية لمشغّل الخدمات الوصول إلى ملفات تعريف الارتباط.

وقد شكل ذلك مشكلة بالنسبة إلينا عندما حاولنا تنفيذ ميزة تتبُّع الإشعارات. وقد أردنا إرسال حدث من مشغّل الخدمات (عبر Measurement Protocol) في كل مرة يتم فيها إرسال إشعار إلى المستخدِم، ثمّ تتبُّع نجاح إعادة التفاعل لذلك الإشعار في حال نقر المستخدم عليه وعاد إلى التطبيق.

على الرغم من أنّنا تمكّنا من تتبُّع نجاح الإشعارات بشكل عام من خلال utm_source مَعلمة الحملة، لم نتمكّن من ربط جلسة معيَّنة لإعادة التفاعل بمستخدم محدّد.

ما كان بإمكاننا فعله للتغلب على هذا القيد هو تخزين معرّف العميل من خلال IndexedDB في رمز التتبع لدينا، ومن ثم يمكن الوصول إلى هذه القيمة من خلال النص البرمجي لعامل الخدمة.

3. السماح لعامل الخدمة بالإبلاغ عن حالة الاتصال بالإنترنت أو عدم الاتصال بالإنترنت

من خلال فحص navigator.onLine، يمكنك معرفة ما إذا كان بإمكان المتصفّح الاتصال بجهاز التوجيه أو الشبكة المحلية، ولكنّه لن يرصد بالضرورة ما إذا كان المستخدم لديه اتصال حقيقي. وبما أنّ النص البرمجي لعامل تشغيل خدمة التحليلات بلا اتصال بالإنترنت أعاد تشغيل النتائج غير الناجحة (بدون تعديلها أو وضع علامة عليها كـ "تعذّر")، لم نرصد استخدامنا بلا اتصال بالإنترنت بشكل كافٍ.

في المستقبل، ينبغي لنا تتبع حالة navigator.onLine إلى جانب ما إذا كان مشغّل الخدمة قد أعاد تشغيل النتيجة بسبب فشل مبدئي في الشبكة. وسيعطينا ذلك صورة أكثر دقة عن الاستخدام الفعلي بلا اتصال بالإنترنت.

ملخص

أظهرت دراسة الحالة هذه أنّ استخدام مشغّل الخدمات قد أدّى إلى تحسين أداء التحميل لتطبيق الويب Google I/O على مجموعة واسعة من المتصفحات والشبكات والأجهزة. أظهرت التجربة أيضًا أنّه عند النظر إلى توزيع بيانات التحميل على مستوى مجموعة كبيرة من المتصفحات والشبكات والأجهزة، تحصل على مزيد من الإحصاءات حول كيفية تعامل هذه التكنولوجيا مع سيناريوهات واقعية، وتكتشف خصائص أداء لم تكن تتوقعها.

وفيما يلي بعض النقاط الرئيسية من دراسة IOWA:

  • في المتوسط، يتم تحميل الصفحات بسرعة أكبر إلى حدٍّ ما عندما كان عامل الخدمة يتحكّم في الصفحة مقارنةً بما كان يتم تحميله من دون مشغّل خدمات، وذلك بالنسبة إلى الزوّار الجدد والمكرّري الزيارة.
  • زيارات الصفحات التي يتحكم فيها مشغّل الخدمات والتي تم تحميلها بشكل فوري تقريبًا للعديد من المستخدمين.
  • عندما كان عاملو الخدمة غير نشطين، استغرق بدء تشغيله بعض الوقت. ومع ذلك، لا يزال أداء عامل الخدمات غير النشط أفضل من عدم وجود عامل خدمات.
  • كان وقت بدء تشغيل مشغّل الخدمات غير النشط أطول على الأجهزة الجوّالة مقارنةً بجهاز سطح المكتب.

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

إذا كنت بصدد تنفيذ عامل الخدمات في تطبيقك، من المهمّ أن تنفِّذ استراتيجية القياس الخاصة بك حتى تتمكّن من تقييم أدائك ومنع التراجع في المستقبل. إذا فعلت ذلك، يُرجى مشاركة نتائجك كي يستفيد الجميع!

الحواشي السفلية

  1. ليس من المنصف مقارنة أداء ذاكرة التخزين المؤقت لمشغِّل الخدمات بأداء موقعنا الإلكتروني الذي يتضمّن ذاكرة التخزين المؤقت لـ HTTP وحدها. لم نقضي الكثير من الوقت في تحسين ذاكرة التخزين المؤقت لـ HTTP نظرًا لأننا كنا نجري تحسينات على IOWA لمشغِّل الخدمات. لو كان الأمر كذلك، لكانت النتائج مختلفة على الأرجح. لمعرفة مزيد من المعلومات حول تحسين موقعك الإلكتروني للتوافق مع ذاكرة التخزين المؤقت لبروتوكول HTTP، يمكنك الاطّلاع على تحسين المحتوى بكفاءة.
  2. بناءً على الطريقة التي يحمِّل بها موقعك الإلكتروني أنماطه ومحتواه، من الممكن أن يتمكّن المتصفّح من الرسم قبل أن يتوفّر المحتوى أو الأنماط. في هذه الحالات، قد تتطابق شاشة firstpaint مع شاشة بيضاء فارغة. إذا استخدمت firstpaint، من المهم التأكّد من توافقه مع نقطة مفيدة أثناء تحميل موارد موقعك الإلكتروني.
  3. من الناحية الفنية، يمكننا إرسال نتيجة توقيت (وهي ليست تفاعل بشكل افتراضي) لتسجيل هذه المعلومات بدلاً من إرسال حدث. وفي الواقع، تمت إضافة نتائج التوقيت إلى Google Analytics خصيصًا لتتبع مقاييس التحميل مثل هذه؛ ومع ذلك، يتم أخذ عينات من نتائج التوقيت بشكلٍ كبير في وقت المعالجة، ولا يمكن استخدام قيمها في الشرائح. وفي ضوء هذه القيود الحالية، تظل الأحداث التي لا تتضمّن تفاعلاً أكثر ملاءمة.
  4. للتعرّف بشكل أفضل على النطاق الذي يجب منحه سمة مخصّصة في "إحصاءات Google"، يُرجى الرجوع إلى قسم السمة المخصّصة في مركز مساعدة "إحصاءات Google". من المهم أيضًا فهم نموذج بيانات "إحصاءات Google"، والذي يتألف من المستخدمين والجلسات والتفاعلات (النتائج). لمعرفة المزيد من المعلومات، يمكنك مشاهدة درس أكاديمية Analytics عن نموذج بيانات "إحصاءات Google".
  5. ولا يأخذ ذلك في الاعتبار الموارد التي تم تحميلها ببطء بعد حدث التحميل.