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 load — на реальную работу.
Собственно, вся идея Developer Experience в значительной степени сводится к одной формуле: найти и устранить 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».
Практические стратегии снижения
Упрощайте тулчейны. Каждый инструмент, который разработчик должен знать, добавляет когнитивную нагрузку. Регулярно проводите аудит: действительно ли нам нужны три системы мониторинга и два способа деплоя?
Ограничивайте scope владения. Правило «две пиццы» от Amazon — грубая, но рабочая эвристика. Скелтон и Пайс формулируют точнее: команда должна владеть таким объёмом кода, который она реально может удерживать в коллективной рабочей памяти.
Сокращайте контекстные переключения. Выделяйте блоки непрерывного времени для глубокой работы и защищайте их от митингов — никакие инструменты не компенсируют постоянное дёрганье между задачами.
Инвестируйте в документацию. Хорошая документация позволяет «выгрузить» знания из голов людей в артефакт, который можно прочитать в нужный момент.
Стандартизируйте, но не до фанатизма. Единообразие снижает extraneous load, но чрезмерная стандартизация сама становится источником нагрузки, когда стандарт не подходит под задачу.
Рекомендации
Соберите команду и обсудите, что отнимает больше всего сил, но не создаёт ценности. Составьте список и приоритизируйте — обычно первые три-пять пунктов дадут 80% эффекта. Сфокусируйтесь на extraneous load, потому что именно его можно убрать без компромиссов по функциональности. А germane load защищайте — время на изучение системы окупается многократно, даже если кажется, что команда «просто сидит и читает код».