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

Это вторая часть серии:

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

Сценарий 4

const chemicalSymbols = {
  Sodium: "Na",
  Hydrogen: "H",
  Helium: "He",
  Oxigen: "O",
};
function getSymbol(name) {
  const symbol = chemicalSymbols[name];
  if (symbol) {
    return symbol;
  }
  console.log("symbol not found");
  return "not found";
}

В чем проблема?

(не читайте, пока не закончите с приведенным выше кодом)

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

Решение

Способ исправить это — иметь лучшие журналы и возвращать что-то другого типа, чем обычное возвращаемое значение. Например, null вместо строки.

function getSymbol(name) {
  const symbol = chemicalSymbols[name];
  if (symbol) {
    return symbol;
  }
  console.log(`getSymbol:: symbol not found for ${name}`);
  return null;
}

Но гораздо лучшая альтернатива — выдать ошибку. Таким образом, если есть проблема, ошибка предотвратит распространение и приведет к сбою программы, если она не будет обработана. Вы всегда можете использовать try/catch для обработки ошибки.

function getSymbol(name) {
  const symbol = chemicalSymbols[name];
  if (symbol) {
    return symbol;
  }
  throw new Error(`symbol not found for ${name}`);
}

Сценарий 5

function getDisplayImage(article, watermark) {
  let image
  if(article.image && article.displayImage) {
    if(watermark){
      image = applyWatermark(article.image, watermark)
    } else {
      image = article.image
    }
  } else {
    image = null
  }
  return image
}

В чем проблема?

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

Решение

Полезный шаблон для разбиения этой логики на более мелкие и более понятные фрагменты — «вернуться раньше». Мы можем выполнить обратное сравнение первого if и немедленно вернуть null. Тогда другие операторы не нужно вкладывать друг в друга, так как им больше не нужно проверять изображения статей.

function getDisplayImage(article, watermark) {
  let image
  if(!article.image || !article.displayImage) {
    return null
  }
  if(watermark){
    return applyWatermark(article.image, watermark)
  }
  return image
}

Сценарий 6

if (
  typeof AUTH_ENABLED === 'string' &&
  AUTH_ENABLED === 'true' &&
  !skipAuthentication &&
  user.email
) {
  console.info('Welcome back, ' + user.name);
}

В чем проблема?

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

Решение

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

const authEnabled = typeof AUTH_ENABLED === 'string' && AUTH_ENABLED === 'true';
const authIsEnforced = authEnabled && !skipAuthentication;
const userLoggedIn = user && user.email;
if(authIsEnforced && userLoggedIn) {
  console.info('Welcome back, ' + user.name);
}

И это было последнее упражнение для этого поста. Напоминаем, что ознакомиться с упражнениями для части 1 серии можно здесь.

Первоначально опубликовано на ederdiaz.dev