JavaScript: что senior-ы ищут в коде и за что ставят минус

Онлайн-тренажер Python для начинающих

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

Начать курс

Ревью кода на JavaScript: что на самом деле бесит senior-ов

Каждый разработчик хотя бы раз получал пул-реквест с комментарием вроде «тут лучше переписать» или «это антипаттерн». Если вы Junior или Middle, такие замечания часто кажутся придирками. Но за каждым словом senior-а стоит реальный опыт: вызов на продакшене, баг в три часа ночи или падение производительности.

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

Статья будет полезна всем, кто пишет на JS: от новичков до опытных разработчиков, которые хотят прокачать качество кода.

1. Мутация входных данных: главный грех

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

Плохой пример

function addUser(users, newUser) {
  users.push(newUser); // мутация исходного массива!
  return users;
}

const allUsers = [{ id: 1 }, { id: 2 }];
const updated = addUser(allUsers, { id: 3 });
console.log(allUsers.length); // 3 — исходный массив изменён!

Как надо

function addUser(users, newUser) {
  return [...users, newUser]; // возвращаем новый массив
}

const allUsers = [{ id: 1 }, { id: 2 }];
const updated = addUser(allUsers, { id: 3 });
console.log(allUsers.length); // 2 — исходник не тронут

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

2. Магические числа и строки: убийцы читаемости

Сеньоры часто пишут в комментариях: «Что за число 86400?» или «Откуда взялась эта строка?». Магические значения делают код непонятным и усложняют его поддержку.

Плохой пример

function calculateDiscount(price) {
  if (price > 1000) {
    return price * 0.9;
  }
  return price * 0.95;
}

Как надо

const DISCOUNT_THRESHOLD = 1000;
const HIGH_DISCOUNT_RATE = 0.9;
const STANDARD_DISCOUNT_RATE = 0.95;

function calculateDiscount(price) {
  if (price > DISCOUNT_THRESHOLD) {
    return price * HIGH_DISCOUNT_RATE;
  }
  return price * STANDARD_DISCOUNT_RATE;
}

Совет: выносите все константы в именованные переменные или отдельный конфигурационный файл. Это упрощает ревью кода на JavaScript и делает его самодокументированным.

3. Ошибки с async/await и промисами

Асинхронный код — зона, где спотыкаются даже мидлы. Senior-ы на ревью обращают внимание на два основных момента: неправильная обработка ошибок и смешивание синтаксисов.

Плохой пример (промис без catch)

async function loadData() {
  const response = await fetch('/api/data');
  const data = await response.json();
  return data;
}

Как надо

async function loadData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Ошибка загрузки данных:', error);
    throw error; // пробрасываем дальше, если нужно
  }
}

Важно: никогда не игнорируйте ошибки. Пустой catch — это зло. Если ошибка произошла, вы должны хотя бы залогировать её, а лучше — корректно обработать.

Ещё одна частая ошибка — забытый await

function processUsers(users) {
  users.forEach(async (user) => {
    await updateUser(user); // forEach не ждёт выполнения
  });
  console.log('Все пользователи обновлены'); // сработает раньше
}

Используйте for...of или Promise.all:

async function processUsers(users) {
  for (const user of users) {
    await updateUser(user);
  }
  console.log('Все пользователи обновлены');
}

4. Избыточная вложенность и ранний выход

Сеньоры терпеть не могут глубокие if-else конструкции. Чем больше вложенность, тем сложнее читать код. Правило хорошего тона — использовать ранний возврат (early return).

Плохой пример

function processOrder(order) {
  if (order) {
    if (order.items && order.items.length > 0) {
      if (order.paymentStatus === 'paid') {
        // логика обработки
        return 'Order processed';
      } else {
        return 'Payment pending';
      }
    } else {
      return 'Empty order';
    }
  } else {
    return 'No order';
  }
}

Как надо

function processOrder(order) {
  if (!order) return 'No order';
  if (!order.items || order.items.length === 0) return 'Empty order';
  if (order.paymentStatus !== 'paid') return 'Payment pending';

  // логика обработки
  return 'Order processed';
}

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

5. Сравнение с == вместо ===

Казалось бы, банальность, но до сих пор встречается. Senior-ы на ревью кода на JavaScript обязательно поправят == на ===. Почему? Потому что == приводит типы, и это может давать неожиданные результаты.

console.log(0 == false);  // true
console.log('' == false); // true
console.log(null == undefined); // true

// А с === всё предсказуемо:
console.log(0 === false);  // false
console.log('' === false); // false
console.log(null === undefined); // false

Правило: всегда используйте строгое сравнение === и !==. Исключение — только когда вы осознанно хотите проверить и null, и undefined одновременно (value == null).

6. Неправильное использование map, filter, reduce

Эти методы появились, чтобы сделать код декларативным. Но многие превращают их в мутантов: используют map для побочных эффектов или reduce там, где хватило бы filter.

Плохой пример (map как forEach)

users.map(user => {
  console.log(user                

Блоги

Рекомендаций по книгам