Как мы проект с аутсорса забирали: комментарии разработчика
Что делать, если через пару месяцев аутсорс-команда исчезнет, а проект с кодом, который вы видите впервые в жизни, целиком остаётся на вас? История и маленькие практические советы по выживанию от разработчика — для команд, которым предстоит забирать проект в условиях отсутствия документации, и для тех, кто внезапно оказался за это ответственным.

Предыстория: когда с аутсорсом что-то пошло не так
Однажды в моей компании, после N лет успешной разработки продуктов силами внутренних ресурсов, решились на эксперимент — сотрудничество с аутсорс-командой. План был хорош: за короткий промежуток времени, не отвлекая своих программистов от текущих задач, получить сильно урезанную с точки зрения функциональности версию одного из наших продуктов — попроще для внедрения, покрасивше внешне и подешевле.
И всё вроде бы шло неплохо, пока не выяснилось, что вместо «быстро и без усилий» получается долго, дорого и непонятно. Разработка продвигается медленно, сильно медленнее, чем планировал бизнес. Команда проекта существует где-то отдельно, и никто не понимает: так ли это должно быть и всё ли под контролем, или уже давно что-то пошло не так. В таком состоянии мы просуществовали около года, после чего было принято решение забрать кодовую базу с аутсорса и дальше вести разработку самостоятельно.
Вводные данные: проект и личные ожидания (которые не оправдались)
Кто, собственно, я — Java-разработчик сервиса «Майснаб» и тот человек, которому поручили этим заниматься. На тот момент — без опыта руководства командой, но с опытом менторства; без опыта построения архитектуры на глобальном уровне (и вообще не с супербольшим опытом коммерческой разработки, раз уж на то пошло), но с интересом и желанием в этом преисполниться.
Важная для контекста деталь номер один: оба проекта, старый и новый, представляют собой средства автоматизации процессов снабжения у строительных компаний (это нужно для понимания задач, которые я буду упоминать дальше).
Важная для контекста деталь номер два: до этого в компании пилили исключительно монолиты с некоторыми попытками в отдельные сервисы для инфраструктурных целей, так что разработка и поддержка микросервисов были знакомы мне только в теории. Следовательно, процесс перенятия чужого кода превращался в задачку со звёздочкой.
Проект, которым нужно было заниматься: микросервисы (аж 21 штука), тоже на Java (и на том спасибо), в стадии развёрнутого и достаточно жизнеспособного MVP. Тестирование уже переехало к нам, и планировалось (по крайней мере, в моей голове), что мы с ещё одним разработчиком где-то полгодика поработаем под менторством аутсорс-команды: они будут принимать важные решения и разбираться с проблемами, а мы — постепенно привыкать к новой системе. А потом, когда-нибудь, когда мы почувствуем себя готовыми, случится передача ответственности…
В реальности — через полтора месяца от всей аутсорс-команды с нами остался один разработчик, который продолжал работать в штатном режиме, а ещё через два месяца — не осталось никого.
Этап номер один (первый провал)
Итак, двадцать один новый сервис, ноль документации, очереди сообщений, распределённые транзакции, угрожающе выглядящие таблицы в реляционной БД, которые почему-то не в 3НФ, два разработчика, которые всё это видели только в статьях и pet-проектах — и осознание, что в скором времени сторонняя команда уйдёт, а разбираться со всеми бизнесовыми хотелками, клиентскими проблемами и падениями прода придётся только нам. При этом аутсорс-коллеги уже что-то там спроектировали, заложили какие-то абстракции на будущее — и это тоже не хотелось бы сломать…
Так родилась первая паническая идея: «до начала активной разработки осознать всё, что только можно, чтобы быть готовыми ко всему».
Вот наш примерный список вопросов — от экзистенциальных до вполне прикладных, которые возникли в процессе поиска ответов на экзистенциальные:
-
Как всё это дело развернуть? Сколько стендов и зачем они? Какие на стендах стоят ветки? А что по стратегии ветвления?
-
Что будет, если сервис упадёт? Как организован мониторинг? Где смотреть логи? А есть ли у kafka какие-то логи? Как её мониторить? Что будет, если kafka упадет? А почему вообще именно kafka?
-
Как сервисы общаются между собой? Почему где-то HTTP-запросы, а где-то очереди сообщений? Почему где-то обновление данных между сервисами идёт напрямую, а где-то — через saga orchestration?
-
Какие компоненты есть внутри сервиса? Есть ли конвенции, которым нужно следовать? Почему почти везде есть интерфейсы, но где-то их нет?
-
Почему у нас postgres, но в каждом сервисе — по одной таблице, а бизнесовые данные лежат в одном jsonb-поле (этот вопрос мучил меня больше всего!!)? Если мне нужно сделать запрос к глубоко вложенному в этот jsonb полю — как я это буду делать?
В общем, мы со вторым разработчиком раскидали этот список между собой, начали собирать информацию, читать код, документировать, и…
Диалог:
– Есть, может, какая-то инструкция, которую вы рассылаете своим новеньким, чтобы они разобрались?
– К сожалению, нет, только на словах… Давай конкретные вопросы.
– Задаю вопросы.
– Каждый раз по ситуации… По этому процессу вообще полное творчество, так как ничего не описано нигде. Второй вопрос на целый доклад. Тоже все по ситуации, на самом деле… Третий – вообще доклада на 3…
Что-то, конечно, выяснилось — стенды и ветки, например (здесь ничего не могло пойти не так), но когда мы полезли в код, стало понятно, что:
а) абстрактные вопросы порождают абстрактные же ответы (посмотрим на диалог выше), и всегда имеют место истории «так сделано на нашем другом проекте, скопировали оттуда» или «тут решение на скорую руку, планировали переделать, когда будет время»;
б) простые прикладные штуки, во-первых, достаточно быстро гуглятся, а во-вторых, мгновенно стираются из памяти, как только ты перестаешь их активно использовать (вспомним мемы про senior developer Google search).

Этап номер два (успех)
После непродолжительных попыток в гугление и интервью старших членов аутсорс-команды к нам пришло осознание, что план «сесть и понять все сразу и заранее» — нежизнеспособен. Зато к этому моменту чужой проект перестал казаться какой-то идеально спроектированной машиной, где в основе всего лежит четкая причинно-следственная связь, непонимание или отступление от которой ведет к мгновенной поломке всего на свете.
Жить стало легче, и мне даже удалось вспомнить о своём опыте онбординга разработчиков в свой предыдущий проект — ведь по сути, процесс передачи кода на первых этапах и есть онбординг, просто мы в нем оказались с другой стороны.
Так возник новый план: «если бы мне нужно было за максимально короткий срок погрузить нового программиста в проект, что бы я делала?» Так что ниже — очень небольшой (и на самом деле очень простой, и очень напоминающий одну известную картинку) список вещей, которые помогли нам за несколько месяцев полностью забрать проект с аутсорса и не сойти с ума.

Первое — больше задач!
Очевидный совет номер один — делать задачи. Как можно больше задач, хороших и разных, особенно если они:
а) из мерзкого техдолга, до которого ни у кого из аутсорс команды не доходили руки;
б) касаются новых для нас областей (в нашем случае — всё, связанное с микросервисами).
Примеры задач, выполненных мной, с описанием, почему это было полезно:
-
Перезаписать в DTO с фронта одно поле на значение из базы, чтобы его точно не затерли. Одна строчка, но зато обновление шло через местную реализацию Saga Orchestration, так что получилось ее подебажить.
-
Рефакторинг (который, честно говоря, я уже толком не помню) чего-то затрагивающего общую на все сервисы абстракцию в кастомной проектной библиотеке. Помог разобраться с версионностью + пришлось залезть в N сервисов + посмотреть, что там в этой библиотеке есть.
-
Сделать сервис фонового обновления данных для текстового поиска, чтобы можно было искать в одном сервисе по данным, принадлежащим доменным моделям других сервисов. Например, в сервисе счетов, где есть только uuid автора + строчка с его ФИО на момент сохранения счета, искать по актуальным на текущий момент ФИО автора этого счета, информация о которых хранится в сервисе пользователей. Тут получилось словить комбо: очереди и асинхронную обработку, а главное – проблемы с несогласованностью данных, когда сообщение в очередь уже улетело и триггернуло сервис, который попытался запросить данные из другого сервиса, а у другого все еще не завершилась транзакция, и актуальных данных в базе еще нет
Второе — ревью
Нам повезло: первые полтора месяца с нами возился архитектор, а затем — сильный разраб, и это лучший расклад, который я только могу представить (пользуясь случаем, передаю привет и огромное спасибо за терпение архитектору! По тарантиновским диалогам из этапа номер один могло показаться, что толку от нашего общения было немного, но на самом деле он с утра до вечера разбирал со мной те самые мерзкие задачи из техдолга в личке в тг).
Диалог 2:
– Скидываю ссылку на merge request
– Давай я тебе вопрос задам без ответа и ты сразу коммиты поправишь? Допустим, мы убрали поисковую информацию из всех сервисов и засунули в эластик, будет работать? И сколько надо изменений? Блин, два вопроса получилось…
Диалог 3:
– … нагрузка в месседже может быть для каждого события своя, апи от нее зависеть не должно, просто сейчас как-то все обошлось очень похожей нагрузкой.
– Это будет полный роллбэк сейчас, я так понимаю…
– )))
В общем, первые ревью были скорее из серии «отлично, а теперь давай снесем все и сделаем по-новой», но без них у меня точно не получилось бы преисполниться концепциями новой системы и совершить эволюционный скачок (а теперь привет всем маленьковым разработчикам, на которых свалилась большая ответственность). Думаю, что секрет успеха здесь в обсуждении: нужно не просто править, а понимать, почему ты это правишь.
Неочевидный на первый взгляд факт про ревью: ревьюить большие и страшные задачи кого-то
классного и умногоболее опытного — оказалось очень полезно. Во-первых, это шанс посмотреть, как человек решил задачу, прикинуть, как бы ты сам ее решил, и все это сравнить, а во-вторых – возможность задать вопросы в момент появления логики и не дать неизведанной части проекта сильнее разрастись.Раз уж я пытаюсь приводить примеры, то вот большая задача, которая попала на ревью ко мне: добавить пользователям настройки тайм-зоны и каждый день в определенное время в их часовом поясе слать пуши со сводной информацией по действиям, которые пользователю необходимо выполнить в текущий день –– согласовать счета, принять доставки, запланировать платежи и т.д. Все это тоже с учетом тайм-зоны нужно было посчитать.
Третье — расследование инцидентов
Когда дата окончательного отсоединения от наших аутсорс-коллег приблизилась, на передний план вышла другая проблема: страх, что вот сейчас сторонняя команда исчезнет, и в этот момент обязательно случится что-то хитрое, прод будет гореть, пользователи — страдать, а ты останешься один посреди катастрофы.

Так что на этом этапе мы спохватились и начали активно следить за тем, как там себя чувствует продакшн, и подключаться к решению проблем. План действий такой:
-
Если прод ведёт себя странно — начинаешь расследование. Получилось разобраться — супер.
-
Если не получилось — идёшь к аутсорс-разработчику, спрашиваешь, куда смотреть: в какие метрики, в какие логи, в какой сервис.
Внимание, промах: мы начали делать это слишком поздно. В итоге, в реальности мы оказались к разбору инцидентов практически не готовы, и после ухода сторонней команды нам пришлось справляться со всем методом проб и ошибок.
Думаю, здесь могло бы сработать как с ревью — понаблюдать за тем, как проблемами системы занимаются люди, которые эту систему проектировали. Это помогло бы нам заранее выстроить алгоритм действий, чтобы панически не искать три часа не там и не то.
Что было дальше:
Через три с половиной месяца мы остались одни, но уже без паники, с надеждой на светлое будущее. Вселенная не cхлопнулась. Это достаточно короткий срок для такого масштабного переезда в условиях нашего ограниченного опыта, так что в первое время все еще было страшно что-то поломать или в чем-то не разобраться… Но постепенно у нас получилось перейти от состояния «боюсь тронуть» и «хоть бы не навернулось» к крупным переделкам и оперативному решению проблем без лишней суеты. Сервисов у нас, кстати, теперь на четыре больше.
Теоретически, у нас осталась возможность задать вопрос бывшей команде, но на практике стратегия «задать вопрос потом» тоже не самая рабочая, потому что:
а) спрашивать о чем-то мелком не имеет смысла — люди довольно быстро выпадают из контекста (кто может детально описать ход своих мыслей в контексте прошлогодней задачи – пусть первым кинет в меня камень);
б) на экзистенциальные вопросы (по типу «вот тут возросла нагрузка, как бы нам получше от нее избавиться») ответов чаще всего больше одного, и выбор очень сильно завязан на понимание текущих требований и ограничений.
Выводы
-
Забрать себе проект c аутсорса — реально, даже если это нужно сделать быстро, даже если он «другой» и релевантного опыта у вас немного.
-
Теория — хорошо, но без практики не работает. Плюс есть риск зарыться в поиске причин и правил, которых нет.
-
Брать сложные мерзкие задачи и расследовать сложные мерзкие проблемы — лучший способ ускорить погружение.
-
Если есть возможность поработать с людьми, которые проект писали –– супер! Но на время придется вырубить свою интровертность и задавать вопросы. Очень много вопросов.
-
Вы во всем разберётесь. Со временем.
Автор: alsntt