Госконтракт: история о том, как мы не справились
- среда, 27 ноября 2024 г. в 00:00:13
Дисклеймер:
Все факты, описанные в статье, основаны исключительно на моём личном опыте в рамках одного проекта и одной компании. Я понимаю, что мой опыт может не быть универсальным, и он не отражает работы других команд или людей. Всё, что написано, — это исключительно мои ощущения и впечатления, которые могут быть ошибочными или неполными.
Я сознательно упустил многие рабочие моменты, которые не относятся к истории.
Я не осуждаю никого в этой статье.
Я не собираюсь вас чему‑то научить.
Доброго времени суток, Хабр!
Сегодня я подкину своим хейтерам отличный повод провести вечер в комментариях под этой статьёй. Речь пойдёт о том, как я участвовал в провале гос. контракта.
Сразу развею возможные тезисы вроде: «Ты ужасный прогер, только и ноешь о своих проблемах и некомпетентности.» На самом деле, я пишу об этом намеренно. Меня раздражают весёлые, а порой и лицемерные статьи, где авторы только и делают, что кичатся своими успехами.
Увы, я претендую на искренность. Моя цель — подсветить негативные моменты и ошибки. Возможно, мои провалы помогут кому‑то не наступить на те же грабли, что и я. Да, я осознаю, что меня могут заклеймить как «неудачника» или «плохого прогера», но меня это устраивает.
Устроился я в обычный классический аутсорс фронтенд‑разработчиком. После успешно пройденного собеседования (довольно лёгкого) наступил мой первый рабочий день.
Я ожидал получить обещанный онбординг, но, как оказалось, пришлось самостоятельно находить членов команды и поодиночке писать им в личку, чтобы разведать обстановку и познакомиться. Первым делом я нашёл тимлида и попросил у него аудиенции — ждал от него вводной о том, что мне делать.
Тимлидом оказался старый пердун, который позвонил мне на телефон по обычной связи и с ужасным микрофоном. Как выяснилось позже, тимлид никак не участвовал в жизни команды, проваливал задачи и время от времени пропадал с радаров. «Этот перец мне не помощник,» — подумал я и пошёл искать братьев‑фронтов.
Обещанная команда опытных фронтендеров состояла из одного человека, который устроился за пару дней до меня. Мы сразу нашли общий язык, и на мой вопрос: «Ну что, как тут тебе?» он без раздумий заявил: «Тут [нарушение правил Хабра], а в коде тут [нарушение правил Хабра].»
Я немного расстроился, но решил, что стоит попробовать и убедиться во всём лично. Вдруг всё не так плохо, а я, как Д’Артаньян, смогу повлиять на процессы.
Компания занималась преимущественно госзаказами и работой с дубайскими коллегами. В нашей команде было два мидла‑фронтендера, джун‑бэкендер (работавший исключительно на Битриксе, без знаний основ нативного PHP и существования REST API), пре‑синьор BA, тестировщица, ПМ и директор дивизиона. Наша супер‑компашка отправилась «поднимать с колен отечественную IT‑индустрию» (шутка).
Через полтора месяца лида выкинули ссаными тряпками из компании, и мы выдохнули. В основном занимались внутренним продуктом — маркетплейсом с авторскими правами.
Это чудо было написано в формате MPA на Vue 2. Роутинг был монструозно реализован прямо в конфигурации Webpack, а каждый роут представлял собой новый экземпляр Vue. Шаблон компонента создавался на Pug.js, а манипуляции с DOM происходили с помощью jQuery. И всё это — на базе Vue.js. Vue.js, Карл!
Может, для Multi Page Application это и норма, я не в курсе. Сказали, что такой подход обещал им хорошее SEO. Ну, такое...
Мы довели это дело до MVP. Нам с коллегой разрешили переписать проект на Nuxt.js и дали на это месяц. С чем мы отлично справились.
Спустя 4 месяца началось...
Общий созвон. ПМ довольный, рассказывает нам, что мы стартуем крупный госзаказ. По его словам, сдача этого проекта должна была перекрыть долг дивизиона и вывести его в плюс. Что? Долг дивизиона? 5 млн? Опешил я, но виду не подал. Окей, работаем!
Нам взяли нового лида, который был очень токсичным, но тем не менее толковым. Хоть и не сразу, но мы нашли с ним общий язык и приступили к делу...
Реализация трёх модулей для учёта трудозатрат государственного аппарата. В них входили:
Модуль с дашбордами. Состоял из диаграммы Ганта и двух других диаграмм, похожих на первую, но с более урезанным функционалом.
Модуль учёта времени, потраченного на проект или инициативу. Полный список под каждого сотрудника: кто, где и на что потратил время. Представлял собой таблицу с фильтрами и списком сотрудников с возможностью в реальном времени редактировать данные внутри таблицы с автосохранением.
Модуль с таблицей проектов, инициаторов, ответственных. Представлял собой вложенные таблицы с данными, тесно связанными с модулем учёта времени.
Каждый модуль является отдельным модулем, который интегрируется в CRM Битрикс24 как компонент.
На всё про всё — три месяца, не больше. Время пошло!
ТЗ ещё не разработано, но есть скрины похожего модуля. Нет понимания конечного функционала и требований к нему. Только широкими мазками из брифов ПМа, основанных на созвонах с конечным клиентом, у нас было абстрактное описание проекта.
На счету дивизиона нет дизайнера. Как это должно выглядеть — мы не знали.
Неизвестен API-контракт.
Неизвестна конечная точка интеграции. О том, что это модуль для Битрикса, мы узнали уже в конце. До этого не было понимания, где эти модули будут находиться и использоваться.
Диаграмма Ганта имела специфический набор дополнительного функционала, который не могла предоставить ни одна библиотека для отрисовки диаграмм и графиков. По крайней мере, мы такую не нашли.
Оценили фронт работ и разбили его на зоны ответственности. Фронт решили писать на Vue.js. У каждого был свой модуль с таблицами, а работу с дашбордами мы проводили втроём: я, лид и второй фронтендер. Модули учёта времени и сводка проектов были довольно простыми, не буду заострять на них внимание. Особого внимания требовала диаграмма Ганта. Из-за её функциональных особенностей и требований заказчика пришлось писать кастомное решение на TS + <canvas>
. Всё ещё нет финального ТЗ.
Мы довольно быстро накидали классы, которые давали нам абстракцию для удобного рисования на canvas. Базовый инструмент для рисования был готов, начали художничать. У нас был только скриншот примерного результата, остальное приходилось дофантазировать аналитике и ПМу. Потихоньку стала вырисовываться первая версия ТЗ. Мы уже начали понимать, какой примерно функционал требует заказчик.
Прошло половина срока, большая часть работы была уже готова. Модули с табличками были завершены. Два дашборда находились на завершающем этапе. Диаграмма Ганта имела весь необходимый функционал, но всё ещё оставались пару неприятных багов со скроллом и подсчётом праздничных дней.
Праздничные дни считались неправильно, потому что с бека приходил неверный контракт, который не учитывал актуальные выходные дни и праздники РФ. К тому же, не было до конца ясно, какие выходные учитывать, а какие нет. Проблема скорее заключалась в недопонимании.А баг со скроллом приводил к тому, что временами заставлял моргать отрисовку или вовсе рендерил объекты на Ганте неверно. Изначально мы реализовали вариант с тем, что горизонтальный скролл был стандартный, а Гант увеличивался в размерах столько, сколько ему было нужно. Такой вариант работал хорошо без сбоев в рендере, но Лид решил заморочиться и сделать иначе. Его концепция предполагала написание виртуального скрола поверх статического канваса с фиксированной шириной. Изменения координат скролла должны были запускать процесс перерисовки всей видимой области Ганта, стирая части позади таймлайна и дорисовывая в конце (при движении вправо, и наоборот — если влево). Идея звучала круто. Он принялся её реализовывать, и, чёрт возьми, это переусложнило логику настолько, что из-за ошибки в пересчёте координат появился этот чёртов баг, с которым он продолжал сидеть неделями.
На руках у нас появилось первое «финальное ТЗ». Но не всё так просто. Оно сильно отличалось от того, что спускали нам ПМ и аналитик. Изменения касались всего: где-то появился новый функционал, а где-то полностью изменилась концепция подсчёта затрат.
Мы принялись переделывать то, что есть. Время утекает через наши ладони. В процессе реализации правок ещё неоднократно появятся новые требования и улучшения, а ни одно ТЗ в этой истории не будет финальным.
Наша команда утопает в правках, каждую неделюнам спускают пачку «хотелок», и мы послушно начинаем их реализовывать. Срок сдачи уже через неделю, а мы в четвёртый раз перерисовываем дашборды, потому что заказчику захотелось добавить туда ещё пару метрик, которые будут отрисовываться в виде плавающих окошек. Команда разработки уже смирилась с тем, что мы не успеем. Пока директор дивизиона и ПМ вытаскивают нас на очередные выходные, пришёл Кабан Кабаныч...
Кабан Кабаныч в ярости. Неустойка за проваленный контракт 12 млн. Кабан Кабаныч не был осведомлен, что у нас пожар в дивизионе, а осталась неделя. Ауф... Полетели головы... первым уволили директора дивизиона. Все обязанности за завершение проекта возложили на ПМ`а. Аналитика забрали на другой проект. Бекендер уволился незадолго до прихода Кабан Кабаныча. Нам в команду прислали двух синьоров со словами "их время стоит намного дороже чем ваше, используйте его с умом". К нашему сожалению синьоры оказались бутафорскими. Синьор фронт не особо пробовал Vue (говорил, что они такие вещи в своих отделах на Jquery пишут) и другие фреймворки, а синьор бек оставшуюся неделю ждал какие-то доступы вместе со своим коллегой. Так что, за черту невозврата мы и высокооплачиваемые специалисты — вошли с гордо поднятой головой. Команда усиления не помогла, даже коммитов не было. ПМ был уволен сразу. Дивизион расформировали. К фронтам и тестировке вопросов не было, даже наоборот нас сохранили и отправили работать в другие отделы.
Я, лид и второй фронт уволились из компании, не отработав и недели в других дивизионах. Акция увольнения была уже спланирована заранее и по одной причине. Дивизион, в который мы пришли изначально, был самым современным в плане технологий и взглядов. Остальные дивизионы отрицали существование фреймворков и современных инструментов. Поголовно всё было написано на jQuery и нативном JS. Очень низкое качество кода и низкая квалификация коллег. Откуда мы это знали заранее? До того как попасть на госзаказ, каждый из нас уже успел поработать в других командах на усилениях. Истории там были забавные. Да и связывать себя с Битриксом не было желания.
Кто виноват в этой ситуации — решайте сами. Разработчики, которые не справились, несмотря на всяческие усиления? Или директор дивизиона с ПМ, которые принимали все правки, не оговорённые контрактом, и без увеличения срока исполнения, в добавок не оповещали руководство о проблемах? А может, Кабан Кабаныч, который пришёл проверить важный госзаказ только за неделю до дедлайна? Кто знает...
Возможно, стоило «дать заднюю», когда тимлид позвонил по телефону, а не назначил встречу в Google Meet)))