Когда не стоит использовать дублирующий код?

Ответ

В моей практике разработки на Node.js я избегаю дублирования кода в следующих случаях:

1. Бизнес-логика и валидация

// Плохо: дублирование валидации email
function registerUser(userData) {
  if (!userData.email.includes('@')) {
    throw new Error('Invalid email');
  }
  // регистрация
}

function updateUser(userData) {
  if (!userData.email.includes('@')) {
    throw new Error('Invalid email');
  }
  // обновление
}

// Хорошо: единая функция валидации
function validateEmail(email) {
  const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
  return emailRegex.test(email);
}

2. Конфигурация и подключения В Node.js проектах я выношу конфигурацию базы данных, настройки логгера или клиентов внешних API в отдельные модули:

// database.js
const knex = require('knex');

const dbConfig = {
  client: 'pg',
  connection: process.env.DATABASE_URL
};

module.exports = knex(dbConfig);

// Теперь используется во всех модулях
const db = require('./database');

3. Middleware в Express.js

// Дублирование проверки аутентификации
app.get('/api/profile', (req, res) => {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  // логика
});

app.get('/api/settings', (req, res) => {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  // логика
});

// Лучше: middleware
const authMiddleware = (req, res, next) => {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
};

app.get('/api/profile', authMiddleware, profileHandler);
app.get('/api/settings', authMiddleware, settingsHandler);

Когда дублирование может быть оправдано:

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

Ответ 18+ 🔞

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

Вот смотри, есть места, где дублировать — это просто пиздец какой-то грех, ёпта.

1. Вся эта ваша бизнес-логика и проверки Представь, ты пишешь функцию для регистрации юзера и для его обновления. И в обеих тупо копипастишь проверку мыла. Ну это же манда с ушами получается! Завтра заказчик придет и скажет: «А давайте мыло теперь проверять по новой схеме, там три собаки должно быть». И ты пойдешь по всему проекту, как угорелый, искать все эти if (!userData.email.includes('@')). Овердохуища работы, а главное — накосячить проще простого. Один раз забудешь — и всё, приехали. Выноси в отдельную функцию validateEmail и спи спокойно, блядь.

2. Конфиги и подключения к базе Это вообще классика, ядрёна вошь. Ты в каждом файле, где нужно с базой работать, начинаешь импортировать knex и настраивать его заново? Да ты что, с ума сошел? Это же чистой воды распиздяйство. Создал один файлик database.js, настроил там соединение один раз и на всю жизнь, и потом отовсюду его импортируешь. И если что-то поменяется (а оно всегда меняется), ты правишь в одном месте, а не бегаешь по всему проекту, как сука обезумевшая.

// database.js — сделал один раз и забыл
const knex = require('knex');
const dbConfig = { client: 'pg', connection: process.env.DATABASE_URL };
module.exports = knex(dbConfig);

3. Middleware в Express — это святое! Вот это, блядь, реально больное место. Видел я такие проекты, где в каждом роуте по десять строк одинаковой проверки на авторизацию торчит. Представь: у тебя 50 защищенных эндпоинтов. И в каждом if (!req.headers.authorization). А потом тебе говорят: «Добавь еще проверку роли». И что, ты в 50 мест полезешь? Да похуй, я лучше повешусь. Сделал один мидлвар authMiddleware, кинул его перед хендлерами — и вся магия. Изменил логику в одном месте — она применилась везде. Красота, ёперный театр!

// Сделал один раз — и везде работает. Умно, да?
const authMiddleware = (req, res, next) => {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  next();
};
app.get('/api/profile', authMiddleware, profileHandler);

НО! Не надо фанатеть, чувак. Иногда дублирование — это не грех, а мудрое решение.

  • Простые утилитки в разных модулях. Если в одном файле нужна функция formatDate, а в другом — точно такая же, но они друг про друга не знают и никогда не будут связаны... Ну, скопируй её, и хуй с горы. Выносить её в общую либу и тащить зависимость — это иногда оверкилл, честно.
  • Когда абстракция начинает мозг выносить. Бывает, пытаешься сделать одну супер-универсальную функцию, а она обрастает условиями, флагами и становится неподъёмной хитрой жопой. В итоге её сложнее читать, чем два простых дубликата. Вот тут лучше оставить как есть. Простота важнее.
  • В прототипах или временных костылях. Ну скинул ты быстренько PoC, там код повторяется. Да и ладно, терпения ноль ебать на этапе прототипа. Главное — потом, когда это пойдет в продакшн, не забыть причесать. А то так и живут с этим.

Короче, правило простое: думай головой, а не жопой. Если видишь одинаковую логику в двух местах — спроси себя: «А если её поменять, мне везде придется бегать?». Если да — выноси. Если нет — можешь оставить. Главное — не превращай код в ёбушки-воробушки, где всё связано так, что чихнешь — всё развалится.