CoderCastrov logo
CoderCastrov
Программирование

Как мы провели успешный неудачный эксперимент

Как мы провели успешный неудачный эксперимент
просмотров
8 мин чтение
#Программирование

Эксперименты в YipitData

В YipitData мы серьезно относимся к нашим культурным ценностям: мы много говорим о них, мы претворяем их в жизнь и мы хвалим друг друга за их воплощение (часто в компании-широких электронных письмах).

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

Проблемы, которые мы хотели решить

Основные продукты YipitData основаны на общедоступных веб-данных, собираемых с помощью систем парсинга. Самая большая проблема с парсингом заключается в том, что мы не контролируем веб-сайты, и они часто меняются. Наша команда инженеров сосредоточилась на создании этих парсеров как можно более простыми, эффективными, масштабируемыми и легкими в исправлении, чтобы обеспечить надежность парсеров и, в конечном счете, данных.

Важной частью парсинга является извлечение нужных данных со страницы, обычно из HTML или JSON, процесс, который мы называем парсингом. Обычно владелец системы пишет специальный код на Python для парсинга данных с использованием XPaths или другого кода селектора, объединяет данные в структуру данных на Python и сохраняет данные в базе данных. Этот код парсинга обычно изменяется чаще всего, потому что структура страницы и ее данные часто меняются.

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

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

В конечном итоге, мы хотели решить несколько проблем:

  • Сократить обратную связь между владельцем продукта и инженером
  • Избавиться от повторяющегося кода
  • Сократить время на исправление сломанного парсинга

Уменьшение обратной связи

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

Избавление от повторяющегося кода

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

Сокращение времени на исправление ошибок парсинга

Наконец, мы хотели сократить время на исправление ошибок парсинга. Отслеживание было недостаточным, у нас не было отличных инструментов для тестирования логики парсинга, и после исправления логики парсинга обычно требовалось как минимум 20 минут, чтобы код заработал в продакшн. Это ценное время для веб-парсеров - каждая пропущенная секунда может привести к устаревшей или отсутствующей точке данных, что может повлиять на точность нашего продукта и удовлетворенность наших пользователей. Мы надеялись, что, стандартизируя парсинг наших систем, мы сможем построить надежное мониторинговое решение, чтобы сократить время на исправление ошибок парсинга.

Наше решение

Учитывая эти проблемы, мы начали с создания небольшой библиотеки на Python, yparser, для выполнения парсинга. Вместе с yparser мы создали стандартный формат для наших парсеров: JSON с определенными полями. Он выглядел примерно так:

{
  "name": "image",
  "type": "tag",
  "tag": "img",
  "attributes": {
    "src": {
      "type": "attribute",
      "name": "src"
    },
    "width": {
      "type": "attribute",
      "name": "width"
    },
    "height": {
      "type": "attribute",
      "name": "height"
    },
    "alt": {
      "type": "attribute",
      "name": "alt"
    },
    "sizes": {
      "type": "attribute",
      "name": "sizes"
    }
  }
}

yparser брал эту спецификацию JSON и выполнял весь парсинг за вас.

Мы быстро поняли, что будет неприятно для инженеров, а в конечном итоге и для других пользователей, писать все это самостоятельно. Кроме того, рабочий процесс тестирования на реальных веб-страницах был медленным и муторным. В этот момент мы решили работать над веб-приложением Parse Central, чтобы создавать и тестировать эти парсеры.

Вот пример парсера на Parse Central (который со временем развивался и получил много опций, таких как "режим текста", "пользовательские" поля и самое интересное - автозаполнение всего парсера из JSON):

И разобранные результаты - вывод парсера - который обновлялся интерактивно при добавлении "правил" парсинга:

Parse Central был разработан для:

  • Создания и сохранения парсеров
  • Возможности интерактивного тестирования парсеров на веб-страницах
  • Возможности развертывания парсеров без изменения кода (с помощью yparser)
  • Обмена парсерами между аналитиками (которые обычно определяли имена полей и/или логику парсинга) и инженерами (которые интегрировали парсеры в свои системы скрапинга веб-страниц)

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

На этом этапе может показаться, что этот проект был успешным! Но примерно в это время внешние изменения заставили нас задуматься о завершении этого эксперимента.

Завершение эксперимента

Два внешних изменения заставили нас пересмотреть это решение.

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

  • Чем дольше занимает перенос кода для парсинга из разработки в продакшн, тем сложнее вносить изменения
  • Написание кода для определения таблиц является трудоемким и необязательным
  • Обратная связь между инженером и владельцем продукта действительно замедляет разработку продукта

В Readypipe мы решили включить возможность программирования в JupyterLab (великолепный проект с открытым исходным кодом, который позволяет редактировать код в веб-интерфейсе, использовать Jupyter-ноутбуки, терминалы и многое другое) и сократить процесс развертывания до одной кнопки. Сразу же это решило проблему "времени на исправление сломанного парсера", поскольку владелец системы мог перейти к ноутбуку, изменить сломанный код и нажать "Развернуть", чтобы его новый код заработал в течение 1 или 2 минут, гораздо быстрее, чем раньше.

Кроме того, мы устранили необходимость в схемах таблиц. Определение схем таблиц было основным источником дублирования кода и разочарования, которые наши инструменты для парсинга пытались решить, но вместо этого они были решены Readypipe.

Благодаря этим функциям Readypipe также сократил обратную связь между командой продукта и инженерами. Еще одно важное решение сократило ее еще больше: мы решили предоставить команде продукта полное владение своими системами парсинга. Это решение сделало платформу Readypipe гораздо более простым и мощным инструментом для изменения логики парсинга - все можно было сделать в одном месте человеком, владеющим проектом.

Из-за этих решений мы в конечном итоге решили прекратить использование yparser и Parse Central. Но это был успешный эксперимент, потому что мы многое узнали и в конечном итоге использовали наши знания для решения тех же проблем более простым способом.

Что мы узнали

Мы узнали несколько вещей, которые мы могли бы сделать в будущем, чтобы сделать эксперименты быстрее и проще:

  • Установить временные рамки для измерения успеха
  • Принимать обратимые решения
  • Проверять предположения без создания излишнего количества
  • Четко называть инструменты

Установить временные рамки для измерения успеха

Мы провели этот эксперимент в течение примерно года, с инженерами, такими как я, работающими над ним на неполный рабочий день. Для некоторых экспериментов это может быть хорошим временным рамком для измерения успеха. Однако я думаю, что мы могли бы установить контрольные точки для себя, возможно, каждый месяц или квартал, чтобы решить, был ли он успешным и стоит ли продолжать, или стоит прекратить работу над ним.

Когда мы приняли решение завершить эксперимент по парсингу, у нас возникла проблема: мы изменили код многих наших проектов, чтобы использовать новые инструменты. Я не подумал о том, что нам придется откатываться.

К счастью, несколько других членов команды (привет Анжели Филип и Джеймс Фарнер!) придумали и реализовали простое решение: написать скрипт для преобразования кода из новых инструментов (которые требовали дополнительную библиотеку) в код на языке Python (который этого не требовал), понятный для любого разработчика.

В нашем случае мы не потратили слишком много времени на откат эксперимента, но я думаю, что мы могли бы сэкономить некоторое время и снизить уровень стресса, потратив час-два в начале, чтобы обдумать, как мы могли бы это сделать. Я думаю, что это также ускорило бы процесс принятия изменений - по моим наблюдениям, я гораздо склоннее внести изменение, которое легко откатить.

Мы начали этот эксперимент с создания yparser, а затем быстро создали Parse Central. Взглянув в прошлое, мы могли бы достичь успеха быстрее, составив список гипотез, которые мы хотели проверить, и проверить их, не создавая слишком много.

Например: мы могли бы работать с одной парой владелец продукта и инженер, чтобы переработать их код парсинга для одного парсера, чтобы он соответствовал тому же интерфейсу, который мы создали с помощью yparser и Parse Central, не создавая их на самом деле. Затем мы могли бы позволить владельцу продукта написать более простой код парсинга и провести интервью с этой парой, чтобы проверить, уменьшилось ли общее трение и время, затраченное на это.

По нашему опыту, создание чего-либо имеет большие затраты по сравнению с созданием ничего, и мы, вероятно, могли бы проверить и усовершенствовать наш подход, не создавая ничего (вначале).

Четко называйте инструменты

Названия инструментов, yparser и Parse Central, были недостаточно информативными (и я полностью несу за это ответственность!). Одним из главных уроков, которые я извлек из этого эксперимента, является то, что ясное и запоминающееся название могло бы значительно снизить сопротивление в принятии пользователей. Я часто приходилось повторно объяснять, что делает каждый инструмент, что является хорошим показателем непонятности названий.

Заключение

Хотя мы отклонились от нашего первоначального подхода, я считаю, что этот эксперимент был очень успешным. Помимо вышеупомянутых техник, которые мы изучили, команда проекта многое узнала о разработке библиотек, управлении продуктом, а также о разработке веб-приложений на стороне сервера и клиента (включая современные фреймворки, такие как React и Redux).

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

Благодарности

Благодарность Хуго Лопесу Таваресу (https://twitter.com/hltbra) за его тщательный и продуманный обзор и предложения, чтобы сделать это намного лучше.