Не надо заставлять, надо автоматизировать

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

В этом посте — о том, что это работает не только в уговорах с собой, но и в общем случае.

Порядок, правила, инструкции

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

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

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

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

Например

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

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

Та же история — с ручным тестированием в проектах. Людям лень тестировать проекты. Нам надоедает делать одни и те же действия раз за разом, особенно — если для них требуется какое‑то значительное количество ресурсов: концентрации, внимания, мыслетоплива. В итоге мы начинаем пренебрегать инструкциями и чеклистами.

«Страх наказания» не работает. Да, человек будет тревожиться и переживать, что его накажут, но лень это не переборет. Надо автоматизировать процесс или менять контекст.

Инструкции не работают, человеческая лень — вот, что работает

…Поэтому когда я замечаю, что «пишу инструкцию» для кого‑то, я начинаю думать:

  • могу ли я автоматизировать процесс?
  • могу ли я изменить контекст так, чтобы делать «неправильно» стало менее удобно, чем правильно?

В жизни

Я постарался принести эту философию в разработку Тяжеловато.

Мы сейчас переезжаем на conventional commits, но поменять привычку писать комиты так, как я привык, мне было тяжеловато (no pun intended). Поэтому мы пилим ветку с линтером, который не будет пропускать комиты не по стандарту. А для мотивации писать нормальные комит‑сообщения мы будем каждый комит переносить в автоматически сгенерированный чейнджлог.

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

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

А не манипуляция ли это?

Это тонкий вопрос.

Я считаю такую стратегию манипуляцией при совпадении двух факторов:

  • она не служит безопасности и «лучшим практикам»;
  • её нельзя обсудить и изменить.

Первое понятно — сужение дороги перед переходом спасает жизни, тут не важно, бомбит водителям или нет. А вот «как называть ветки» — это более серая зона. С одной стороны есть best practice, с другой — это похоже на директивное управление.

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

Почитать на тему

У меня в блоге:

Не у меня в блоге:

Тяжеловато:

Автопрочитывать почту

Я живу без уведомлений, потому что они меня раздражают. Исключения — баджик на иконке почты и Слака (от упоминаний через @ и личных). Если в Слаке по пустякам баджик не появляется, то почта в какой‑то момент начала подбешивать.

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

Хоть у меня скрыты док и верхнее меню, между программами я переключаюсь через Cmd + Tab. Если в почте появляется письмо, то баджик видно и в этом окне тоже — именно это отвлекало: Отвлекающий баджик на почте при переключении программ

Отписываться от рассылок, которые мне нравятся, не хотелось. Закрывать почтовый клиент полностью — тоже, я ждал писем от сервисов логирования.

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

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

+10 к спокойствию и сосредоточенности.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Тоже эйчар

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

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

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

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

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

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

Тоже тимлид

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

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

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

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

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

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

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

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

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

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

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

О площадке:

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

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

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

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

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

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

Контекст

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итог

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

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

Когда последовательность важнее правильности.

Пост будет холиварный, читайте с осторожностью.

Представьте ситуацию: приходит задача дополнить валидацию данных пользователя, которую писали до вас. Вы открываете код и видите:

const validateUserData = (userData) => {
  const {socialNumber, email} = userData
  return validateSocialNumber(socialNumber)
    || validateEmail(email)
}

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

Вы открываете код функций validateSocialNumber и validateEmail и видите, что они возвращают истину, если в данных есть ошибка. Откуда делаете вывод, что и validateUserData возвращает истину, если есть ошибка (наверное, на то были причины ¯\_(ツ)_/¯). Беглый просмотр кодовой базы показал, что таких функций много, они встречаются в разных модулях, и быстро исправить всё не получится.

Ваша задача — добавить проверку почты и сделать это «ВЧЕРА!!!». Из‑за сроков отрефактироить код перед этим не успевается (напомню, подобных функций много). Вы понимаете, что правильнее — написать новую функцию так, чтобы она возвращала истину, если ошибок нет…

Но прямо сейчас последовательность — важнее правильности, и первый шаг — сделать по аналогии, сделать «неправильно»

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

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

Раньше