Я недавно посчитал, что нашему проекту исполнилось 250 человеко-месяцев. Это почти 21 человеко-год или почти 28 рожденных детей, если бы мы занимались рождением детей (мужики, вы чего? — прим. ред.).
С одной стороны, если речь об одном человеке, это огромное число, лично я 250 месяцев назад был в школе. С другой стороны, если посмотреть на похожий (ладно, относительно похожий) проект, а именно — на групповое фото команды, то можно понять, что 250 человеко-месяцев легко сжигается за один месяц (нам потребовалось 7 лет).
В интернете пишут, что первая версия Minecraft была разработана “буквально за выходные”. Я оставлю эту оценку на совести авторов, просто констатирую факт, что на первую версию было потрачено меньше 250 человеко-месяцев.
Вероятно, вы используете curl. Эта программа есть, без преувеличения, на миллиардах устройств по всему миру, как минимум на двух планетах. Она долгое время разрабатывалась и поддерживалась одним человеком, Даниэлем Стенбергом, и он до сих пор сделал больше половины всех коммитов. Трудозатраты на её разработку по порядку величин сравнимы с трудозатратами на нашем проекте.
Думаю, в качестве примера можно привести и nginx. Первые его версии были результатом работы всего одного человека, и они завоевали мировую популярность.
В общем, за 250 человеко-месяцев вполне можно сделать что-то выдающееся и заметное в масштабах человечества. Но, вероятно, для этого еще и нужно быть выдающейся личностью.
В то же время, в офис одной известной мне не-IT компании каждый день приходят на работу 25 1С разработчиков. Естественно, я не понимаю, что там можно делать таким составом, но компания частная, компания работает далеко не один год и, вероятно, приносит своим владельцам прибыль. И за эту работу они готовы платить своими деньгами, поэтому, без всякого сарказма, мои д’Артаньянские мысли на счет эффективности этой работы не выдерживают проверки практикой.
Давайте разберемся, на что мы потратили эти 250 человеко-месяцев (дальше по тексту — просто месяцев, но держите в уме, что речь не про последовательные отрезки времени). В принципе, ответ на этот вопрос дает картинка для привлечения внимания, но там акцент на том, как мы тратили эти месяцы. А теперь сделаем акцент на том, что мы получили взамен.
“... ан нет, опять опыт”
В моих подсчетах учтено только время команды проекта. Некоторыми вещами, например, бухгалтерией, занимаются другие компании на аутсорсе, их время я не учитывал.
Контекст
Мы делаем PIM-систему. Это такой специализированный инструмент для управления товарами. В интернет-магазинах и на маркетплейсах вы наверняка видели карточки товаров: собранные на одной странице фотографии, характеристики, описание, инструкции для какого-то товара. Они там берутся не из воздуха, за этим стоит человеческий труд.
Чтобы создать карточки товаров (и создавать их регулярно для новых товаров), а потом поддерживать их актуальность, нужны инструменты. Чаще всего, из моего опыта, используются инструменты общего назначения, например Гугл таблицы, или Эксель для характеристик и Гугл диск для картинок. Чуть реже — дорабатываются 1С или Битрикс, туда добавляются сущности для хранения карточек и создаются интерфейсы для работы с этими сущностями, добавляются возможности по массовой загрузке и выгрузке карточек в виде файлов некоторого формата. Встречаются варианты с использованием чего-то разработанного с нуля внутри компании. И последний вариант — использование PIM-системы от стороннего поставщика.
Кроме того, что видит обычный пользователь, у товаров есть и другие атрибуты: штрихкоды для складского учета, вес и габариты упаковки для логистики, классификация в соответствии с определенным государством справочником для взаимодействия с таможней и налоговой, сертификаты, маркетинговые материалы, история заказов, аналоги у конкурентов, результаты ABC и XYZ анализа по важности для выручки или прибыли и так далее.
PIM-система позволяет тратить меньше времени на создание и управление такой информацией, и помогает избежать превращения этого массива данных в аналог папки “Разобрать”. Это с одной стороны. А с другой, внедрение PIM — это время и деньги сейчас ради удобства, экономии и роста потом.
Разработка
Итак, 70 месяцев было потрачено на непосредственно работу с кодом ядра PIM. Под ядром тут я подразумеваю что-то самодостаточное, что может справляться со своей основной функцией — управлением товарами, и делает это управление удобным для пользователей, предоставляет собственный API, но не умеет работать со сторонними системами, например, не умеет отправлять карточки товаров на Озон.
Еще 30 месяцев ушло на упомянутые выше интеграции. Это то, что позволило PIM обмениваться информацией с маркетплейсами, и не только с ними.
16 месяцев потребовалось, чтобы сделать управленческий учет. В двух словах, это функции, которые помогают с анализом, какие товары приносят деньги, а какие — нет, на что деньги тратятся, и принятием решений, что закупать, когда, по какой цене продавать.
Еще 9 месяцев заняла разработка парсеров. Они нужны, чтобы не копировать руками те характеристики, которые можно найти в интернете.
Пока, описывая функции и назначение нашей PIM-системы, я отделывался общими фразами типа “управление большими объемами данных о товарах”. А теперь рассказываю, что на проект был потрачен 21 год рабочего времени. Но абстрактная “возможность управления” — плохая мотивация для того, чтобы тратить время таким образом. За абстрактную “возможность управления” никто не готов платить, а за решение конкретных задач — кто-то, да готов. Давайте разберемся, как именно и в каких ситуациях разработанный нами инструмент экономит время, деньги и другие ресурсы, а в каких — делает что-то, без инструмента практически невозможное, возможным.
Сопоставление товаров
Я уже писал про сопоставление товаров, и про то, как оно реализовано на уровне концепции и кода и зачем нужно. Сейчас расскажу, как время, потраченное нами на разработку, экономит время другим.
Представьте, что вы каждый день получаете информацию об актуальных ценах и наличии товаров на складах от 200 ваших поставщиков. Это компании, у которых вы можете купить товары по оптовым ценам, чтобы потом продать в розницу и на этом заработать. Причем, сначала можно получить заказ на товар, а потом — заказать его у поставщика и доставить покупателю, так работают многие интернет-магазины. Причем, кто-то просто дает ссылку на Гугл таблицу, кто-то присылает утром файл эксель на почту, у кого-то актуальный файл можно скачать только в личном кабинете, другие дают ссылку на csv или xml файл у себя на сайте.
Если ваш рабочий день длится 8 часов, на обработку каждого файла у вас есть 2 минуты и 20 секунд. В каждом файле — от сотни единиц до сотен тысяч записей. По каждому товару вам нужно выбрать лучшее предложение из всех (один и тот же товар может быть у разных поставщиков по существенно разной цене), и исходя из него — посчитать розничную цену. У разных поставщиков один и тот же товар называется по-разному, ВПР, он же VLOOKUP на таких данных не работает. Один человек в такой ситуации не справляется, если процесс опирается на ручную работу, то для обработки такого количества информации требуется 5-10 человек.
Думаю, очевидно, что без программирования или специального инструмента тут не обойтись. Наша система всю описанную работу делает в фоне и почти не требует вмешательства человека. Конечно, нечестно сравнивать руки, вооруженные только экселем, со специализированным инструментом. Но и по сравнению с другими программами, ориентированными на такую работу, у нас получается точнее, гибче, быстрее. Причем, когда речь идет о скорости, разница может составлять от десятков до тысяч раз.
На разработку этого функционала суммарно мы потратили около 20 месяцев. Это был итеративный процесс, сначала сделали достаточно хороший базовый алгоритм, потом, если была необходимость, дорабатывали его под определенные частные случаи. Например, для автомобильных шин и для автомобильных дисков есть специальный код, который разбирает все параметры и строит сопоставление с их учетом.
Карточки товаров
Но работа с ассортиментом не ограничивается ценами. Это раньше можно было выложить файл с названием “Прайс-лист”, а покупатель сам разберется. Теперь нужны характеристики, фото, описания, нужна возможность сравнивать товары и подбирать их по характеристикам. А для этого товары в одной категории должны иметь одинаковое устройство характеристик. Нельзя у одного товара характеристику назвать “Мощность”, а у другого — “Потребляемая мощность”. Нельзя в одном товаре вес измерять в граммах, а в другом — в килограммах.
Это обширная тема для того, чтобы рассказать в двух словах, но, к счастью, об этом есть подробная статья.
Если все же попытаться кратко передать суть, то мы сделали удобные интерфейсы с фильтрами, тегами, подсказками. Что можем заполнить автоматически — заполняем автоматически, для этого сами ищем в интернете фотографии и характеристики товаров, конвертируем единицы измерения, выбираем уникальные изображения хорошего качества. Естественно, делаем это не вручную, это одна из встроенных функций нашей системы. Интегрированный ChatGPT работает над описаниями товаров.
Все это экономит время на работу с карточками.
Например, один и тот же холодильник или телевизор можно купить в разных магазинах, информацию о них в интернете найти легко, тогда на создание одной карточки товара человек потратит в 100 раз меньше времени. Если такой товар особенный, например, на склад закупили сотни одинаковых холодильников, то требования к карточке вырастают, она должна быть максимально подробной и точной, и в таком случае потребуется большее участие человека. Экономия времени будет такой же в абсолютных величинах, но снизится в относительных.
Для товаров, не так широко представленных на рынке, стократного ускорения, конечно, не получится, но все равно эффект окажется заметен: что-то получится найти в интернете, где-то ChatGPT поможет, где-то благодаря фильтрам, интерфейсам и массовым операциям получится быстрее, чем вручную.
В карточках можно настраивать связи между товарами. Например, на странице с принтером можно сразу предложить совместимые картриджи, а шапку — дополнить варежками такой же расцветки. Это увеличивает средний чек.
Если речь про сотни или тысячи товаров, можно обойтись и Гугл таблицами. Когда речь про сотни тысяч или миллионы — эта работа приобретает новое качество. PIM система в данном случае превращает задачу из невозможной в трудную, но возможную. Самый большой каталог, которым наша PIM управляет на данный момент, насчитывает два с половиной миллиона карточек.
Парсеры
Чтобы была возможность автоматически наполнять карточки товаров информацией, нужны исходные данные. Их мы собираем по интернету, для этого пришлось написать парсеры для примерно 400 сайтов. На данный момент они собрали данные о 76 миллионах товаров и обработали 250 миллионов фотографий. На это мы потратили 9 месяцев. Иногда приходится обходить капчи, я подробно писал о том, каким способом это делаем, а код для обхода капч опубликовал на гитхабе.
Интеграции
Во-первых, у нас есть интеграции с крупными поставщиками по API. Так можно узнавать о изменении цен или наличия не через файл, который приходит на почту раз в сутки, а, например, раз в полчаса, если вам требуется такая частота обновления.
Во-вторых, это то, что позволяет стать “одним окном” для работы с разными каналами продаж, и переиспользовать уже сделанную работу. Наполнили информацией карточку товара для сайта — отлично, теперь можем использовать её и для маркетплейсов. Но с нюансами, конечно.
Нюансы заключаются в следующем. У Озона и у Вайлдберрис разные деревья категорий, и они ожидают наполнения разных характеристик. У нас это реализовано как равноправные независимые каталоги, а для переиспользования информации настраиваются потоки данных: что откуда и куда переносить, как конвертировать. Например, можно настроить процесс так, что изменения, сделанные в основном каталоге, транслируются в каталоги маркетплейсов в нашей системе, а оттуда — и на сами маркетплейсы. В итоге получается не самый простой и очевидный процесс, но рабочий. Меня радует то, что эта сложность не искусственная, обусловленная устройством нашей системы, а связана со сложностью реального мира.
Напрямую через API мы умеем обновлять карточки, цены, наличие на Озоне и Вайлдберрис. На Яндекс Маркете и других площадках — частично через API, частично через фиды. Это файлы, сформированные по определенным правилам. Они размещаются так, чтобы быть доступными по https, а ссылка на файл указывается в настройках личного кабинета продавца на площадке. Информация в этих файлах регулярно обновляется, чтобы маркетплейс мог получить актуальные данные.
Кроме маркетплейсов, можно интегрироваться и с другими инструментами, например, маркетинговыми площадками. Там проще, обмен чаще всего делается с помощью фида, а фиды мы генерировать умеем какие угодно, в пространство пользователя вынесен шаблонизатор, и для многих площадок мы написали типичные базовые шаблоны.
Управленческий учет
Раз уж мы интегрировались с маркетплейсами по части работы с карточками товаров, ценами и остатками, то логичным следующим шагом стал анализ финансовых показателей. Мы забираем данные о всех заказах и всех транзакциях, и сопоставляем транзакции с заказами. Кроме этого, нам потребуется информация о себестоимости товаров, настроить её обновление можно разными способами: можно вручную указать для каждого товара, можно загрузить таблицу сразу со всеми значениями можно настроить регулярное автоматическое обновление из Гугл таблиц или учетной системы.
Когда все данные собраны, можно приступать к их анализу. Это можно делать на разных уровнях: от обзора важных показателей (выручки, маржинальности, прибыли и так далее) и их динамики суммарно по всем подключенным кабинетам, до анализа конкретного заказа.
Ниже — пример графиков цены конкретного товара и количества его заказов на одной диаграмме. Видно, что спрос эластичен по цене: изменение цены на 10% приводит к изменению количества заказанных товаров в три раза.
А если мы знаем структуру затрат (нам тут потребуется себестоимость товара), мы сможем рассчитать и предложить такую цену, при которой прибыль за день будет максимальной.
Еще один пример: так соотносятся выручка, затраты на площадке, себестоимость и прибыль (это может быть график для товара, категории, бренда, аккаунта, всех аккаунтов).
Можно и более детально: разбить затраты на площадке на продвижение, комиссии, логистику и так далее.
Все эти и многие другие данные доступны в виде графиков, таблиц, отчетов. Но не обязательно смотреть глазами на график или в таблицу, чтобы понять, что продажи упали, или что маржинальность продаж отрицательная, или что товар приносит хорошую прибыль, но заканчивается на складе. Такие вещи доступны и для автоматического анализа, что мы и сделали. Реализовали порядка 25 таких диагностик, сделали настраиваемую рассылку уведомлений в телеграме, чтобы клиенты могли максимально быстро реагировать на обнаруженные проблемы.
Все это можно сделать и без нашего сервиса. На небольшом объеме данных даже навыки программирования не потребуются, все можно сделать при помощи электронных таблиц (ВПР, он же VLOOKUP — наше всё). На больших — можно импортировать данные в какую-нибудь SQL базу данных, и обработать там. Именно так мы и делали, перед тем, как реализовать все в коде, чтобы понять, что важно, что не важно, и с какими трудностями придется столкнуться. Трудностей нашлось немало, начиная с дублирующихся записей в отчетах и заканчивая тем, что простые подходы работают на полных и финальных данных. Но если говорить про оперативные данные, то на часть товаров себестоимость будет неизвестна, часть заказов будет еще в пути (по ним за услугу логистики и некоторые другие услуги маркетплейс уже списал деньги, а выручка — еще непонятно, будет или нет, товар могут не выкупить, и он поедет обратно). В таком случае ситуация усложняется, а какие-то полезные выводы делать надо, в этом суть управленческого учета — быть оперативным. И с учетом этого всего построить работающий процесс своими силами — долго и дорого. Мы на это потратили 16 месяцев (забегая вперед, поддержание уже построенного процесса в рабочем состоянии тоже требует ресурсов, и немало).
Ценообразование
Раз уж мы что-то анализируем постфактум, что-то в реальном времени, у нас есть интеграции с API маркетплейсов, данные о себестоимости товаров, то логичный следующий шаг — формирование цен на товары с учетом всей этой информации.
Сценарии ценообразования могут быть разными, кому-то важна целевая маржинальность, для кого-то важно поддерживать минимальную розничную цену с учетом всех скидок, которые делает маркетплейс без ведома продавца. Кто-то вообще не имеет дела с маркетплейсами, но должен агрегировать сотни прайсов и выбирать лучшие условия по каждому из товаров, поддерживать актуальные данные о ценах и наличии товаров.
Все эти сценарии поддерживаются нашей PIM системой. Для 80% из применяемых на практике сценариев достаточно визуального конфигуратора, еще 20% потребностей закрывается с помощью встроенного DSL языка (дважды язык, простите).
Другое
Автоматический поиск похожих по параметрам товаров увеличивает конверсию в покупку. Например, пользователь перешел на страницу с товаром из поисковика, а за время, прошедшее с последнего посещения страницы роботом поисковой системы, товар закончился. Тогда вместо сухого сообщения о том, что товара нет в наличии, покупатель увидит список альтернатив.
API дает возможность сторонним системам забрать информацию из PIM. Документированное API с настроенным Swagger (если вы его не используете — попробуйте, рекомендую) — еще и поддерживать документацию в актуальном состоянии, отлаживать вызовы API в браузере, импортировать в Postman одной кнопкой.
Возможность настройки расписания задач позволяет делать что-то в фоне в заданное время или с заданным интервалом. Например, одно из маркетинговых агентств использует инструмент следующим образом. Раз в час система забирает фиды (это специально сформированные xml файлы) клиентов и информацию из Гугл таблиц, где указано, как именно конкретные фиды нужно изменить: какие параметры для каких товаров добавить или изменить, какие картинки заменить и так далее. И на основе объединенных данных формируются новые фиды, и уже они используется, например, для Яндекс Директа. Это позволяет быстро делать изменения, проверять гипотезы, и не вовлекать клиентов в этот процесс. Потому что вовлечение клиента — это дорого и долго. Это все настраивается в пользовательском пространстве с помощью доступных инструментов, мы не дорабатывали код PIM для решения этой задачи. Просто приятный бонус от того, что в систему встроен DSL (это специальный язык для определенной доменной области).
Часть времени была потрачена на эксперименты. Например, мы сделали MVP инструмента для массовой генерации видеообложек для товаров. Сгенерированные видео выглядят примерно так. При этом от пользователя требовался только текст, алгоритмы сами располагают его так, чтобы не перекрывать предметы на фотографии, подбирают читаемые шрифты и видео эффекты.
Но пока это эксперимент, результаты которого мы не знаем как применить. Можете поэкспериментировать с автоматическим размещением текста на картинке на этой странице. Генерация видео пока не доступна в публичном доступе, но я планирую её добавить в обозримом будущем.
Техподдержка
В этот раздел я отнес все то, что потребовалось сделать, чтобы система решала уже заявленные задачи с точки зрения клиента.
Поддержка клиентов
Если мы обещаем гибкое конфигурируемое ценообразование, и оно на самом деле гибкое, конфигурируемое и даже работает, а клиент не разобрался, как его настроить, то заявленная задача не решается. Для клиента эта функция оказывается нерабочей. Тогда списываемся в чате, получается быстро разобраться — отлично, нет — договариваемся созвониться и помочь с настройкой.
На вникание в суть вопросов, ответы в чатах, созвоны и прочее взаимодействие с клиентами по техническим вопросам мы потратили 20 месяцев.
Поддержка интеграций
Первую интеграцию с Озоном мы сделали в 2019 году. Если посмотреть на те методы, которые использовались тогда, и на те методы, которые используются сейчас, то ничего общего мы, скорее всего, не увидим. Изменились версии методов, какие-то из методов объявлены устаревшими и удалены, на смену им пришли новые, часто — с другой логикой работы. Бывает так, что вместо одного вызова метода API в новой версии нужно сделать сотню вызовов, а бывает наоборот, взаимодействие упрощается. В общем, не проходит ни месяца без изменений просто для того, чтобы то, что уже работает, продолжало работать. Обычно Озон на изменения дает два-три месяца, иногда больше.
С Вайлдбериз ситуация аналогичная, постоянно приходится менять что-то, чтобы продолжило работать то, что и так работает. Но в определенном смысле — хуже. Случается и такое, что старая версия метода API уже не работает, а новая — еще не работает. И живите с этим как хотите.
Со всеми интеграциями с внешними системами ситуация обстоит похожим образом: приходится бежать, чтобы оставаться на месте. На такой бег мы потратили год, или 12 месяцев.
Устранение багов
Чтобы не заниматься устранением багов, лучше сразу писать код без багов. Запишите эти простые, но, в то же время, великие слова. Если бы мы вовремя постигли эту мудрость, сэкономили бы 10 месяцев.
Обновление парсеров
Среднее время жизни парсера без обновлений — чуть меньше года. Потом на одних сайтах кардинально меняется стиль и разметка, на других — появляется капча, третьи вместо рендеринга на сервере переходят на рендеринг на клиенте, у четвертых постраничная навигация сменяется бесконечной прокруткой. И так далее, и тому подобное. И в парсеры периодически нужно заглядывать и их чинить. Этот процесс в сумме занял 8 месяцев.
Внедрение
В этот раздел попали те задачи, которые возникают после того, как мы с клиентом подписали договор и до того, как сервис начнет реально решать задачи клиента. Это и перенос данных, и обучение сотрудников работе с системой, и помощь с настройкой для решения задач конкретного клиента, и срочные изменения в коде PIM-системы.
Данные из существующих у клиента систем нужно перенести к нам. В трети случаев это ограничивается загрузкой xml файла формата Яндекс Маркета, который стал стандартом де-факто при обмене информацией о товарах. Еще две трети случаев — это новые форматы, которые преобразуются в промежуточные базы данных, в которых происходит генерация скриптов по вставке напрямую в таблицы нашей структуры. В общем, каждый раз нужно что-то делать заново, и все прошлые разы — это опыт, но не готовые наработки.
А бывает, что от PIM нужна выгрузка определенного формата. Наш конфигуратор выгрузок может многое, но не все. И тогда мы его срочно дорабатываем, чтобы закрыть возникшую потребность.
Продажи
Тут у нас жалкие 20 месяцев, и это провал. По-хорошему, продвижение и продажи должны быть во главе угла, и им должно быть подчинено все остальное. На нашем примере можно увидеть, что случается, когда проектом руководит разработчик, но не предприниматель по своей натуре. Я осознаю, что у нас с этим пунктом проблемы, я стараюсь что-то сделать для исправления ситуации, но пока результатом не очень доволен.
Мы не пользуемся платными инструментами типа Яндекс Директа или рекламной сети того же Яндекса. Попробовали, эффекта не получили.
Зато работают рекомендации клиентов и статьи, в которых мы делимся опытом. Например, статья про способы обхода капч набрала 41 тысячу просмотров, статья про алгоритм нечеткого поиска — 11 тысяч просмотров. Кстати, тогда я писал её по горячим следам, теперь же могу сказать, что три года все просто работает. Аптайм сервиса на данный момент — больше года. Вероятно, кто-то связался с нами после прочтения этих статей. Я спрашиваю (не всегда, чаще забываю), как клиенты нас находят, и часто получаю ответ, что читали статьи на Хабре.
Бизнес-анализ
Кто-то же должен задачи в Трелло добавлять. А до этого — разобраться, какие и, главное, зачем. Сюда же я отнес ежедневные утренние созвоны команды. Мы все вместе разбираемся, что мы будем делать, и зачем мы это будем делать. 18 месяцев.
Административные задачи
При регистрации нужно оформить устав. Потом зарегистрировать компанию. Потом получить электронную подпись. Потом заключать договоры, отправлять счета, подписывать акты. Ну и так далее. Один день в месяц на такие задачи уходит как минимум, в некоторые месяцы — больше. Так и накопилось 8 месяцев.
Документация
Какая документация? Нет такого сектора на диаграмме.
Ну а если серьезно, у нас есть хорошо документированное API. У нас есть хорошо документированный встроенный DSL язык. В случае с языком — это не совсем наша заслуга, мы взяли готовое решение с открытым исходным кодом и хорошей документацией, но нам пришлось описать все наши структуры данных. Есть базовая документация по функциям системы, где написано что-то вроде “чтобы добавить поставщика, перейдите на вкладку “Поставщики” и нажмите кнопку “Создать””. Но это все — частные задачи. К сожалению, у нас на данный момент нет документации, которая бы отвечала на более общий запрос, как настроить систему для решения задачи клиента. Это сложно сделать: вводные разные, задачи разные. Отчасти вместо этого мы занимаемся обучением, отчасти помогаем с настройками, самостоятельно вникая в задачи и бизнес клиентов, отчасти с этим помогает настроенная на типовой базовый процесс демо-версия.
Заключение
Если у вас есть идея сделать свой программный продукт, будьте готовы, что на разработку вы потратите только треть временных ресурсов. Еще треть стоит потратить на продвижение, поиск клиентов, переговоры, продажи. У нас эта доля мала, и я могу только гадать, как бы обстояли дела, будь она больше. Еще треть уйдет на техподдержку, внедрения, административные задачи, документацию. Может оказаться, что к вашему продукту внедрение не применимо, но, думаю, у реальности найдется, чем его заменить.
Чем программный продукт отличается от программы? Тем, что на создание программного продукта нужно потратить в три раза больше времени. У нас получилось в два раза больше, но я бы не ставил это нам в заслугу, скорее, отметил как ошибку, над исправлением которой мы будем работать.