В предыдущих колонках я подробно рассказал о кошельке Миллера — неприятной закономерности, которая делает из сложности программного обеспечения проблему. Самый простой и очевидный способ борьбы с кошельком — это разделение программы на небольшие части, в каждой из которых не больше 5-10 сущностей. Но у этого простого и очевидного способа есть недостаток, озвученный еще Дэвидом Уилером в известном афоризме:
Любую проблему можно решить путём введения дополнительного уровня абстракции, кроме проблемы слишком большого количества уровней абстракции.
Практика показывает: нельзя просто брать и делить программу на части при повышении концентрации сложности. Сложность любит концентрироваться в одних и тех же «слабых» областях архитектуры. Деление этих областей на части быстро создает количество слоев абстракции, выходящее за границы разумного. И за границы кошелька Миллера. Это особенно хорошо видно в проектах на Java, для которых декомпозиция технически проста и предпочтительна с архитектурной точки зрения. Stack Trace серьезного проекта на Java обычно содержит сотни вызовов: платформа, middleware, контейнеры, логика самой программы, снова middleware, коммуникационные и вспомогательные слои, слои инкапсуляции и адаптации… Несмотря на то, что каждый конкретный вызов — это всего лишь несколько строчек простого кода, длина цепочки вызовов делает логику работы очень трудной для понимания.
Навыки, как способ расширения кошелька Миллера
К счастью, декомпозиция — это не единственный способ борьбы с кошельком Миллера. Среди множества других способов я хочу выделить способ расширить сам кошелек Миллера за счет вырабатывания навыков. И в этом нам поможет другая закономерность: чем больше мы тренируем какой-то навык, тем меньше нам нужно усилий для удержания его в фокусе внимания.
На тренингах я люблю иллюстрировать эту закономерность игрой в шахматы. Когда человек начинает изучать правила и играть, в его фокусе внимания только самые простые вещи: как ходят фигуры, какие из них под угрозой, не поставят ли мат в следующий ход. Кошелек Миллера полностью забит этой информацией, и больше внимания ни на что не хватает.
Человеческий мозг устроен так, что пытается приспособиться к повторяющимся действиям и минимизировать затраты энергии на их обработку. Со временем игроку уже не нужно держать в фокусе внимания правила, чтобы понимать, как ходят фигуры, какие есть на доске угрозы и будет ли мат. Выработанные навыки перестают занимать место в кошельке Миллера, освобождая его для более важных вещей: тактики и стратегии игры, создании ловушек для оппонента и всего того, что делает шахматы шахматами.
Навыки не занимают места в кошельке Миллера
Эта важная закономерность позволяет по-другому взглянуть на распределение сложности при разработке программного обеспечения. Код можно перемещать не только в исходные файлы проекта, но и в навыки программистов. Примером такой декомпозиции являются всевозможные фреймворки и библиотеки. Их ценность не только в готовом коде. Чем дольше разработчик пользуется фреймворком или библиотекой, тем лучше тренируются соответствующие навыки и тем меньше внимания требует сам код фреймворка. Хорошо знакомый с фреймворком разработчик почти не тратит усилий на восприятие кода фреймворка, что позволяет ему фокусировать внимание на действительно важных вещах: архитектуре, логике работы программы, контроле ошибок и многом другом.
Считается, что лучше всего разработчик понимает код, который написал сам. Поэтому большинство программистов, даже не зная о кошельке Миллера и проблеме сложности, инстинктивно пытаются выделить и повторно использовать свой код. Это не столько ускоряет разработку за счет повторного использования, сколько позволяет освободить место в фокусе внимания и не утонуть в сложности создаваемой программы.
Фреймворки и библиотеки: экономия фокуса внимания
Лучше всего разработчик будет работать со своим собственным кодом. Но если в команде больше одного разработчика, то позволить каждому из них писать свой фреймворк и набор стандартных библиотек — будет далеко не лучшим решением. Поэтому такой популярностью пользуются готовые фреймворки. Если все разработчики в команде хорошо знакомы с одним фреймворком, то они могут легко читать код друг друга, фокусируясь только на «отличиях» между известным им кодом и тем, что они видят. Через несколько месяцев работы с таким стандартным набором начнут вырабатываться навыки, разработчики будут быстро «узнавать» знакомые фрагменты кода и не тратить на это дефицитное внимание.
Единый стандарт кодирования в команде разработчиков и аккуратно подобранный набор инструментов крайне благоприятно влияют на работу команды. Но при этом каждый отдельный разработчик будет считать, что «сам бы он переписал все это намного лучше, и инструменты бы выбрал другие». Это абсолютно нормально, и менеджеру необходимо объяснять команде, для чего нужно придерживаться единых практик. Бездумное следование прочитанным где-то кулинарным рецептам понижает мотивацию и увеличивает трения в коллективе. А вот жесткая, но разумная и аргументированная позиция дисциплинирует команду, позволяет разработчикам тратить меньше времени на изобретения велосипедов и переписываний «не понравившегося» кода.
Велосипеды, конечно, изобретать не перестанут. И код переписывать будут. Такова человеческая природа, и пытаться совсем это устранить — хороший способ потерять хороших разработчиков. Понимание происходящих процессов, постепенное закрепление единых стандартов кодирования и набора библиотек — хорошее подспорье, чтобы и волки были сыты, и овцы целы, и писец не пришел.