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

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

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

Контекст

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Итог

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

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

Юодкранте, Нида, Прейла, март 2019

Все три пункта находятся на литовской стороне Куршской косы. (Про российскую сторону у меня тоже есть пост.)

Юодкранте выглядит опрятно, хотя и как‑то сбито что ли.

Юодкранте

Побережье залива красивое.

Вид на побережье залива
Старые лодки
Два лебедя

Красиво.

Вид на лес

На горе ведьм ветер в кронах шумит очень похоже на звук моря.

Вход на гору ведьм
Дорожка, обрамлённая деревьями

Иногда встречается скульпт‑крипота.

Криповая скульптура — 1
Криповая скульптура — 2

Красиво — 2.

Снова вид на лес

В Ниде встречаются чёрные дома (напомню, что чёрный дома — кайф). Больше рассказать о ней нечего, не в сезон там вообще ничего не происходит :–)

Чёрный дом в Ниде

Если останавливаться с ночёвкой, то лучше — в Прейле. Там можно снять дом прямо на берегу залива.

Дом на берегу залива
Вид на залив

Медитативненько получилось.

Тлеющие угли в гриле

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

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

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

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

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

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

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

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

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

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

Знакомьтесь — я. Послесловие

Я сидел на диване, обложенный подушками с головы до ног.

— Не думал, что их аж 8 получится.

Доктор пожал плечами, мол, всяко бывает. Время сеанса подходило к концу.

— Ты же понимаешь, что это просто инструмент, а не панацея ото всех бед?

— Конечно, понимаю, — отмахнулся я.

Я смотрел перед собой, приставив большой палец к верхней губе — делаю так, когда думаю.

— Отдавать кому‑то приоритет ведь будет неправильно? — возник у меня вопрос.

— А что такое «правильно»? — последовал ответ.

Я улыбнулся — и правда, а как будет «правильно»?

Работы предстояло ещё очень много.

Знакомьтесь — я. Часть 4

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

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

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

Он подошёл к пофигисту и положил ему руку на плечо.

— Расскажи, пожалуйста, что тебя больше всего расстраивает? — спросил логик мягко.

— Ничего, — пожал плечами пофигист.

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

— В смысле? — воскликнул романтик.

— Вот‑вот, — прищурив взгляд поддакивал циник.

— Я тоже не понимаю, — присоединился меланхолик.

Пофигист спрыгнул с подоконника, пожал плечами и продолжил:

— Да я как‑то и сам не знаю, как так можно. Просто меня не особо задевает, когда что‑то идёт не так, — он начал оглядывать каждого по кругу. — Мне всё равно, если на меня не обращают внимания другие люди; если задача не решается; если что‑то не совершенно или не идеально; если не ладятся отношения с кем‑то; если у чего‑то нет решения вообще. Мне просто от этого никак. Я не знаю, как это работает; оно просто работает.

Он посмотрел на потолок, поджал губы, а потом продолжил:

— Меня просто забавит, что моё отношение позволяет мне махнуть рукой на всё. Ну окей, если мы в чём‑то виноваты, можно что‑то с этим сделать? Да — хорошо, делаем; нет — ну что ж теперь.

Глаза перфекциониста и меланхолика расширились; циник ухмыльнулся.

— Или вот кто‑то сказал, что мы ничего не стоим. Его мнение важно для нас? Да — ну примем к сведению; нет — ну и шут с ним. Что тут такого‑то? Есть кто‑то лучше нас? Ну и бога ради, что мне‑то с того?

В комнате всё ещё царило непонимание. Никто не осознавал, как это возможно, как это существует.

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

Он уселся на полу посреди комнаты и замолчал. Внимание каждого было приковано к нему, а он молчал. Смотрел в окно и молчал. Это длилось долго, никто не осмеливался нарушить тишину. Даже цинику было неловко начать говорить. Он чувствовал, что в этом что‑то есть. Ему была близка философия пофигиста, но…

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

— Как это вижу я: философия пофигиста нас не раз выручала.

Все переглянулись и согласились. Да, это было действительно так.

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

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

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

Он снова вышел в центр комнаты, поправил очки и продолжил:

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

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

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

Теперь он говорил свободно и легко. Самое сложное осталось позади.

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

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

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

Напряжение пропало окончательно.

— И именно поэтому — я вам и предлагаю работать сообща.

Он больше не смотрел на них, он смотрел на свет от лампы. Его план действительно работал; он закончил говорить.

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

Они молчали; и молчание длилось вечность.

Раньше ↓