Обложка статьи «10 принципов хорошего кода и хорошего программиста»

10 принципов хорошего кода и хорошего программиста

Оригинальная статья

Спагетти-коды, огромные цепочки «if-else» и программы, которые ломаются после изменения переменной, функции размером в сотни строк и раздражающие имена переменных и классов? Это лишь некоторые из постоянно встречающихся в работе недочётов. И результат того, что будет, если попытаться превратить надвигающийся дедлайн в готовый продукт, внутри которого скрывается проблемный и перегруженный код.

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

KISS

KISS расшифровывается как «чем проще — тем лучше». Этот принцип стоит использовать для решения разных жизненных задач, и он очень помогает в написании кода.

Например, вы собираетесь разработать мобильную игру — и у вас появился шанс это сделать. Не факт, что вы создадите следующую Candy Crush или Clash Royale. Поэтому постарайтесь оставить проект маленьким и простым. А если он уже прост — сделайте его ещё проще. Дополнительные функции появятся, когда вы сделаете стабильно работающую базу.  Впрочем, можете не придерживаться этого правила, перегрузить софт функциями и «взорвать» весь проект.

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

DRY

DRY означает «не повторяйся», и это следует понимать буквально. Если ваш код повторяется и повторяет одни действия, вы нарушаете это правило. Несколько функций делают одно и то же? Рефакторинг в одну функцию. Содержат ли несколько переменных одни и те же данные? Рефакторинг в одну переменную.

Против принципа DRY выступает WET: «пиши всё дважды» или «потрать время зря». Основной вопрос для определения нарушителей правил заключается в следующем: сколько мест необходимо изменить, чтобы пофиксить программу? Если ваш ответ «больше одного», значит, вы действовали вопреки принципу DRY.

Представьте, что вы разрабатываете музыкальное приложение с тремя страницами: альбомы, названия и плейлисты. Для каждой из этих страниц существует собственный класс, а для каждого класса — своя функция «fetchMusic= ()». Так почему же в коде есть три места, которые ведут себя одинаково? Извлеките эту функцию и не действуйте против принципа DRY.

Открытый/Закрытый

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

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

Если во время основного релиза кто-то серьёзно модифицирует код, требуется слияние всех изменений. Это занимает много времени и может привести к появлению багов. Не говоря уже о том, что те, кто переписывал код, наделают своих ошибок. Следование принципу «открытый/закрытый» защищает ваш софт от таких проблем, потому что простые расширения не могут взломать ни один существующий код.

Построение, а не наследование

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

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

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

Отдельная ответственность

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

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

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

Разделение задач

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

Хорошо известен пример MVVM-Pattern (Модель, Представление и Модель представления), где приложение разбивается на три не пересекающихся части. Модель данных содержит необработанные данные и выполняет некоторый алгоритм. Модель представления содержит агрегированные данные, которые должны отображаться, но не знает, как отобразить их. А Представление отображает эти данные наилучшим образом. Кроме того, только у него есть возможность взаимодействовать с пользователем и реагировать на него напрямую.

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

YAGNI

Принцип хорошего программиста «Тебе это не нужно» хочет, чтобы вы не прописывали функции, которые могут и не понадобиться в будущем. Потому что велика вероятность, что они вам вообще не понадобятся. Зато усложнят код.

Можете рассматривать это как строгое соблюдение принципов DRY и KISS. В основном его нарушают неопытные разработчики. Они пишут очень абстрактный код и в итоге получают нечто раздутое и невозможное в использовании.

Избегайте преждевременной оптимизации

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

Вы не можете обнаружить недоработку, пока она не обнаружит вас! Программа должна сама показать вам «узкое место», потому что вы не найдете его, изучая код самостоятельно.

Рефракторинг, рефракторинг, рефракторинг

Многие знакомы с этим принципом хорошего программиста, но принимают не все: «код редко получается совершенным с первого раза» — Роберт К. Мартин.

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

Если же вы посмотрели на старый код и поняли, что не можете его улучшить, есть только 2 варианта:

  1. Вы настоящий мастер, и сделали всё идеально;
  2. Вы ещё недостаточно прокачались.

Я очень сомневаюсь, что кто-то может когда-либо прийти к варианту 1.

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

Чистый код лучше, чем «умный» код

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

«Умный код» делает как можно больше в одной строке вместо того, чтобы разбить всё для лучшего восприятия. Или содержит странные имена переменных/методов/классов вместо выразительных. Всё, что заставляет кого-то сказать «Подождите, что?», можно идентифицировать как «умный код».

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

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