В течение многих лет я был большим поклонником красивого кода, еще в руби я был поражен тем, что я мог сделать в одну строку. С Java мы можем транслировать, отображать, а затем собирать!

Но со временем я прочитал много впечатляющих оптимизаций, маленьких хитростей и умных алгоритмов, и меня все меньше и меньше радовали эти открытия. Вот почему я гонялся за фенечками, и они почти всегда были какой-то очень элегантной выразительностью на новом языке (об этом могут свидетельствовать конвертации Ruby из Java) или приемом, который я вряд ли буду использовать.

Когда я присоединился к сообществу Ruby, я всегда слышал о ясности кода и коде, читабельном благодаря наплыву гибких методологий, отбрасывающих почти всю проектную документацию. Так что мое эстетическое чувство обратилось к ясности кода.

Но почему так важна читабельность кода?

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

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

Но год спустя никто не знает систему так хорошо, поэтому им нужно будет снова прочитать код и извлечь из него уроки. А если к команде присоединится новичок, то больше всего он узнает из кода.

Если вы изо всех сил пытаетесь прочитать код, как, черт возьми, вы собираетесь его исправить? — Бен Хоск

Итак, как нам улучшить читабельность?

Именование, Боже, именование!

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

Код должен делать только то, что ему нужно, без кучи абстракций и комментариев. Именование сложно, но важно, потому что метод data обновляет некоторые данные для объекта, должен кричать, что он обновляет данные объекта и только это! — но это не SRP, и я объясню это в другой раз.

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

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

int d; // elapsed time in days
int elapsedTimeInDays;

Хороший код должен быть понятным без строчки комментариев и самодокументируемым.

Закомментированный код сбивает с толку. Кто-то удалил его временно? Это важно? Когда это было прокомментировано? Он мертв, избавьте его от страданий. Просто удалите его.

Выкройки, друг мой, выкройки!

Еще в 2013 году Sand Metz создал некоторые правила для разработчиков.

_Есть четыре правила._

1. Классы не могут быть длиннее ста строк кода.

2. Методы не могут быть длиннее пяти строк кода.

3. Передавайте в метод не более четырех параметров. Опции хэша — это параметры.

4. Контроллеры могут создавать только один объект. Следовательно, представления могут знать только об одной переменной экземпляра, и представления должны отправлять сообщения только этому объекту (@object.collaborator.value не разрешено).

И, на мой взгляд, самое интересное правило — пять строк на правило метода.

Мы согласились, что if, else и end — это строки. В блоке if с двумя ветвями каждая ветвь может быть только одной строкой.

public void validateActor() {
  if (actor_type == 'Group') {
    userMustBelongToGroup()
  } else if (actor_type == 'User') {
    userMustBeTheSameAsActor()
  }
}

Пять строк гарантировали, что мы никогда не используем else с else if.

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

Вы должны нарушать эти правила, только если у вас есть веская причина или ваша пара позволяет вам — Санди Мец

Защитные оговорки могут быть всем, что вам нужно!

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

Начнем с фрагмента кода:

public void updateData(Data data) {
  if (data == null) {
    return;
  } else if (data.isPresent()) {
    // do stuff here
  } else {
    trow new Exception(msg);
  }
}

А как насчет следующего?

public void updateData(Data data) {
  if (data == null) return;
  if (!data.isPresent()) trow new Exception(msg);
  // do stuff here
}

Довольно часто в кодовой базе можно найти большие блоки if, потому что это связано с тем, что наш мозг работает по-разному: мы склонны думать «делать что-то, если оно разрешено», а не «делать что-то, если оно включено, но если оно не разрешено, то делать». ничего такого".

Итак, зачем эти рекомендации?

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

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

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

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

if (readableCode()) { 
  beHappy(); 
} else {
  refactor();
}