Этот текст все еще страдает избыточным многословием - периодически возвращаюсь к его редактированию
В сухом остатке
Имеется некий опыт работы в ключе "Пиши столько кода, чтоб потом писать его меньше" - и, как оказалось, это работает. Здесь автор пробует формализовать тезисы своего подхода к успешному DX в духе продуктовых Enterprise, исходя из личного опыта (возможно, подойдет не всем).
Статья не для всех, но в споре рождается истина
На момент написания статьи взгляды автора базируются на проблемных проектах ⚠️ как опыт решения похожих проблем легаси кода в рамках работы в нескольких компаниях, продукты которых необходимо было поддерживать как приносящие основной доход. ⚠️ Но ни один из которых нельзя считать идеальным! И, по привычке, автор посчитал нужным задокументировать очередной успешный кейс (все перечисленные моменты подлежат обсуждаемой критике здесь).
1. Простая сборка — лучшая сборка
Первое правило хорошего DevOps инженера: "Чем проще — тем лучше"
- Запуск / Сборка / Деплой должны запускаться одной командой (посредством bash лучше автоматизировать все, что не требует изменений самих сборок - но не злоупотреблять им)
- Сборка и раскатка всех App Mode режимов (Staging / Production) должна быть настроена и автоматизирована до начала разработки фич; Режим Development, разумеется, должен быть отлажен в первую очередь
- Процесс сборки должен быть максимально абстрагирован от среды сборки и хостера. Все что можно вынести в переменные среды для конкретной сборки - должно быть вынесено. В отличие от продукта сборки - он собирается для конкретного инстанса (Staging / Test / Production) - в нем должно быть предусмотрено все для простого запуска и раздачи с хоста.
Вы получите неожиданный для себя результат: "прозрачный" деплой и онбординг нового разработчика в Ваши проекты в минимальные сроки.
2. Помните про абстракцию
2.1 Соблюдайте высокий уровень абстракции на уровне компонентов
Для удобства переиспользования компонентов и соблюдения атомарности.
2.2 Сохраняйте контроль над Бизнес Логикой
Соблюдать разделение Бизнес Логики (далее по тексту БЛ) веб-приложения на "слои" - мастхэв для масштабируемости и устойчивости к изменениям отдельных слоев (бонус: удобство тестирования отдельных слоев БЛ). Здесь нужно определить значимость центров принятия решений при постановке ТЗ (что бы это ни значило, постараюсь объяснить ниже по тексту) - теоретически, именно это должно повлиять на выбор стека технологий на ранних этапах.
В более широком смысле
Иными словами, расставляйте приоритеты правильно:
1/ Деньги в глазах Бизнеса; 2/ Живучесть Бизнеса глазами абстрактных инвесторов (вера в продукт и другие ментальные вещи, не касающиеся разработки); 3/ Управление логикой Продукта на уровне Менеджмента, а так же необходимая масштабируемость и гибкость Продукта - глазами Менеджмента (тот слой компании, который ставит задачи разработчикам); 4/
> Вы здесь 👉
DX глазами Разработчиков; 5/ Ценность Программного Продукта (в виде физического набора текстовых файлов исходного кода, которые никому не нужны без адекватного DX, а их отсутствие принесет ущерб Бизнесу) - глазами абстрактного бухгалтера, выдающего зарплату;Имеющее более низкий приоритет (убывание приоритета вниз по списку) не должно быть важнее того, что выше - иначе Бизнес Вам скажет, что ему это не нужно, т.к. от удобства разработки не должно страдать управление Проектом, а значит выбор стека технологий должен быть соответствующий задачам Бизнеса и т.д. Для примера: в моем случае удачно подвернулся XState, который (помимо прочих его достоинств) позволяет продемонстрировать и согласовывать верхний уровень БЛ до написания кода - что сыграло положительную роль в согласованности при разработке новых продуктов (пункт 4 выполнен в пользу пункта 3, а не наоборот). Ещё пример утверждения: Удобство разработки Продукта, не должно обходиться дороже, чем та прибыль, которую имеет Бизнес с Продукта (приоритет пункта 5 не выше приоритетов пунктов 1-2), но случай, когда Продукт живёт за счёт другого Продукта будем считать исключением - это совсем другая история.
Какой результат ожидается
- Удобство переиспользования кода;
- Быстрое решение задач Бизнеса в дальнейшем (даже если на первоначальном этапе это займет больше времени - потом разрабы Вам скажут Спасибо за DX);
- Бизнес про Вас не знает (имеется ввиду, Вы не оттягиваете внимание на себя), а Вы, в свою очередь, покрываете все его текущие и новые требования;
3. Настройте внешние механизмы отладки
3.1 Формулируйте требования
В процессе разработки, отладки (и в процессе работы на проде) приложения (особенно в SP) могут возникнуть ситуации, требующие детального анализа:
- Позитивные кейсы (клиент дошел до конца успешного сценария, к примеру, сдачи устройства в Trade-In);
- Негативные кейсы (к примеру, ошибка сценария);
- Все остальные кейсы, вызывающие вопросы;
Есть много способов узнать текущее состояние клиента с целью анализа, к примеру:
- Telegram API
- Google Sheets API
- Любой другой ресурс (Sentry и т.д.)
Посыл заключается в том, чтоб иметь возможность получить эти данные для дальнейшего анализа.
3.2 Формулируйте ограничения
Путь Вашего лога проходит через сервисы, имеющие ограничения - изучите их. В моей практике каждый лог мог находиться на разных уровнях, к примеру:
- Кэш (практически, без ограничений)
- Google Sheets (ограничение 50K символов в ячейке + 300 ивентов в минуту на проект / 60 ивентов на пользователя в проекте) See also
- Telegram API (10K символов в сообщении + самописная очередь с ограничением по частоте отправок)
На каждом этапе ивент может "отвалиться" - об этих случаях разработчику также надо быть в курсе (см. пункт 4.1).
3.3 Ничто не вечно
Если внешний механизм отладки недоступен либо не функционирует - приложение должно работать (кстати, по этой причине пришлось однажды выпиливать newrelic из проекта - отдельная история).
3.4 Управляйте метрикой
Отключайте метрики для устаревших версий. Логика управления поддержкой логов для конкретных версий клиентского приложения должна быть внешней.
Зачем это все?
См. пункт 4.
4. Настройте внутренние механизмы отладки
Пишите код так, чтоб Reverse Engineering был не нужен! Иначе, следующий разраб может сделать харакири в лучшем случае - себе, в худшем - начать искать Вас.
4.1 Все данные должны быть проверены
Если что-то пришло от бэкенда - это следует проверить на соответствие тому, что ожидалось от него получить. Если что-то пошло не так, скажите об этом клиенту, который, скорее всего, захочет понять причину происходящего (об этом будет подробнее в 5.2).
В случае, если пришло не совсем то, что ожидалось - формулируйте подробности и информируйте пользователя об ошибке (сейчас только про UI). Как показала практика, это мастхэв для уменьшения Вашего же времени на отладку. На личном примере: Ответ на каждый запрос имеет свою уникальную валидацию в виде настраиваемой схемы с предусмотренной формулировкой сообщений для UI.
4.2 "Явное лучше неявного"
- Типизируйте все, что можно
- Покрывайте тестами то, что нужно
- Держите пользователя в курсе происходящего (см. пункт 4.1)
- Держите разработчика в курсе происходящего (см. пункт 4.5)
4.3 Предусматривайте дебаг-режим кода
Используйте настраиваемый дебаг-режим, который можно отключить одной настройкой К примеру либо выносите настройки в отдельный конфиг когда их много (к примеру), чтоб не засорять консоль и не рассеивать Ваше внимание.
4.4 Предусматривайте пользовательский дебаг-режим
А это нечто другое - речь про включение / отключение отладочного UI клиента. Желательно, чтоб это не требовало перезагрузки страницы (к примеру, в тех проектах, где это возможно, для включения такого режима, я использую хэш роутинг с параметром). Что я включил бы в этот пункт:
- Отладочная печать
- Визуальный контроль расхода памяти
- Custom devtools
4.5 Отправляйте данные (логи) для анализа
В дополнение пункта 3 - нужна отправка данных в те службы, которые предоставят Вам возможность иметь полную картину взаимодействия клиента с Вашим приложением. На личном примере - Вот минимальный набор свойств, которые я включаю в лог:
eventType
- Тип ивента (default|info|warn|danger|success)appName
,appVersion
- Project props from package.jsondetails
- Объект с целевой информацией (к примеру, текущее состояние приложения в формате json)uniquePageLoadKey
- Ключ, который был сгенерирован при загрузке страницыgitSHA1
- Хэш коммита, соответствующий сборке
Все данные, которые можно вынести во внешние службы, должны быть вынесены:
ts
- Время прилёта ивентаip
- IP клиентской подсетиuserAgent
- User-Agent from headersclientReferer
- Client-Referer from headers
При включенном дебаг-режиме советую отображать состояние лога, как следствие пункта 4.4.
Помните про 152 ФЗ
Никогда не включайте перс. данные в лог
Какой результат ожидается
Возможность дебажить проект локально и дистанционно на разных уровнях абстракции - бесценно.
5. Выполняйте сложную работу один раз
5.1 Второй раз всегда должен быть проще
Если есть необходимость отладить что-либо - предоставьте следующему разработчику возможность сделать это второй раз быстрее
В качестве примера, частный случай из практики: Есть необходимость дебажить кейс из двух процедур, вторая их которых должна быть вызвана по некоему неочевидному условию: 1) В контексте стейт-машины создаем промежуточный шаг с отключенной настройкой "Пропустить этот шаг" и кнопками "Продолжить" для различных сценариев; 2) Дебажим; 3) Включаем настройку "Пропустить шаг"
В результате имеем переиспользуемый кейс для подобных случаев.
5.2 Отладка должна быть информативной
Используйте UI для отладочного режима с информативными сообщениями. Я имею ввиду не просто отображать факт ошибки (см. пункт 4.1), а делать это так, чтоб информация о ней была максимально исчерпывающей. Клиент (в частном случае, разработчик) должен понимать, что делать с этой информацией. Именно выполнение этого пункта даст моральное право написать клиенту "Мы уже работаем над этой проблемой!"
Что может быть важно в плане практической пользы:
- Все сервисы должны иметь общий протокол информирования об успехе или ошибке. К примеру, оглядываясь на fb, можно увидеть для себя хороший и простой пример:
{ ok: boolean; message?: string; }
Зачем это все?
Больше работы - меньше кода.