Недавно я прочитал отличную статью в блоге Coding Unicorn на dev.to под названием Гибкий код считается вредным. Простите за чрезмерное использование заголовка считается вредным, статья была чрезвычайно наводящей на размышления. Она довольно короткая, и я рекомендую вам прочитать ее.

Она делает интересное замечание о том, что создание гибкого кода означает, что код может быть легко расширен в будущем, но эти точки расширения имеют свою цену в виде повышенной сложности. Это означает, что код на самом деле сложнее понять и сложнее изменить.

Она также упоминает Парадокс использования/повторного использования (еще одно хорошее чтение, хотя и немного абстрактное), который указывает на то, что вещи, которые легко использовать, трудно использовать повторно.

Ее резюмирующая точка зрения такова: «гибкий и абстрактный код сложен в использовании, а также сложен для понимания». Этот момент, безусловно, заслуживает внимания. Когда мы делаем код более гибким и абстрактным, становится ли его сложнее использовать и понимать?

Давайте проанализируем это на примере кода.

Давайте воспользуемся приложением, которое упорядочивает и отображает статьи. Вот структура примера статьи (очень упрощенная):

Как указано, каждая статья может быть помечена одним или несколькими тегами. В нашем интерфейсе, если мы выбираем один тег, мы хотим отфильтровать список статей по этому тегу. Но мы также хотим иметь возможность углубляться. Например, после выбора всех статей о javascript мы можем захотеть перейти только к тем, которые связаны с Express. Итак, как только мы выберем тег и отфильтруем статьи только с этим тегом, нам нужно создать список тегов, которые содержат все эти статьи. Нам нужно будет убедиться, что этот список не дублируется, а также нам нужно удалить выбранный тег из списка.

Убедитесь, что вы понимаете, каковы требования нашей задачи, прежде чем пытаться читать код. Теперь давайте создадим алгоритм для этого, учитывая список статей и выбранный тег:

Чтобы понять что-то незнакомое в приведенном выше коде, смотрите примечания к алгоритму здесь.

Я написал этот алгоритм очень просто. Я пытался заставить его просто работать. Я не добавлял абстракций. Я бы посчитал это самым быстрым способом заставить его работать. Он выполняет свою работу, и код, возможно, «простой», поскольку практически не использует абстракций. Делает ли это его простым в использовании? Конечно, вызвать функцию несложно.

Но что, если мы применим несколько типичных рефакторингов кода и введем некоторые абстракции?

Упражнение.В качестве забавного упражнения попробуйте взять этот алгоритм и исправить его, прежде чем смотреть на мое скорректированное решение. Просто сделайте его лучше и читабельнее в соответствии с вашими собственными суждениями. Вы можете нажать эту ссылку и внести свои изменения. Затем сравните с тем, что я сделал с моим исправлением, показанным ниже, и посмотрите, пришли ли вы к похожему решению.

А теперь вот рефакторинг алгоритма с добавлением того, что я считал уместными абстракциями:

Посмотрите, что произошло. Я создал несколько подфункций и один класс TagList, и теперь у меня есть все эти многократно используемые части, которые можно было бы скомпоновать для выполнения других задач. Большинство этих функций можно легко использовать повторно. TagList можно использовать во многих других местах, выполняя другие задачи с тегами в подобном приложении.

Я добавил абстракции. Возможно, я сделал код более расширяемым и пригодным для повторного использования. Я усложнил использование или понимание? Вам было бы очень трудно убедить меня, что исходное решение было лучше в любом случае.

Могли бы вы сказать, что этот код более удобочитаем, чем исходный алгоритм? Хотя удобочитаемость может быть субъективной, я предполагаю, что большинство людей скажут, что новый алгоритм более удобочитаем.

Один важный момент об абстракциях, который важно понять, заключается в том, что абстракция — это, по сути, способ обработки нескольких более мелких частей вместе с более простой, единственной дескриптором. Хорошим примером абстракции является руль автомобиля. Это простой инструмент, который на самом деле управляет очень сложным механизмом из стержней, шестерен и различных деталей. Когда мы абстрагируем часть нашего кода, мы даем себе более простой способ работать с этим кодом и рассуждать о нем. Это снижает нашу когнитивную нагрузку. В этой фантастической статье о программировании и когнитивной нагрузке вы можете прочитать о том, что когнитивная нагрузка, по сути, является нашим жестким пределом как программистов. Абстракции позволяют нам работать лучше и быстрее.

Конечно, как и все вещи, это можно довести до крайности. Обычно мы называем это чрезмерной инженерией или принципом ЯГНИ.

Итак, добавляя эти абстракции, не перестарался ли я с решением? Было ли слишком много добавления класса TagList? Я попытался реализовать алгоритм без этого класса и, честно говоря, почувствовал, что это упростило код. Еще одно забавное упражнение: возьмите мой окончательный алгоритм и попробуйте провести его рефакторинг и удалить TagList. После того, как вы спросите себя, считаете ли вы, что код стал проще в использовании?

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

Так что да, мы можем перепроектировать вещи, но отказ от абстракций вряд ли облегчит написание, чтение или расширение нашего кода.

Соглашаться? Не согласен? Подпишитесь на мою рассылку здесь.

Счастливого кодирования

Посетите нас: thinkster.io | Facebook: @gothinkster | Твиттер: @GoThinkster