Функции: именование и лучшие практики

Хорошо названная функция — самодокументирующийся код: имя должно точно описывать действие, аргументы — данные, return — результат; функция должна делать одно дело и делать его хорошо.

Зачем нужно

Большая часть времени разработчика уходит на чтение кода. Правильно названные функции с чёткими обязанностями делают код понятным без комментариев, упрощают рефакторинг и тестирование. «Как назвать» — один из самых частых вопросов при код-ревью.

Где используется

  • Любой JavaScript-код — фронтенд, бэкенд, тесты
  • Code review — стандарты именования в команде
  • Рефакторинг и поддержка легаси-кода

Соглашения об именовании

// Глагол + существительное — что делает функция
function getUser(id) {}
function fetchProducts() {}
function validateEmail(email) {}
function renderCard(data) {}
function handleSubmit(event) {}
function calculateTotal(items) {}

// Булевы функции — is/has/can/should
function isValid(value) {}
function hasPermission(user, action) {}
function canEdit(user, resource) {}
function shouldRetry(error) {}

// Обработчики событий — on + событие или handle + действие
function onClick() {}
function onUserLogout() {}
function handleSearch(query) {}

// Трансформации — глагол + что
function formatDate(date) {}
function parseJSON(str) {}
function normalizeUser(raw) {}
function mapToViewModel(entity) {}

// Фабрики — create/make/build
function createButton(label) {}
function makeRequest(config) {}
function buildQueryString(params) {}

Принцип единственной ответственности

// Плохо: функция делает слишком много
function processUserData(data) {
  // Валидация
  if (!data.name) throw new Error('Нет имени');
  // Преобразование
  data.name = data.name.trim().toLowerCase();
  // Сохранение
  db.save(data);
  // Отправка письма
  emailService.send(data.email, 'Добро пожаловать!');
  // Логирование
  logger.info('User created:', data.id);
}

// Хорошо: разделение на маленькие функции
function validateUser(data) {
  if (!data.name?.trim()) throw new ValidationError('Имя обязательно');
  if (!isValidEmail(data.email)) throw new ValidationError('Неверный email');
  return data;
}

function normalizeUser(data) {
  return { ...data, name: data.name.trim().toLowerCase() };
}

async function createUser(rawData) {
  const validated = validateUser(rawData);
  const normalized = normalizeUser(validated);
  const user = await db.users.create(normalized);
  await emailService.sendWelcome(user.email);
  logger.info('User created:', user.id);
  return user;
}

Параметры: не более 3, используй объект

// Плохо: много позиционных параметров
function createRequest(url, method, body, headers, timeout, retries) {}

// Хорошо: объект конфигурации
function createRequest({ url, method = 'GET', body = null, headers = {}, timeout = 5000, retries = 3 }) {}

// Использование
createRequest({ url: '/api/users', method: 'POST', body: { name: 'Иван' } });

Чистые функции (Pure Functions)

// Нечистая: зависит от внешнего состояния, имеет побочные эффекты
let total = 0;
function addToTotal(n) {
  total += n; // мутирует внешнее состояние
  return total;
}

// Чистая: только аргументы → результат, без побочных эффектов
function add(a, b) { return a + b; }

// Чистая: иммутабельное обновление
function addItem(items, newItem) {
  return [...items, newItem]; // не мутирует оригинал
}

Размер функции: правило одного экрана

// Функция должна умещаться на одном экране (~20-40 строк)
// Если длиннее — скорее всего нужно разбить

// Плохо: 100-строчная функция со вложенными условиями
function hugeFunction(data) {
  // ... 100 строк ...
}

// Хорошо: основная функция как оркестратор
async function processOrder(orderId) {
  const order    = await fetchOrder(orderId);
  const valid    = validateOrder(order);
  const enriched = await enrichWithUserData(valid);
  const result   = await submitOrder(enriched);
  await notifyUser(result);
  return result;
}

Частые ошибки

1. Аббревиатуры и однобуквенные имена

// Плохо
function calc(u, p, d) {}
function fn(x) {}

// Хорошо
function calculateTotal(user, products, discount) {}
function transform(inputValue) {}

// Исключение: математические формулы, итераторы
for (let i = 0; i < arr.length; i++) {}
const distance = Math.sqrt(x**2 + y**2); // x, y — общепринятые

2. Ложные имена

// getUser — должна только возвращать, не менять
function getUser(id) {
  const user = db.find(id);
  user.lastAccessed = new Date(); // неожиданный побочный эффект!
  return user;
}

// Правильно: разделить или переименовать
function findUser(id) { return db.find(id); }
function touchUser(id) { db.update(id, { lastAccessed: new Date }); }

Связанные темы

Ресурсы