TG Telegram Group & Channel
Будни разработчика | United States America (US)
Create: Update:

#баг дня

Преамбула

Некий сервис, назовём его Doodle Lampolytics, заставил всех своих клиентов переползти с модели подсчёта просмотров страниц на модель подсчёта событий.

Суть проблемы сервиса очевидна: постраничная модель слабо подходила для серьёзной аналитики данных в веб-приложениях. Даже элементарные лендинги стали гораздо сложнее, чем просто переходы по ссылкам.

И если раньше мы в нагрузку к «просмотру» передавали так называемые индивидуальные размерности и метрики, привязанные к сессии, то теперь — каждое событие может нести индивидуальный их набор.

Не в последнюю очередь это связано с ужесточением запретов на слежку за посетителями сайтов.

Поскольку в типичном проекте зачастую присутствует не одна сотня событий/страниц, то переезд сопровождается знатным перетряхиванием всей аналитики.

Суть

Суд да дело, приходим мы к идее передачи события с неким контекстом:


trackEvent('event_name', context) {}

В одном из постов выше я уже показывал, что этот самый контекст (context) обогащает собой общие для всех событий параметры, превращая событийную модель в некое подобие сессионной.

Передаём туда, например, productId и orderId — и получаем трекинг истории конкретного продукта или заказа. Удобно, когда продукт сильно кастомизированный. Можно накинуть туда optionId и следить, какие продукты какими опциями нашпиговывают.

Таким образом, мы отсылаем объекты вида:

productId,
optionId,
orderId,
locale,
}


Потом объект из camelCase конвертируется в snake_case, как того требует документация, и дёргается некий API. Запомните этот момент.

И всё, поехали в продакшен. События уходят, счастье. Заодно, те же самые события, за некоторым исключением, можно пихать в сервисы вроде Sentry.

И всё бы ничего, но интерфейс Doodle Lampolytics настолько проклят, что оказалось намного проще выгружать данные оттуда сразу в Doodle LargeQuery и SQL-ем их запрашивать.

Но в какой-то момент времени мне это радикально надоело. Мне нравилась простота старого интерфейса, и я решил разобраться в новом. Проблема была в том, что я там не мог найти не только половину событий, но и их параметры.

Я почитал документацию, нашёл где создавать свои размерности и метрики на основе передаваемых параметров — в админке — захожу туда и наблюдаю следующую картину:

product_ıd,
option_id,
option_ıd

— Какого хера?! — заорал я, я же был в офисе.

Но параметры с ı вместо i исчислялись десятками, в то время как остальные — десятками тысяч. И я зачем-то успокоился. Подумал, что это косяк ламполитики, с которым можно разобраться попозже.

Но сегодня я зашёл в наш прекрасный чат, зачем-то ткнул в аватарку одного из подписчиков и увидел у него в истории некую песню с названием Bakı.

И тут до меня резко дошло, какой я идиот.

Прежде чем читать дальше, вы можете посмотреть на код функции, которой мы преобразуем camelCase в snake_case: https://github.com/jonschlinkert/snakecase/blob/master/index.js

Особо внимательные, наверное, уже догадались, в чём проблема. А ведь мы даже тесты написали.

Поскольку не все пройдут по ссылке, я приведу кусочек:

const lowercase = (input = '', options) => input.toLocaleLowerCase(options?.locale);


Ничего не смущает? Я подожду.

...

Да, правильно. Если забыть передать локаль (язык клиента, сервера в нашем случае), то будет взята переменная среды.

И для кого-то из наших клиентов в этой переменной оказался турецкий (или узбекский) язык.

В которых нет буквы i, вместо неё — ı.

Вы все правильно поняли, мы не полностью контролируем среду выполнения. Это так называемый Doodle AppsScript. Он исполняется на языке, в котором открыт офисный инструмент посетителя.

Естественно, мы локаль передать забыли. Хороший вопрос, почему мы вообще не проверили это поведение изначально... но тут как есть.

Стыдно? Стыдно. Зря я винил Doodle Lampolytics.

#бородач

#баг дня

Преамбула

Некий сервис, назовём его Doodle Lampolytics, заставил всех своих клиентов переползти с модели подсчёта просмотров страниц на модель подсчёта событий.

Суть проблемы сервиса очевидна: постраничная модель слабо подходила для серьёзной аналитики данных в веб-приложениях. Даже элементарные лендинги стали гораздо сложнее, чем просто переходы по ссылкам.

И если раньше мы в нагрузку к «просмотру» передавали так называемые индивидуальные размерности и метрики, привязанные к сессии, то теперь — каждое событие может нести индивидуальный их набор.

Не в последнюю очередь это связано с ужесточением запретов на слежку за посетителями сайтов.

Поскольку в типичном проекте зачастую присутствует не одна сотня событий/страниц, то переезд сопровождается знатным перетряхиванием всей аналитики.

Суть

Суд да дело, приходим мы к идее передачи события с неким контекстом:

trackEvent('event_name', context) {}

В одном из постов выше я уже показывал, что этот самый контекст (context) обогащает собой общие для всех событий параметры, превращая событийную модель в некое подобие сессионной.

Передаём туда, например, productId и orderId — и получаем трекинг истории конкретного продукта или заказа. Удобно, когда продукт сильно кастомизированный. Можно накинуть туда optionId и следить, какие продукты какими опциями нашпиговывают.

Таким образом, мы отсылаем объекты вида:

productId,
optionId,
orderId,
locale,
}


Потом объект из camelCase конвертируется в snake_case, как того требует документация, и дёргается некий API. Запомните этот момент.

И всё, поехали в продакшен. События уходят, счастье. Заодно, те же самые события, за некоторым исключением, можно пихать в сервисы вроде Sentry.

И всё бы ничего, но интерфейс Doodle Lampolytics настолько проклят, что оказалось намного проще выгружать данные оттуда сразу в Doodle LargeQuery и SQL-ем их запрашивать.

Но в какой-то момент времени мне это радикально надоело. Мне нравилась простота старого интерфейса, и я решил разобраться в новом. Проблема была в том, что я там не мог найти не только половину событий, но и их параметры.

Я почитал документацию, нашёл где создавать свои размерности и метрики на основе передаваемых параметров — в админке — захожу туда и наблюдаю следующую картину:

product_ıd,
option_id,
option_ıd

— Какого хера?! — заорал я, я же был в офисе.

Но параметры с ı вместо i исчислялись десятками, в то время как остальные — десятками тысяч. И я зачем-то успокоился. Подумал, что это косяк ламполитики, с которым можно разобраться попозже.

Но сегодня я зашёл в наш прекрасный чат, зачем-то ткнул в аватарку одного из подписчиков и увидел у него в истории некую песню с названием Bakı.

И тут до меня резко дошло, какой я идиот.

Прежде чем читать дальше, вы можете посмотреть на код функции, которой мы преобразуем camelCase в snake_case: https://github.com/jonschlinkert/snakecase/blob/master/index.js

Особо внимательные, наверное, уже догадались, в чём проблема. А ведь мы даже тесты написали.

Поскольку не все пройдут по ссылке, я приведу кусочек:

const lowercase = (input = '', options) => input.toLocaleLowerCase(options?.locale);


Ничего не смущает? Я подожду.

...

Да, правильно. Если забыть передать локаль (язык клиента, сервера в нашем случае), то будет взята переменная среды.

И для кого-то из наших клиентов в этой переменной оказался турецкий (или узбекский) язык.

В которых нет буквы i, вместо неё — ı.

Вы все правильно поняли, мы не полностью контролируем среду выполнения. Это так называемый Doodle AppsScript. Он исполняется на языке, в котором открыт офисный инструмент посетителя.

Естественно, мы локаль передать забыли. Хороший вопрос, почему мы вообще не проверили это поведение изначально... но тут как есть.

Стыдно? Стыдно. Зря я винил Doodle Lampolytics.

#бородач


>>Click here to continue<<

Будни разработчика




Share with your best friend
VIEW MORE

United States America Popular Telegram Group (US)