Русский
Русский
English
Статистика
Реклама

Dodoengineering

История архитектуры Dodo IS ранний монолит

01.10.2020 18:11:51 | Автор: admin

Или каждая несчастная компания с монолитом несчастлива по-своему.

Разработка системы Dodo IS началась сразу же, как и бизнес Додо Пиццы в 2011 году. В основе лежала идея полной и тотальной оцифровки бизнес-процессов, причем своими силами, что еще тогда в 2011 году вызывало много вопросов и скептицизма. Но вот уже 9 лет мы идем по такому пути с собственной разработкой, которая начиналась с монолита.

Эта статья ответ на вопросы Зачем переписывать архитектуру и делать такие масштабные и долгие изменения? к предыдущей статье История архитектуры Dodo IS: путь бэкофиса. Начну с того как начиналась разработка Dodo IS, как выглядела изначальная архитектура, как появлялись новые модули, и из-за каких проблем пришлось проводить масштабные изменения.

Серия статей Что такое Dodo IS? расскажет про:

  1. Ранний монолит в Dodo IS (2011-2015 годы). (You are here)

  2. Путь бэкофиса: раздельные базы и шина.

  3. Путь клиентской части: фасад над базой (2016-2017 годы). (In progress)

  4. История настоящих микросервисов. (2018-2019 годы). (In progress)

  5. Законченный распил монолита и стабилизация архитектуры. (In progress)

Изначальная архитектура

В 2011 году архитектура Dodo IS выглядела так:

Первый модуль в архитектуре прием заказа. Бизнес-процесс был такой:

  • клиент звонит в пиццерию;

  • трубку берет менеджер;

  • принимает по телефону заказ;

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

Интерфейс информационной системы выглядел примерно так

Первая версия от октября 2011:

Чуть улучшенная в январе 2012

Ресурсы для разработки первого модуля приема заказа были ограничены. Нужно было делать много, быстро и малым составом. Малый состав это 2 разработчика, которые и заложили фундамент всей будущей системы.

Их первое решение определило дальнейшую судьбу технологического стека:

  • Backend на ASP.NET MVC, язык C#. Разработчики были дотнетчиками, этот стек был им знаком и приятен.

  • Фронтенд на Bootstrap и JQuery: интерфейсы пользователя на самописных стилях и скриптах.

  • База данных MySQL: без затрат на лицензии, простая в использовании.

  • Серверы на Windows Server, потому что .NET тогда мог быть только под Windows (Mono обсуждать не будем).

Физически это все выражалось в дедике у хостера.

Архитектура приложения приема заказа

Тогда уже все говорили о микросервисах, а SOA лет 5 использовалось в крупных проектах, например, WCF вышел в 2006 году. Но тогда выбрали надежное и проверенное решение.

Вот оно.

Asp.Net MVC это Razor, который выдаёт по запросу с формы или от клиента HTML-страницу с рендерингом на сервере. На клиенте уже CSS и JS-скрипты отображают информацию и, по необходимости, выполняют AJAX-запросы через JQuery.

Запросы на сервере попадают в классы *Controller, где в методе происходит обработка и генерация итоговой HTML-страницы. Контроллеры делают запросы на слой логики, называемый *Services. Каждый из сервисов отвечал какому-то аспекту бизнеса:

  • Например, DepartmentStructureService выдавал информацию по пиццериям, по департаментам. Департамент это группа пиццерий под управлением одного франчайзи.

  • ReceivingOrdersService принимал и рассчитывал состав заказа.

  • А SmsService отправлял смс, вызывая API-сервисы по отправке смс.

Сервисы обрабатывали данные из базы, хранили бизнес-логику. В каждом сервисе был один или несколько *Repository с соответствующим названием. В них уже находились запросы к хранимым процедурам в базе и слой мапперов. В хранимках была бизнес-логика, особенно много в тех, которые выдавали отчетные данные. ОРМ не использовался, все полагались на написанный руками sql.

Еще был слой доменной модели и общих классов-хелперов, например, класс Order, хранивший заказ. Там же, в слое, находился хелпер для преобразования текста отображения по выбранной валюте.

Всё это можно представить такой моделью:

Путь заказа

Рассмотрим упрощенный первоначальный путь создания такого заказа.

Изначально сайт был статический. На нем были цены, а сверху номер телефона и надпись Хочешь пиццу звони по номеру и закажи. Для заказа нам нужно реализовать простой flow:

  • Клиент заходит на статический сайт с ценами, выбирает продукты и звонит по номеру, который указан на сайте.

  • Клиент называет продукты, которые хочет добавить в заказ.

  • Называет свой адрес и имя.

  • Оператор принимает заказ.

  • Заказ отображается в интерфейсе принятых заказов.

Все начинается с отображения меню. Залогиненный пользователь-оператор в один момент времени принимает лишь один заказ. Поэтому draft-корзина может храниться в его сессии (сеанс пользователя хранится в памяти). Там объект Cart, в котором продукты и информация о клиенте.

Клиент называет продукт, оператор нажимает на + рядом с продуктом, и на сервер отправляется запрос. По продукту вытаскивается информация из базы и добавляется информация о продукте в корзину.

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

Далее вводим адрес и имя клиента.

При нажатии Создать заказ:

  • Запрос отправляем в OrderController.SaveOrder().

  • Получаем Cart из сессии, там лежат продукты в нужном нам количестве.

  • Дополняем Cart информацией о клиенте и передаем в метод AddOrder класса ReceivingOrderService, где он сохраняется в базу.

  • В базе есть таблицы с заказом, составом заказа, клиентом и они все связаны.

  • Интерфейс отображения заказа идет и вытаскивает последние заказы и отражает их.

Новые модули

Прием заказа был важен и необходим. Нельзя сделать бизнес по продаже пиццы, если нет приема заказа для продажи. Поэтому система начала обрастать функционалом примерно с 2012 по 2015 года. За это время появилось много различных блоков системы, которые я буду называть модулями, в противовес понятию сервиса или продукта.

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

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

Технически модули оформлялись как Area (вот такая идея даже осталась в asp.net core). Там были отдельные файлы для фронтенда, моделей, а также свои классы контроллеров. В итоге система преобразовалась из такой...

в такую:

Некоторые модули реализованы отдельными сайтами(executable project), по причине совсем уже отдельного функционала и частично из-за несколько отдельной, более сфокусированной разработки. Это:

  • Site первая версия сайта dodopizza.ru.

  • Export: выгрузка отчетов из Dodo IS для 1C.

  • Personal личный кабинет сотрудника. Отдельно разрабатывался и имеет свою точку входа и отдельный дизайн.

  • fs проект для хостинга статики. Позже мы ушли от него, переведя всю статику на CDN Akamai.

Остальные же блоки находились в приложении BackOffice.

Пояснение по названиям:

  • Cashier Касса ресторана.

  • ShiftManager интерфейсы для роли Менеджер смены: оперативная статистика по продажам пиццерии, возможность поставить в стоп-лист продукты, изменить заказ.

  • OfficeManager интерфейсы для роли Управляющий пиццерии и Франчайзи. Здесь собраны функции по настройке пиццерии, её бонусных акций, прием и работа с сотрудниками, отчеты.

  • PublicScreens интерфейсы для телевизоров и планшетов, висящих в пиццериях. На телевизорах отображается меню, рекламная информация, статус заказа при выдаче.

Они использовали общий слой сервисов, общий блок доменных классов Dodo.Core, а также общую базу. Иногда еще могли вести по переходам друг к другу. В том числе к общим сервисам ходили и отдельные сайты, вроде dodopizza.ru или personal.dodopizza.ru.

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

Для лучшего понимания масштаба модулей, сделанных в системе, вот схема из 2012 года с планами развития:

К 2015 году всё на схеме и даже больше было в продакшн.

  • Прием заказа перерос в отдельный блок Контакт Центра, где заказ принимается оператором.

  • Появились общедоступные экраны с меню и информацией, висящие в пиццериях.

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

  • Блок доставки стал отдельной Кассой Доставки, где заказ выдавался курьеру, который предварительно встал на смену. Учитывалось его рабочее время для начисления зарплаты.

Параллельно с 2012 по 2015 появилось более 10 разработчиков, открылось 35 пиццерий, развернули систему на Румынию и подготовили к открытию точек в США. Разработчики уже не занимались всеми задачами, а были разделены на команды. каждая специализировалась на своей части системы.

Проблемы

В том числе из-за архитектуры (но не только).

Хаос в базе

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

Но за 4 года разработки в базе оказалось около 600 таблиц, 1500 хранимых процедур, во многих из которых была еще и логика. Увы, хранимые процедуры не приносят особого преимущества при работе с MySQL. Они не кэшируются базой, а хранение в них логики усложняет разработку и отладку. Переиспользование кода тоже затруднено.

На многих таблицах не было подходящих индексов, где-то, наоборот, было очень много индексов, что затрудняло вставку. Надо было модифицировать около 20 таблиц транзакция на создание заказа могла выполняться около 3-5 секунд.

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

К одним и тем же таблицам производились очень разнородные запросы. Особенно страдали популярные таблицы, вроде упоминавшейся таблицы orders или таблицы pizzeria. Они использовались для вывода оперативных интерфейсов на кухне, аналитики. Еще к ним обращался сайт(dodopizza.ru), куда в любой момент времени могло придти внезапно много запросов.

Данные не были агрегированными и много расчетов происходило на лету средствами базы. Это создавало лишние вычисления и дополнительную нагрузку.

Часто код ходил в базу тогда, когда мог этого не делать. Где-то не хватало bulk-операций, где-то надо было бы разнести один запрос на несколько через код, чтобы ускорить и повысить надежность.

Связность и запутанность в коде

Модули, которые должны были отвечать за свой участок бизнеса, не делали этого честно. Некоторые из них имели дублирование по функциям для ролей. Например, локальному маркетологу, который отвечает за маркетинговую активность сети в своем городе, приходилось пользоваться как интерфейсом Админа (для заведения акций), так и интерфейсом Менеджера Офиса (для просмотра влияния акций на бизнес). Конечно, внутри оба модуля использовали один сервис, который работал с с бонусными акциями.

Сервисы (классы в рамках одного монолитного большого проекта) могли вызывать друг друга для обогащения своих данных.

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

Логика была либо в контроллерах, либо в классах сервисов.

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

Сложность большой разработки

Трудности возникли и в самой разработке. Нужно было делать разные блоки системы, причем параллельно. Вместить нужды каждого компонента в единый код становилось все труднее. Было не просто договориться и угодить всем компонентам одновременно. К этому добавлялись ограничения в технологиях, особенно касаемо базы и фронтэнда. Нужно было отказываться от JQuery в сторону высокоуровневых фреймворков, особенно в части клиентских сервисов (сайт).

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

Команды и разработчики, занимающиеся своей областью явно хотели большей самостоятельности для своих сервисов, как в части разработки, так и в части выкатки. Конфликты при мерже, проблемы при релизах. Если для 5 разработчиков эта проблема несущественна, то при 10, а уж тем более при планируемом росте, все стало бы серьёзнее. А а впереди должна была быть разработка мобильного приложения (она стартанула в 2017, а в 2018 было большое падение).

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

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

Как блог Сила ума положил кассы в ресторанах

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

В блоге Сила ума был виджет, который показывал данные по выручке за год всей сети. Виджет обращался к публичному API Dodo, которое предоставляет эти данные. Сейчас эта статистика доступна на http://dodopizzastory.com/. Виджет показывался на каждой странице и делал запросы по таймеру каждые 20 секунд. Запрос уходил в api.dodopizza.ru и запрашивал:

  • количество пиццерий в сети;

  • общую выручку сети с начала года;

  • выручку за сегодня.

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

В эту же таблицу заказов ходили Кассы в ресторанах, выгружали список принятых за сегодня заказов, в неё же добавлялись новые заказы. Кассы делали свои запросы каждые 5 секунд или по обновлению страницы.

Схема выглядела так:

Однажды осенью, Федор Овчинников написал в свой блог длинную и популярную статью. На блог пришло очень много людей и стали внимательно всё читать. Пока каждый из пришедших человек читал статью, виджет с выручкой исправно работал и запрашивал API каждые 20 секунд.

API вызывало хранимую процедуру на расчет суммы всех заказов с начала года по всем пиццериям сети. Агрегация шла по таблице orders, которая очень популярна. В неё же ходят все кассы всех открытых ресторанов на тот момент. Кассы перестали отвечать, заказы не принимались. Ещё они не принимались с сайта, не появлялись на трекере, менеджер смены не мог увидеть их в своем интерфейсе.

Это не единственная история. К осени 2015 года каждую пятницу нагрузка на систему была критическая. Несколько раз мы выключали публичное API, а однажды, нам пришлось даже отключить сайт, потому что уже ничего не помогало. Был даже список сервисов с порядком отключения при серьезных нагрузках.

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

Бурный рост бизнеса

Почему нельзя было сделать сразу хорошо? Достаточно посмотреть на следующие графики.

Также в 2014-2015 было открытие в Румынии и готовилось открытие в США.

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

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

Быстрые решения, которые помогли

Проблемы требовали решения. Условно, решения можно разделить на 2 группы:

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

  • Системные и, поэтому, долгие. Реинжиниринг ряда модулей, разделение монолитной архитектуры на отдельные сервисы (большинство из них вполне не микро, а скорее макросервисы и про это есть доклад Андрея Моревского).

Сухой список быстрых изменений таков:

Scale up мастер базы

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

С 2014 года мы перешли в Azure, на эту тему мы тоже писали еще в то время в статье Как Додо Пицца доставляет пиццу с помощью облака Microsoft Azure. Но после череды увеличений сервера под базу уперлись по стоимости.

Реплики базы на чтение

Реплик для базы сделали две:

ReadReplica для запросов на справочники. Применяется для чтения справочников, типа, города, улицы, пиццерии, продуктов (slowly changed domain), и в тех интерфейсах, где допустима небольшая задержка. Этих реплик было 2, мы обеспечивали их доступность также, как и мастера.

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

Кэши в коде

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

Несколько серверов для бэкэнда

Бэкэнд приложения тоже надо было масштабировать, чтобы выдерживать повышенные нагрузки. Необходимо было сделать из одного iis-сервера кластер. Мы перенесли сессию приложений из памяти на RedisCache, что позволило сделать несколько серверов, стоящих за простым балансировщиком нагрузки с round robin. Сначала использовался тот же Redis, что и для кэшей, потом разнесли на несколько.

В итоге архитектура усложнилась

но часть напряженности удалось снять.

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

Подробнее..

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

17.02.2021 16:08:10 | Автор: admin

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

И мы решили поменять флоу оплаты заказа и сделать его максимально простым именно для таких клиентов.

При оформлении заказа у нас есть два обязательных экрана: для выбора адреса и для выбора способа оплаты.

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

Если вспомнить полученную аналитику и взять в учёт, что большинство клиентов не меняет адрес и просто жмёт Далее, то экран адресов для них выполняет скорее информационную функцию: лишь напоминает, куда мы доставим заказ. При этом требует нажать Далее, чтобы подтвердить предвыбранный адрес.

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

Снова смотрим в аналитику. Часть людей и правда отпадает при переходе с экрана адресов на экран способов оплаты. Причины могут быть разные: начиная от технических и UX-проблем, заканчивая человеческим фактором клиент и правда мог передумать заказывать, могли поменяться планы.

Относим проблему дизайнерам.

Думаем: дизайн и обработка ошибок в приложении

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

Наш дизайнер Паша изучает задачу.Наш дизайнер Паша изучает задачу.

По ходу мы отмечали проблемные места.

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

Автоматические акции. Например, если вы оформляете доставку, то мы дарим вам Додо-набор: пакетик с салфетками, зубочисткой и стикером. Этот или другой акционный подарок добавляется автоматически. А как только условия акции перестают выполняться подарок так же автоматически убирается. Например, если мы добавили вам подарочный Додо-набор, так как вы были на доставке, мы же его и уберём, когда вы переключитесь на самовывоз. В таком случае количество товаров в корзине меняется. А когда меняется количество товаров, может измениться и цена заказа. Ну, если по какой-то причине убрался не подарок, например.

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

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

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

Стало ясно, что чекаут без геолокации делать будет сложно. Ну, точнее, наличие гео решило бы большую часть проблем: актуальное меню, отсутствующие позиции, промокоды.

А требование сделать без геолокации. Потому что её совсем нет, а делать с нуля долго и сложно: это затрагивает не только приложение, но и наш монолит.

Первая мысль

Первая мысль дизайнера Паши воркэраунд: спрашивать адрес, на который делать доставку, в первую очередь. Этакая геологация без доступа к геолокации. Сергей, наш тогдашний CPO, эту идею забрил. Сказал, что это лишний шаг (Серёжа, прости, если мы твои слова переврали). Из-за этого пришлось расписывать больше кейсов, особенно разные ошибочные состояния.

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

Пришлось задвинуть новый чекаут далеко и надолго.

Переключаемся на кастомизируемые комбо

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

Переключаемся на Приложение в ресторане

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

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

Ну, привет, Бриллиантовый Чекаут. Мы возвращаемся к тебе.

Рисуем: 12 макетов на одно и то же

Рисовали мы много и долго: 4 итерации макетов на первом подходе и 8 итераций на втором подходе. Так как Паша не только рисовал, но ещё и много чего обсуждал, то от первого до последнего макета прошло примерно 8 месяцев. И это без учёта переключения на кастомизируемые комбо.

Примеры макетов с разных подходов и итераций.Примеры макетов с разных подходов и итераций.

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

http://personeltest.ru/aways/www.scotthurff.com/posts/how-to-design-for-thumbs-in-the-era-of-huge-screens/https://www.scotthurff.com/posts/how-to-design-for-thumbs-in-the-era-of-huge-screens/

Мы работаем во многих странах и везде свои особенности: где-то есть додо-рубли, где-то нет,где-то есть электронные чеки, где-то нет. А в Британии так вообще город можно сменить на экране оплаты. Все эти проблемы приходилось обдумывать и решать.

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

Разрабатываем и ошибаемся

Мы оценили разработку нового чекаута в 2 месяца, а закончили через 9. И вот почему.

Начали со сложного дизайна

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

Нужно было при пуше экранов внутри чекаута поджимать или растягивать эту шторку так, чтобы всё влезло, но и пустого места не было. На иосе на это ушло несколько недель, а нормально ресайзиться всё это дело так и не успели научить. Решили не тратить ещё больше времени и просто заюзать нативную модалку. А вот на андройде ребята справились и даже написали про это статью Анимация в Android: плавные переходы фрагментов внутри Bottom Sheet.

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

Решение: начинать с простого дизайна и усложнять итеративно. Сели делать задачу, получили рабочую механику вот теперь можно немного закастомайзить дизайн. А потом ещё сильнее. И ещё. А для этого надо привлекать разработчиков с самого раннего этапа отрисовки макетов.

Меняли дизайн на ходу

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

Решение: попробовать затащить прототипы. При планировании закладывать пару дополнительных дней на хоть как-то работающий вариант, который можно посмотреть, потыкать, ощутить.

Переиспользовали код, когда не нужно было

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

Разумеется, там старое непротестированное легаси. Разумеется, туда приходилось вкорячивать ифчики. А потом вообще оказалось, что этот экран строит ещё и вьюмодели для списка пиццерий. А в Москве их 200+ и это нифига не быстро. В конечном итоге поняли, что новый экран со всеми его зависимостями было бы написать быстрее и надежнее: тесты не просто получилось бы написать, так ещё и писать было бы гораздо быстрее.

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

Взяли в команду менторов и новичков

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

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

Решение: не допускать новичков и менторов к разработке фич с горячими дедлайнами. Ну или при планировании закладывать время на онбординг. Кстати, про онбординги у нас тоже есть статья.

Недостаточно точно описывали таски

Один разработчик заболел, его задачи пришлось передать другому. При передаче несколько требований пропустили. А когда таски получили статус Готово готово было не то что нужно. Пришлось переделывать.

Решение: детальнее описывать требования к задачам. В каждой карточке должен быть чеклист того, что надо сделать. За ним надо следить, его надо актуализировать. Ну или конвертировать в отдельные карточки, если чувствуете, что надо ещё подекомпозировать.

Обсуждали одни и те же места по нескольку раз

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

Решение: копить причины принятых решений.

Неправильно оценили сроки

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

Решение: оценивать таски глядя в код. Прямо берём, открываем исходники и смотрим от начала до конца как мы будем делать фичу. Заползаем в самые дальные уголки кода, которые зацепим. Смотрим, как там написан код. Нет ли старых паттернов, от которых мы уже отходим? Покрыто ли это место тестами? Если какого-то кода нет обсуждаем, каким он будет и как подцепится к имеющемуся.

Так дольше, но оценка будет честнее.

Решили сэкономить на тестах

Начали резать скоуп, когда поняли, что не успеваем: минус там, минус тут. Под нож попали и тесты. В итоге иногда что-то отпадало, приходилось чинить. Иногда отпадало снова и снова. Классика.

Из-за то, что чекаут затаскивался за фича-флагом, а между старым и новым есть пересекающиеся места, что-то ломалось и в старом чекауте. Приходилось следить сразу за двумя модулями.

Решение: не отказываться от тестов, даже если сроки горят. Код без тестов легаси. Без тестов ты выигрываешь пару дней/недель сегодня, но проигрываешь месяцы в будущем.

Не пошарили знания

У нас есть CI. И, конечно же, его кто-то поддерживает. Со стороны иоса на тот момент это был я. Но одновременно с этим я занимался и разработкой нового чекаута.

К сожалению, из-за изменений в архитектуре проекта наш CI какое-то время был нестабильным. И это стопало разработку у остальных команд QA не могли получить актуальные сборки и проверить новые фичи или починенные баги.

Поэтому его приходилось чинить. А так как я не успел на тот момент пошарить знания чинить приходилось именно мне, в ущерб разработке чекаута.

Решение: Активнее шарить знания на встречах или во внутренней документации.

Самое главное решение

Не допускать релиза крупных фичей разом, делать всё итеративно.

Так инкремент можно получать гораздо раньше. А не раз в год, как получилось у нас.

Re: Подводим итоги Final_v3

Спустя год разработки наконец-то доталкиваем новый чекаут до релиза. Сначала на Россию, здесь 90% заказов. А потом и на остальные страны, после разных допиливаний: додо-рубли, электронные чеки и прочее, о чем рассказывал выше.

Полезли в аналитику сравнивать конверсию, А ТАМ ТАКОЕ. Цифры просто космические: миллионы посыпались на нас сверху, разработка всего чекаута окупилась буквально за неделю. Потому что конверсия выросла аж на 5%!

А потом поняли, что аналитика кривая. Собрали новую и увидели, что конверсия выросла только на 0,5%. В целом неплохо, но хотелось чуть получше.

Подумали, посовещались, посоветовались и собрали аналитику в третий раз. На этот раз точно, железобетонно и финально: конверсия выросла на 1,5%. В рублях это дополнительные 2 000 000 в неделю.

Работаем над ошибками

БЧ сдан. Возвращаемся к Приложению в Ресторане.

  • Тратим на оценку задачи несколько дней.

  • Декомпозируем до посинения.

  • Постоянно смотрим в код, включаем в оценку время тесты.

  • На аналитику время заложили.

  • И на тестирование тоже.

  • И на возможные баги с прода.

  • И ещё всякого по мелочи.

Составили, в общем, самый настоященский и максимально проработанный роадмап.

И релизнули фичу день в день с планом.

Вот такой вот хеппи енд


Также будет интересно почитать:

Подписывайтесь начат Dodo Engineering, если хотите обсудить эту и другие наши статьи и подходы, а также на каналDodo Engineering, где мы постим всё, что с нами интересного происходит.

А если хочешь присоединиться к нам в Dodo Engineering, то будем рады сейчас у нас открыты вакансииiOS-разработчиков(а ещё для Android, frontend, SRE и других). Присоединяйся, будем рады!

Подробнее..

Зачем и как мы пишем постмортемы по критичным багам

30.04.2021 16:23:36 | Автор: admin

В какой-то момент у нас стало много хотфиксов стабильно больше половины деплоев на проде были хотфиксы или откаты. Мы решили анализировать каждый хотфикс, чтобы понять причины, найти системные закономерности и устранить их, не допуская два раза одних и тех же ошибок. Как говорил Джейсон Стейтем (Стэтхэм? Стэтэм?): Не страшно ошибаться, страшно повторять одну ошибку 2 раза. Ну и мы решили не повторяться. В статье расскажу как мы анализируем хотфиксы и другие критичные проблемы, что у нас получается, а что нет, с какими сложностями столкнулись и как их решали.

Как было раньше

Раньше на проде случались хотфиксы-откаты из-за критичных багов. Мы в QA понимали что нам нужно проводить какую-то ретроспективу по пропущенным багам на прод. Поэтому после каких-то очень проблемных релизов:

  • собирались и обсуждали проблему;

  • звали разработчиков, участвующих в этом релизе;

  • принимали решения (некоторые работают до сих пор).

Основная проблема при таком подходе, что ты не разбираешь каждый хотфикс или откат детально. Ты обращаешь внимание только на очень критичные проблемы. Такая активность не системная.

Когда хотфиксов стало много (примерно половина всех выкладок на прод были хотфиксы) поняли, что этого недостаточно нужно что-то менять. Мы решили попробовать практику написания постмортемов на хотфиксы и откаты.

Что такое постмортем?

Вообще, постмортем это посмертная фотография родственников.

Мы узнали об этой практике у нашей команды Платформы. Они уже с 2018 года ведут постмортемы по всем инцидентам в системе.

Постмортем для примера.Постмортем для примера.

Наши люди даже выступали с этими темами на конференциях.

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

Как начали вести

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

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

Скрин с Kaiten.Скрин с Kaiten.

Чуть поработали и поняли, что у нас есть несколько типов критичных проблем и под каждый из типов создали свой шаблон: некоторые вопросы были актуальны для одного типа, но неактуальны для другого. В итоге получилось 4 типа постмортемов:

  • По хотфиксам на проде.

  • По откатам релизов.

  • По подливкам в релиз когда в релизную ветку подливают фиксы. Иногда на этапе прогона тестов находятся критичные баги. Если бы они попали на прод был бы хотфикс, иначе их бы пофиксили стандартным флоу в следующем релизе.

  • По STL (Stop the Line). Подробнее что это такое можно почитать в статье Stop the line или прокачай свой pipeline, йоу

Пример шаблона для хотфиксов из Kaiten.Пример шаблона для хотфиксов из Kaiten.

Структура и способ ведения

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

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

Авторы постмортема. Знаем к кому идти за подробностями инцидента или с уточняющими вопросами по решению. Наличие авторов постмортема не противоречит принципу написания постмортемов blameless culture. Мы не обвиняем никого в доведении до проблемы, а хотим лишь отобразить участников разбора.

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

Проблемы. Пишем о том, с какими проблемами могли столкнуться наши пользователи. Какую функциональность мы задели, какие непотребства видели наши пользователи. Или что видели мы, если мы заметили проблему раньше пользователей (алерты, подскочившие графики в Grafana).

Потери. В этом блоке пишем влияние на бизнес, сколько задето пиццерий или пользователей, сколько потеряли в деньгах или во времени (это импакт на пользователей).

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

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

Шаблон

Здесь оставлю пример шаблона наших постмортемов без моих комментариев.

## Дата

## Автор

## Проблемы

## Причина

## Последствия для бизнеса

## Предложения по недопущению в будущем

## Как можно было избежать проблемы (представь что у тебя есть машина времени и ты вернулся к моменту, когда ты еще не написал этот код, что можно было сделать, чтобы не было хотфикса)

**Создать картохи на написание _автотеста_ по этой проблеме в своем бэклоге и прикрепи их сюда как дочерние**

**Создать картохи по _недопущению хотфикса_ в будущем в своем бэклоге или бэклоге владельцев компонента и прикрепи их сюда как дочерние**

## Что ещё хочется добавить

**Не забудь поставить теги компонента в котором случилась проблема**

Берите себе, адаптируйте и пользуйтесь.

Сложности и как их решали

С нахрапа не получилось ввести постмортемы и вести их идеально. Вот наш список проблем.

Не заполняли постмортемы. Банально да: поначалу люди ответственные за релиз забывали заполнять постмортемы

Решили проблему добавив в чек-лист релизмена пункт о необходимости заполнения постмортема. Релизмен разработчик отвечающий за выкатку релиза, ротируется после каждого релиза.

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

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

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

Скрин с чек-листа.Скрин с чек-листа.

Не создавали карточки на решение проблем. Мы используем Kaiten и настроили доски так:

  • прикреплённая дочерняя карточка с устранением проблемы берется в работу;

  • постмортем автоматически переезжает в In progress;

  • когда задачу завершают завершается и постмортем.

Это помогает не мониторить исполнение постмортемов.

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

Решения долго берут в работу. Мы все понимаем, что бэклогом владеет продакт и у него есть приоритеты. Мы понимаем, что когда команда берёт техзадачи в спринт, это зависит от множества факторов: понимания продактом важности этих технических задач и последствий (если их не решить), от зрелости самой команды, критичности сервиса и проблемы. Но проблема всё равно болезненная.

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

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

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

Результаты в цифрах

Мы проанализировали постмортемы за пол года, и вот какая картина получается.

  • Треть наших постмортемов не имеют конкретных решений на доработку и недопущение проблем в будущем.

  • Половина наших постмортемовв которых есть конкретные решения ещё не выполнена.

  • 49 дней медианное время жизни постмортема от появления на доске до выполнения (из тех что выполнили и в которых были решения), а среднее 82 дня. Такие различия обусловлены большим разбросом значений. Критичные решения или очень простые решаются достаточно быстро, сложные и не критичные могут долго провисеть в ожидании.

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

Выводы

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

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

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


Что ещё почитать.

Stop the line или прокачай свой pipeline, йоу

Будущее интерактивного дизайна в руках

История Open Source кратко: от калькулятора до миллиардных сделок

Как выйти на китайский рынок с mini-app для WeChat, чтобы не прогореть

Как мы разогнали команду QA, и что из этого получилось

История архитектуры Dodo IS: ранний монолит

Код без тестов легаси

Подписывайтесь начат Dodo Engineering, если хотите обсудить эту и другие наши статьи и подходы, а также на каналDodo Engineering, где мы постим всё, что с нами интересного происходит. А ещё естьгруппа в ВК(ну мало ли).

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru