Синергия и жесткая фокусировка

В прошлом посте, я рассказал, что найм сотрудников А+ на стадии активного роста может лишь ухудшить ситуацию. И объяснил это рассуждениями Адизеса. А еще ранее я рассказывал, что во время взрывного роста нам приходилось решать множество задач одновременно. В том же посте я упомянул, что естественным решением этой проблемы является жесткая фокусировка. Сегодня хочу поговорить как раз о ней и о тех плюсах, которые она дает.

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

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

И мы это ощутили на себе: команда получила 20% рабочего времени на «свои» задачи, и за эти 20% усилий мы ускорили разработку примерно на 80%. Так работает Парето, если фокус держать жёстко, а не «по остаточному принципу».

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

Например, мы последовательно и сфокусированно «навалились» на 2 самых главных направления: — модульные тесты — тщательно покрывать код тестами (детально про них я напишу один из будущих постов); — модуляризация — резать монолит на изолированные модули, о чем я подробно написал в этом цикле постов (тут, тут, тут STAR и про сложности).

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

Как модуляризация помогает тестам:

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

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

— Тесты как спецификация контракта. Границы модуля — это и есть его публичный контракт. Набор юнит-тестов фиксирует этот контракт буквально: сломал обещание — тест краснеет. В монолите «контракта» нет, есть место в коде, где всё сцеплено со всем.

— Локализация отказа. Упал тест на модуль — понятно, где искать, и понятно, чья это зона ответственности. В общем коде падение теста — начало детективного расследования.

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

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