Ревью кода на 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