Синергия и жесткая фокусировка
В прошлом посте, я рассказал, что найм сотрудников А+ на стадии активного роста может лишь ухудшить ситуацию. И объяснил это рассуждениями Адизеса. А еще ранее я рассказывал, что во время взрывного роста нам приходилось решать множество задач одновременно. В том же посте я упомянул, что естественным решением этой проблемы является жесткая фокусировка. Сегодня хочу поговорить как раз о ней и о тех плюсах, которые она дает.
На этапе активного роста проблем всегда больше, чем ресурсов. Стоит распылиться — и через полгода обнаруживаешь, что «делали много», а не сдвинулись ни на дюйм. Узнаете ситуацию?
Жёсткая фокусировка — это сознательный отказ от большинства проблем ради нескольких, но самых существенных, которые дадут самый весомый эффект. Не потому, что остальные не важны, а потому, что 80% из них не изменят ничего, а изменения — наше всё.
И мы это ощутили на себе: команда получила 20% рабочего времени на «свои» задачи, и за эти 20% усилий мы ускорили разработку примерно на 80%. Так работает Парето, если фокус держать жёстко, а не «по остаточному принципу».
Но фокус сам по себе — только половина. Вторая половина — синергия: эффект, когда две задачи, сфокусированные на одну цель (или на несколько связанных), в сумме дают не сложение усилий, а кратный результат.
Например, мы последовательно и сфокусированно «навалились» на 2 самых главных направления: — модульные тесты — тщательно покрывать код тестами (детально про них я напишу один из будущих постов); — модуляризация — резать монолит на изолированные модули, о чем я подробно написал в этом цикле постов (тут, тут, тут STAR и про сложности).
По отдельности каждое из них — «полезная, но небыстрая» задача. Вместе они усиливали друг друга так, что итог оказался больше суммы частей. Разберу, как именно.
Как модуляризация помогает тестам:
— Тестируемость по построению. Модуль с чёткими границами и явными зависимостями можно тестировать в изоляции: подставить заглушки на входах и выходах — и не поднимать половину приложения ради одного теста. В монолите то же самое требует героических усилий: вытащить класс из спагетти-связей дороже, чем написать сам тест.
— Мелкие и быстрые тесты вместо интеграционных монстров. Изолированный модуль тестируется за миллисекунды. Меньше времени на прогон — чаще запускают — раньше ловят баг.
— Тесты как спецификация контракта. Границы модуля — это и есть его публичный контракт. Набор юнит-тестов фиксирует этот контракт буквально: сломал обещание — тест краснеет. В монолите «контракта» нет, есть место в коде, где всё сцеплено со всем.
— Локализация отказа. Упал тест на модуль — понятно, где искать, и понятно, чья это зона ответственности. В общем коде падение теста — начало детективного расследования.
— Управляемая сложность тестов. Каждый модуль маленький, поэтому тесты простые и не требуют хитрых сценариев. Общая трудоёмкость покрытия растёт линейно, а не по «комбинаторному взрыву».
— Дешёвые моки. Чем уже интерфейс модуля, тем меньше заглушек нужно писать. В монолите одна «заглушка» может тянуть за собой полсистемы.
· вчера
Как тесты помогают модуляризации:
— Безопасный рефакторинг. Это главная точка усиления. Резать монолит — значит постоянно передвигать код, и без страховки каждое движение — риск. Тесты превращают рискованную операцию в контролируемую: сделал шаг — прогнал тесты — уверен, что ничего не сломал. Разработчики меньше боятся и активнее вносят изменения.
— Оценка качества разреза. Пишешь тесты на гипотетическую границу модуля — сразу видишь, является ли она настоящей границей. Если для теста модуля нужно знать внутренности трёх соседних — разрез неправильный, границу надо двигать. Тесты — бесплатный детектор плохих стыков. Кажется, именно тут и погорела вымышленная команда Незнайки на Луне вот в этом примере.
— Защита границ от размывания. Модули имеют свойство «срастаться» обратно: кто-то торопится и тянет зависимость напрямую. Тесты, зафиксированные на публичном интерфейсе, делают такие манёвры заметными: полез в чужие внутренности — сломал чужие тесты.
— Возможность распараллелить команду. Когда у модуля есть тесты как контракт, команды могут работать параллельно, не договариваясь о каждой строчке. Без тестов любая параллельная работа по общему коду — это постоянные конфликты и ручная сверка. Об этом я подумываю отдельно рассказать в одном из будущих постов.
— Быстрая обратная связь при миграции. Переносишь код из монолита в модуль — тесты едут вместе с ним и сразу показывают, что перенеслось корректно, а что потеряло зависимость.
— Регресс вместо сюрпризов. Накопленная база тестов превращает каждое следующее изменение архитектуры из «полевого эксперимента» в рутинную операцию с предсказуемым результатом.
Заметьте замкнутый круг: тесты дешёвые, потому что код модульный; модуляризация безопасная, потому что есть тесты. Каждый шаг в одном направлении удешевляет следующий шаг в другом. Именно так синергия превращает два медленных процесса в один быстрый.
И обратно: тот же период дал мне понимание, что бывает «отрицательная синергия» — когда фокус на нескольких похожих задачах дублирует усилия и съедает эффект. Учились избегать и этого. Пишите в комментариях, если вам интересно обсудить такие примеры из моего или вашего опыта.
Полная история того, как мы это делали в 2022-м — с цифрами, ошибками и раскладкой по направлениям — в моей статье на Хабре ( https://habr.com/ru/companies/psb/articles/691896/ ).
Фокус и синергия — про выбор задач. Но есть и другой вопрос: как выбирать путь к цели. В следующем посте расскажу, почему не стоит ставить на одно решение: несколько параллельных подходов к одной цели почти всегда сильнее, чем один «самый правильный».
0
ответить
коммент скрыт — часть юзеров считает его токсичным или некорректным
коммент удалён