Чёрный экран смерти в Тяжеловато, отчёт об инциденте

25 ноября в 9:10 по Московскому времени вышло обновление приложения Тяжеловато для iOS под версией 1.2.

Релиз привёл к поломке, из‑за которой пользователи в течение полутора суток не могли пользоваться приложением. Приложение открывалось на телефонах, но показывало чёрный экран и не реагировало на жесты и перезагрузку.

Устранить проблему полностью у нас не получилось.

26 ноября в 9:05 было подготовлено обновление с частичным исправлением.
В 19:42 оно стало доступно пользователям в магазине.

Предпосылки

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

Для сохранения веб‑версии офлайн на телефоны пользователей мы использовали AppCache. Когда появились оболочки, кодовая база у веб‑версии и версий для магазинов осталась одна. В одной из первых версий мы допустили ошибку — AppCache‑манифест попал в сборку для магазинов по недосмотру.

Мы удалили AppCache‑манифест и ссылки на него в патч‑обновлении, следовавшем сразу после первой версии.

Недавнее обновление веб‑версии и перевод её с AppCache на ServiceWorker прошли гладко. В обновлении для Android «чёрных экранов смерти» также не появлялось. Тестовая сборка приложения в TestFlight и переход на ней между версиями также не показывали подобных проблем.

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

Хронология и анализ

25 ноября в 9:10 по Московскому времени мы запаблишили обновление в AppStore. Обновление должно было использовать старую кодовую базу, а после нажатия кнопки «Сохранить бюджет» — обновить ядро приложения и перейти на новую.

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

В 9:33 мы сделали первое предположение о причине проблемы. Гипотеза заключалась в особенностях работы закэшированных ресурсов, и том, что после обновления мы отказались от использования AppCache, но неправильно очистили кэши после первого обновления.

В 10:06 после разговора с пользователем, который непосредственно пострадал от последствий, гипотеза подтвердилась. Мы начали думать над тем, как исправить ситуацию. Почистить кэши принудительно мы могли только с помощью нативной оболочки.

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

К 20:21 исправление было протестировано на разных версиях iOS и под разными устройствами. Проблема, казалось, была решена и подготовили обновление к релизу в AppStore.

26 ноября в 0:37 после более тщательной проверки выяснилось, что обновление всё‑таки проблему не решает. Принудительное очищение кэшей в оболочке срабатывало не стабильно.

Даные пользователей всё ещё были в сохранности на устройствах, отображались в виджете, но использовать их программно не представлялось возможным.

В 8:43 мы решили больше не рисковать и помочь пользователям обновить приложение вручную.

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

Инструкция «Что делать дальше»
Экран позора — инструкция «Что делать дальше»

В 9:05 обновление было готово к релизу.

В 11:17 исправление было отправлено в магазин.

В 18:02 приложение прошло ревью магазина.

В 19:47 исправление стало доступно пользователям.

В 19:51 появилось первое сообщение от пользователей, что чёрный экран смерти пропал.

Текущий статус

Свежая версия работает в штатном режиме.

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

Выводы и работа над ошибками

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

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

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

Также ошибкой было считать, что обновление не содержало “breaking changes”. По принципу «Сделать всё за пользователя» переход между версиями технической базы я решил сделать плавным и незаметным.

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

Как и зачем мы переписали Тяжеловато на Тайпскрипт

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

Почему поддерживать код стало дорого

Было несколько причин.

Не было тестов

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

Не было нормальной архитектуры

Приложение, я напомню, я написал за 2 недели на коленке, там было не до архитектуры. (Ох уж этот дух стартапа!) По‑хорошему, после запуска надо было взять пару недель и отрефакторить там всё хорошенько, но что‑то (всё?) пошло не так.

Не было документации

Которая бы напомнила, что и как работает, и почему именно так. Казалось бы приложеньице маленькое, что там помнить‑то, но нет! Как хранятся даты?.. Это поле стейта за что отвечало? Так, это‑то с чем связано? Господи, а это что ещё за хрень? И прочее‑прочее‑прочее.

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

И вот в 2019 году — случилось. Мне бомбануло окончательно, и я начал думать, как это можно изменить.

Как это можно было изменить

Мне было понятно, что если я начну исправлять ситуацию, меня будут преследовать две мысли.

Я это уже делал. Зачем тратить силы на то, что уже сделано?

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

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

Поуправлять разработкой — это передать опыт, попробовать посмотреть на процесс шире, выйти в надсистему. У меня как раз на примете было два человека, кто хотел и мог бы помочь: Виктор Дёмин и Фёдор Кузнецов. Собственно, с ними мы и затеяли весь этот карнавал.

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

Не навреди!

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

То есть, нельзя было пофлексить что‑то, что уже работало. Нельзя было выпилить фичу просто так, на то должна быть веская причина. И, разумеется, нельзя было просрать пользовательские данные. (Если вдруг что‑то пошло не так, напишите, пожалуйста, на support@fuckgrechka.ru.)

Всё это грозило парализовать проект, потому что он начал бы казаться слишком большим. Мы с ребятами решили не «упарываться по‑стартаперски», а дать себе бесконечное количество времени. Вот прямо сколько нужно, чтобы написать нормально, столько и берём. Торопиться — запрещено.

Дальше оставалось определить стек и технические ограничения.

Стек и технические ограничения

От Реакта уходить не хотелось. С Ангуляром я так и не подружился, а Вью мне почему‑то казался всё ещё сыроватым. Палец отрезать не стали. Оставили Реакт.

Одним из технических ограничений «со звёздочкой» было минимальное количество зависимостей и размер бандла. Вторым — отсутствие классов: у нас только функциональные компоненты.

Второе действительно заставляет думать про отделение бизнес‑логики от административной. Хуки помогли не размазывать логику по жизненному циклу компонентов, а собрать её в одной функции — SRP, все дела.

Последним (и по совместительству определяющим ход разработки) ограничением был выбор между двумя стульями: JS или TS. Сейчас расскажу, почему выбрали Тайпскрипт.

Почему выбрали Тайпскрипт

Мне хотелось нормальных типов, а не 0 !== '0' и вот этого всего. Хотелось проектировать, как нормальный человек, а не писать тонны jsdoc к каждой функции. Хотелось, чтобы код сам говорил, что он делает, а не прятался за комментариями, которые один хрен устареют и потом сиди‑думай, чему верить. В Тайпскрипте всё это в какой‑то мере есть.

Типы

Да, присвоить переменной типа string значение типа number уже не выйдет — и это прекрасно! Потому что за пределами классической песочницы‑туду‑листа, я буду путать не string и number, а структуры данных и сущности. И если редактор мне подсказывает: «дорогой, у тебя здесь должен быть просто Record, а не Spend», то я готов писать хоть на C#.

Автоматическая документация

Идеальная документация — это та, которой нет, а её функция выполняется. Типы, интерфейсы и сигнатуры функций — это и есть такая документация.

Мы, люди, пользуемся именами, чтобы ссылаться на явления и сущности — нам так удобнее думать. Когда сущности в коде названы в соответствии с предметной областью, код читать становится проще.

Ещё Тайпскрипт позволяет использовать тип‑алиасы для примитивов. Например, DayStartTimeStamp — тип, который описывает временную метку в UTC, отсылающую к началу определённого дня.

Это алиас для обычного number, просто он назван понятно. Я мог быть указать где‑то в комментарии, что startDate указывается в миллисекундах по UTC… но если у меня есть возможность указать это прямо в коде — то я лучше так и сделаю.

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

А вот так эта функция потом используется:

Понимать такой код потом получается быстрее и менее напряжно.

Архитектура

А этот параграф — ода интерфейсам. Если вы однажды упоролись по SOLID, то обратной дороги уже нет, проектировать систему без абстракций становится больно.

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

Тесты и рефакторинг

Для разработки мы выбрали методологию TDD. Здесь Тайпскрит тоже пришёлся кстати, потому что имея типы и интерфейсы проще создавать (или генерировать, кому как больше нравится) стабы и моки.

В рефакторинге же самое кайфовое — использовать встроенные инструменты IDE: rename symbol, extract function и прочее. Мне не нужно беспокоиться, переименовал ли я все сущности в проекте — об этом позаботится IDE. Моё дело — подобрать правильное название, дальше — пусть потеют роботы.

Минусы

Самый жирный минус Тайпскрипта — он требует времени. Много. Дополнительного. Времени.

Оно будет уходить на то, чтобы покрыть функции и методы типами, привести в соответствие с типами все аргументы, понять, почему какой‑то тип не работает для метода из сторонней библиотеки. (Здесь шутка про «нельзя просто так взять и написать быстрый черновик функции, не используя any».)

Второй минус, чуть поменьше, — не у каждой библиотеки есть описание для Тайпскрипта в DefinitelyTyped. Основные решения там есть, конечно, но для менее известных библиотек описаний может не быть. Например, для clsx его не было.

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

Окей‑окей, а когда обновление‑то?

А оно в продакшене уже :–)

  • Если вы пользуетесь веб‑версией, то скорее всего, приложение на телефоне обновилось само.
  • Обновление для Android появилось в магазине пару недель назад.
  • Обновление для iOS появится совсем скоро.

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

Ссылки

О приложении:

Скачать БЕЗ РЕГИСТРАЦИИ И СМС:

Крутые ребята:

Хвастаюсь книгами:

Всякое‑техническое:

Немного о Солидбуке

Мы с Артёмом Самофаловым сделали книгу об ООП. Для нетерпиливых — сразу ссылка.

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

Объектно‑ориентированное программирование — старо как мир, по нему есть куча книг, но они толстые и заумные. Статьи о нём либо слишком академические, либо слишком простые и не покрывают сложных проблем, которые нам интересны. Источников на русском языке вообще раз, два и хабр.

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

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

Если книга вам зашла, пошарьте её в соцсетях и блогах или полайкайте на гитхабе. Мы будем благодарны! А если эта книга или другие статьи‑проекты‑что‑то‑ещё вам очень‑очень зашли, то вы можете поддержать нас на Патреоне.

Как я делал торговую площадку. Часть 2

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

Технолог тоже дизайнер

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

В разработке неизбежно настаёт момент, когда макеты перестают работать: поменялись бизнес‑требования, появились новые технические ограничения, мы что‑то не учли в дизайне, на устройстве работает всё совсем не так, как хотели, сроки горят, надо упрощать… Короче, картинки перестают работать, надо принимать решения на ходу. Часто — технологам.

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

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

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

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

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

Что произойдёт, когда я поставлю невалидную ставку; как мне придёт сообщение о победе в торгах; насколько запарно создавать таблицу с товарами для торгов? Всё это можно было ощутить либо имея кликабельный прототип, либо в ходе разработки. Каждое слабое решение мы меняли на другое.

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

Тоже бекендер и девопс

Код писало двое человек: я и серверный программист. У нас не было ресурсов на отдельного человека для инфраструктуры, поэтому окружение, интеграцию и доставку настраивали мы сами.

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

У меня не получилось на 100% создать структуру с сине‑зелёным продакшеном и выделенным сервером под тестирование. Получилось примерно наполовину: мы ограничились CI/CD и прогонкой тестов в Travis.

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

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

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

Тоже редактор и маркетолог

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

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

Мы думали, как объяснить пользу этого экрана, показать принцип работы, как подписать «включатель» этой фичи. Потом то же — но для участников. Если бы за каждой кнопкой я бежал к дизайнеру за макетом, то мы, скорее всего, зарелизились бы году в 3019. Умейте работать с текстом, экономьте время и запускайте проекты быстрее.

Тоже менеджер

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

Мне по началу было трудно привыкнуть уделять время планированию и определению приоритетов, а не программированию. Но меня спасала аналогия с процессами в разработке — планирование же тоже автоматизация. Оно помогает на время забыть о том, «сколько всего надо сделать и не упустить бы ещё вот это».

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

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

Тоже эйчар

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

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

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

Однажды всего этого стало слишком много. У меня была неделя с 25 созвонами примерно по 2 часа каждый. Это не считая ревью тестовых заданий для тех, кто согласился на тестовое.

Я сильно закопался. Тогда на помощь пришёл Костя. Мы поняли, что собеседования превратились в конвейер, а я подзабыл, зачем это всё.

Мы с Костей проговорили цели, задачи и проблемы и решили, как именно надо искать нового человека. Снизили напряг, сократили ресурсы на поиск и фильтр кандидатов. В итоге я нашёл двух отличных ребят: Тимофея Аксенова и Романа Макарова. Сейчас весь фронт на них.

Тоже тимлид

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

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

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

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

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

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

Параллельно учился описывать задачи более понятно. Скудное описание демотивирует, потому что непонятно откуда брать нужные данные. Слишком объёмное — лень читать. Учился находить баланс.

И вообще кто угодно

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

Конечно, у меня тоже бывают моменты, когда я думаю «уф, это же не моя работа, почему я вообще должен этим заниматься?», но чаще всего — это от усталости. Работа может приносить удовольствие, если найти отчего прёт. Меня пёрла огромная амбициозная задача. Вроде, справился.

Список литературы, кек

О площадке:

Статьи, посты, доклады:

Я награфоманил:

Крутые ребята:

Как я делал торговую площадку. Часть 1

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

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

Контекст

Задача была в том, чтобы переписать фронт, обновить дизайн и добавить новые типы торгов.

Проект оказался сложным — я с таким уровнем до этого не сталкивался. Чтобы как‑то справиться, старался искать рекомендованные подходы, читать книги об организации кода и архитектуре и применять это всё по ходу дела.

Теперь вот рассказываю о граблях, которые насобирал.

Проблема 1. Один в поле

Я начинал писать фронт один. Писать сервис одному — значит страдать от недостатка ревью и обратной связи. Рефакторить трудно, спросить совета не у кого (исходники‑то под NDA).

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

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

Проблема 2. Проседающая мотивация

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

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

Но иногда и дробление переставало работать. Мне тогда помогало сесть и начать хоть что‑то делать. Начав с малого, можно втянуться и продолжать работать. Но именно «сесть и начать» бывает сложно.

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

Проблема 3. Отсутствие обратной связи

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

Без обратной связи от мира трудно убедить себя, что есть реальная польза от работы. Без них может быть туго с удовлетворением от результата. Ну а без него — см. пункт 2 ↑

Проблема 4. Страх запуска

Итеративная разработка — это делаем фичу и деплоим её, когда она готова. Если что‑то пошло не так, узнаем об этом сразу, будет понятно, что вызвало проблему и как её исправлять.

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

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

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

Преодолевать страх — трудно.
Деплоить итерациями — спокойнее.
Понять это на своём опыте — бесценно.

Проблема 5. Фичеризм

Если пилите проект в закрытую, очень велик соблазн добавить как можно больше фич. «Раз уж мы не выкатываемся по частям, давайте сделаем всё‑всё‑всё.» Это — путь в никуда.

Единственное решение, которое помогло нам, — назначить конечный срок запуска и не сдвигать его. Всё, что не успели, перенесли на версию 2.1.

Занятно, что чем больше времени потрачено на разработку, тем легче согласиться на ещё какую‑нибудь фичу. Ведь «мы потратили столько времени, не страшно потратить ещё немножечко». Но из таких «немножечек» могут складываться недели и месяцы. Не надо так.

Проблема 6. Размер и сложность

Помнить всё — нереально; слишком дофига деталей и нюансов.

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

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

Проблема 7. Собственно запуск

В итеративной разработке релиз — это вполне обыденное дело. Сделали, зарелизили, работаем дальше.

В закрытой разработке релиз — это веха. Жизнь делится на до и после. После релиза, как правило, работы становится больше.

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

Это может стать стресс‑тестом и для вашего продукта, и для вас. А там — привет, пункт 2 ↑

Итог

Это было трудно. Наверное, это был самый сложный проект и по сложности системы, и по поддержанию ритмичной работы с самодисциплиной.

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

Раньше