Мысли вслух Разработка

Хороший код = скучный код

-
13 июня, 2018

Эта статья появилась в дополнение к стандартам кода в нашей компании. Стандартизацией и ревью кода мы начали заниматься спустя 2 года совместной работы, когда я стал тим-лидом команды и когда количество проектов над которыми мы работаем и которые были на поддержке стало расти. Где-то 2 года назад, ко мне подошел тим-лид и сказал: «Ну вот то что у нас стандарты есть и они доступны новичкам быстро и удобно это хорошо. Но это много и по-технарски, а главное, новичку не понятно зачем их соблюдать. Давай напишем для всех и понятным языком, почему эти стандарты им надо использовать.» Текучка джунов на тот момента была большой и мне идея понравилась. Мы договорились, подключили обоих сеньоров, и по одному представителю от мидлов и джунов, с которыми обсудили стандарты и попытались найти ответ почему эти стандарты нужно использовать.

Вот что у нас получилось.

[sendpulse-form id=»278″]

Программисту нравится думать, что он пишет хороший код. Ну или, что он пишет больше хорошего кода, чем плохого. В чем преимущества скучного хорошего кода?

Простота отладки, чтения, объяснения

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

Выносимость за пределы проекта

Скучный код не использует глобальных состояний, не порождает побочных эффектов и старается уменьшить свою связанность с проектом, в котором он живёт. Скучнейшим образом происходят присвоения значений, которые для каждой переменной случаются лишь раз и избавляют нас от возможности увлекательного расследования кто же и когда изменил вот это состояние. Скучный код делает лишь то, что должен и не полагается на какие-то неявно высказанные предположения.

Код, использующий неявное поведение, может быть основан на каком-нибудь недокументированном, но уже реализованном функционале. Например, в мире написана целая куча НЕВЕРНОГО кода, который полагается на то, что функция файловой системы, возвращающая список директорий, вернёт их в отсортированном по алфавиту порядке. Это и вправду часто работает именно так, но ровно до того момента, пока не ломается по «непонятным» причинам. А на самом деле просто никто никогда этой сортировки не гарантировал.

Если написанный вами код опирается на какие-то неявные предположения — вам нужно держать их в голове, что уже само по себе усложняет поддержку такого кода. Вам просто не хочется возвращаться к работе над ним, ведь кроме чтения написанных срок придётся также строить в голове общую картину (с учётом её неявных частей). Это сложно. А ещё иногда неявные предположения ломаются из-за внешних факторов и тогда начинается мучительный процесс согласования кода с новой картиной мира.

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

Скучный код берет лучшие практики из разных языков программирования

Переусердствовать с многословностью достаточно легко, но я всё же согласен с Питоновским Дзеном: «Явное лучше, чем неявное». Java, возможно, заходит в многословности слишком далеко и каждый раз, когда нам нужно прочитать все строки файла, приходится писать одни и те же несколько строк кода. Альтернативой этому будет какая-нибудь обёртка, которая возьмёт на себя эту обязанность, но лишит нас некоторой гибкости (а если нужно прочитать не все строки? а если не по порядку? а если не с начала? и т.д.).

Я пытаюсь взять лучшее из обоих миров, разделяя мой API на слои. «Нижний» слой написан в Java-стиле: маленькие компоненты, простое поведение, но требуются некоторые усилия, чтобы собрать из них что-то действительно полезное. «Верхний» слой ставит во главу человекочитаемость и практичность использования: пользователю будет легко использовать API правильным образом, поскольку сама его структура располагает к этому.

Скучный код — модульный или разделимый

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

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

Перефразируя отличное объяснение Дэвида Парнаса: компонент существует для того, чтобы спрятать от остальных компонентов системы какое-то сложное решение или решение, которое с высокой вероятностью может измениться в будущем.

Бизнес-логика, даже достаточно запутанная, не обязательно является тем Гордиевым узлом, который следует бросаться разрубать. Если вы не можете легко заменить компонент, возможно, не стоит начинать с разделения его на отдельные компоненты, ведь более важная его проблема в том, что он не скрывает достаточного от остальной системы.

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

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

Подводя итоги

Старайтесь писать код, который не требует от вас держать в голове его полностью при чтении или изменении. Разделения кода на слои и дробление бизнес-логики на компоненты в этом помогает, но на самом деле просто старайтесь не писать код, который бы со временем вас смутил или, того хуже, заставил ужаснуться.

Старайтесь писать скучный код.

ТЕГИ

Добавить комментарий

Николай Сарры
Харьков, Украина

Меня зовут Николай, я руководитель проектов по внедрению Битрикс24 и его долгосрочному сопровождению. Лофт с заметками, статьями, идеями и мыслями по управлению проектами, использованию гибких методологий разработки. Здесь собраны мои мысли, решения, заметки и статьи. В основном по управлению проектами, PHP-разработке и используемым инструментам, обзоры прочитанных статей, тезисы посещенных конференций.