Cognitive Load Theory для разработчиков
Intrinsic, extraneous и germane load — как это влияет на продуктивность инженеров
Когда умные люди работают медленно
Знакомая картина: в команде сидят опытные инженеры, мотивации хватает, но скорость поставки падает квартал за кварталом. Менеджмент подозревает лень, кто-то предлагает добавить метрик и контроля. Чаще всего причина другая — люди перегружены когнитивно. Рабочая память переполнена, и никакая мотивация это не починит, пока не убрать лишнюю нагрузку.
Теорию когнитивной нагрузки (Cognitive Load Theory, CLT) сформулировал Джон Свеллер в 1988 году в контексте образовательной психологии. Он разбирался, почему студенты не усваивают материал, даже когда его хорошо объяснили. Ответ упирался в ограничения рабочей памяти: человек одновременно удерживает в голове примерно 4–7 элементов, и за этим порогом продуктивная работа невозможна. В 2010-х теорию начали прикладывать к разработке ПО, и интуитивные ощущения про «сложные проекты» получили строгий язык описания.
Три типа когнитивной нагрузки
Intrinsic load — внутренняя сложность
Нагрузка, которая принадлежит самой задаче. Распределённые системы сложны по природе. Конкурентное программирование требует удерживать в голове множество состояний. Бизнес-логика страховой компании запутана не потому, что кто-то плохо её спроектировал, а потому что страхование — это объективно сложная предметная область с большим количеством краевых случаев и нормативки.
Intrinsic load нельзя убрать, не меняя саму задачу. Но её можно держать в управляемых рамках: дробить задачи помельче, выстраивать абстракции, которые прячут детали до момента, когда они понадобятся, делить команды так, чтобы каждой доставался посильный кусок доменной сложности (отсюда Team Topologies).
Extraneous load — паразитная сложность
С точки зрения Developer Experience именно сюда уходят основные усилия. Extraneous load — это лишняя когнитивная нагрузка, которая не имеет отношения к задаче, но всё равно съедает ресурсы рабочей памяти. Невнятная документация. Запутанный процесс деплоя. Устаревшие инструменты, которые падают по случайным причинам. Двадцать шагов для подъёма локального окружения. Всё это — extraneous load.
Когда разработчик тратит час, чтобы понять, какой из трёх способов деплоя сейчас актуален, или полдня воюет с flaky-тестами, не связанными с его изменениями, ресурсы рабочей памяти уходят в задачи, которые не создают ценности. Чем больше extraneous load, тем меньше остаётся на intrinsic — на саму работу.
Большая часть DX-практики сводится к одной формуле: найти и убрать extraneous cognitive load. Ускорение CI-пайплайна, шаблон сервиса в Internal Developer Platform, страница документации, которая отвечает на вопрос с первого захода — всё это снижение extraneous load.
Germane load — продуктивная нагрузка
Третий тип — полезная нагрузка, связанная с построением ментальных моделей и глубоким пониманием системы. Когда разработчик разбирается в архитектуре проекта, осваивает незнакомый паттерн, погружается в предметную область — когнитивные ресурсы тратятся, но это инвестиции. В следующий раз аналогичная задача решится быстрее и аккуратнее.
Germane load хочется максимизировать. Загвоздка в том, что для него нужно свободное место, а место занято extraneous load. Если разработчик весь день воевал с кривым тулингом, на вдумчивое изучение новой архитектурной модели или глубокий code review ресурсов уже не остаётся.
Что показывают исследования
Йо Ханнай из Университета Осло провёл серию работ о когнитивной нагрузке в разработке ПО и пришёл к нескольким понятным выводам. Контекстные переключения между задачами — один из главных источников перегрузки: каждое переключение требует «выгрузить» одну ментальную модель и «загрузить» другую, на это уходит 15–25 минут (Пол Грэм называл это maker’s schedule).
Размер кодовой базы, которую команда обязана знать и поддерживать, тоже коррелирует с когнитивной нагрузкой. Команда из пятнадцати микросервисов, каждый из которых написан немного по-своему и деплоится своим способом, будет жить в перегрузке, даже если по отдельности сервисы простые.
Как измерить когнитивную нагрузку
Прямое измерение — задача нетривиальная, но есть рабочие подходы. Самый простой — субъективный опрос. Попросите команду оценить по шкале от 1 до 10, насколько тяжело работать с каждой из подсистем, которые она поддерживает. Результаты обычно ложатся близко к реальности: разработчики хорошо чувствуют, где им больно, даже если не могут это формализовать.
Подход посложнее — анализ задач. Посчитайте, сколько разных контекстов (репозиториев, сервисов, конфигов, команд) нужно затронуть для выполнения типичной фичи. Чем больше контекстов, тем выше нагрузка. Если добавить поле в API означает изменить код в четырёх репозиториях, обновить два конфига и согласовать с тремя командами, проблема с extraneous load налицо.
Полезны и косвенные индикаторы: длительность онбординга новых инженеров, частота ошибок при рутинных операциях, количество вопросов в корпоративном чате уровня «а как сделать X».
Что снижает нагрузку
Упрощение тулчейнов. Каждый инструмент, который разработчик обязан знать, добавляет когнитивной нагрузки. Регулярный аудит: действительно ли нужны три системы мониторинга и два способа деплоя?
Ограничение скоупа владения. «Правило двух пицц» от Amazon — грубая эвристика, но рабочая. Скелтон и Пайс формулируют точнее: команда должна владеть таким объёмом кода, который она удерживает в коллективной рабочей памяти.
Меньше контекстных переключений. Выделяйте инженерам блоки непрерывного времени для глубокой работы и защищайте их от митингов. Никакие инструменты не компенсируют постоянное дёрганье между задачами.
Документация. Хорошая документация позволяет выгрузить знания из голов в артефакт, который можно перечитать в нужный момент.
Стандартизация в меру. Единообразие снижает extraneous load. Чрезмерная стандартизация сама становится источником нагрузки, когда стандарт не подходит под задачу.
Рекомендации
Соберите команду и обсудите, что отнимает больше всего сил и не создаёт ценности. Список приоритизируйте: обычно первые три-пять пунктов дадут 80% эффекта. Фокус — на extraneous load, его можно убрать без компромиссов по функциональности. Germane load, наоборот, защищайте: время на изучение системы окупается многократно, даже если со стороны кажется, что команда «сидит и читает код».