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

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

1. Прочие заявления.

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

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

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

Как тогда мы можем заменить оператор else? С возвратами. Вместо того, чтобы писать:

if (something) {
 return true;
} else {
 return false;
}

Мы можем написать:

if (something) {
 return true;
}
return false;

2. Операторы переключения.

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

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

Операторы Switch можно заменить объектами, которые действуют как таблицы поиска.

Рассмотрим этот оператор switch:

switch (user.status) {
 case 'online':
   return 'User is online.';
 case 'offline':
   return 'User is offline.';
}

Мы можем создать объект с этими сообщениями о состоянии и создать функцию, которая ищет этот статус в объекте, например:

const userStatuses = {
  online: 'User is online.',
  offline: 'User is offline.',
  default: 'User status is unknown.'
};
function getUserStatus(status) {
  return userStatuses[status] || userStatuses.default;
}

3. Функции с несколькими аргументами.

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

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

  1. Аргументы на самом деле представляют собой список, что означает, что они следуют определенному порядку. Это также означает, что если вы случайно поменяете местами аргументы, то вы успешно взломали функцию. Они делают функцию очень хрупкой.
  2. Многие аргументы затрудняют чтение вызовов функций. Это еще хуже, если есть логические аргументы, например:
doSomething(true, null, userId, false);

Это невероятно тяжело читать.

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

Другой способ заменить его — использовать объектный аргумент. Например, в JavaScript это очень чисто, поскольку становится читабельным. А в реальной функции вы можете деструктурировать аргумент объекта, чтобы свойства стали переменными.

Вызов функции может выглядеть так:

doSomething({ notifyUser: true });

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

function doSomething({ notifyUser } = {}) {
 // ...
}

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

4. Причудливые остроты.

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

Я не говорю о лямбда-выражениях или служебных методах, которые упрощают работу, например, о нативных методах Array в JavaScript. Я говорю о сложных логических выражениях в одну строку, которые делают тяжелые вещи, которые никто, кроме автора, не может понять.

Каждый однострочный код можно разбить на несколько строк, что сделает код намного чище.

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

Независимые переменные также являются хорошим способом объяснить сложное логическое выражение. Вместо того, чтобы писать:

if (person.age >= 65 && person.isEmployed === false) {
// ...
}

Мы можем написать:

const hasRetired = person.age >= 65 && person.isEmployed === false;
if (hasRetired) {
// ...
}

И оператор if внезапно становится намного чище, так как теперь его легче читать людям.

5. Комментарии.

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

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

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

Комментарии нужно просто удалять. Он по-прежнему будет сохраняться в истории файлов, пока в проекте есть какой-либо контроль версий. Одно небольшое предложение, если вы решите удалить закомментированный код, состоит в том, чтобы убедиться, что вы добавили осмысленное сообщение коммита, такое как «Удалить метод…», чтобы вы могли легко проследить назад к тому коммиту, в котором код был удален.

Вывод

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