Назови условие — избавься от хаоса!

чт, 5 июня 2025 г. - 2 мин чтения
Разработчик упрощает условие в коде

🧭 Избегайте сложных выражений в условиях

Иногда в проект подключают внешнего подрядчика, и вместо читаемой логики прилетает условие на пятнадцать строк: if (isUser && hasSubscription && !isExpired && (!isPromo || promo.isActive) && (plan === 'pro' || plan === 'enterprise') && region !== 'blocked' && !isBannedByMarketing).

Пока разработчик, писавший код, рядом — всё работает. Но как только нужно добавить ещё одно правило или исправить баг, команда тратит часы на разбор «каши» в условии. Решение простое: вынести проверки в говорящие функции или предикаты.


Как выглядит тяжёлое условие

if (
  user &&
  user.subscription &&
  !user.subscription.expired &&
  (!campaign || campaign.active) &&
  (user.plan === 'pro' || user.plan === 'enterprise') &&
  !blockedRegions.includes(user.region) &&
  !marketingBanList.includes(user.id)
) {
  showStories();
}

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


Дадим условию имя

const canShowStories = isPremiumSubscriber(user) && isCampaignAllowed(campaign) && isRegionWhitelisted(user.region) && isMarketingApproved(user.id);
 
if (canShowStories) {
  showStories();
}

А сами функции прячем рядом:

const isPremiumSubscriber = (user: User) => user.subscription?.isActive && ['pro', 'enterprise'].includes(user.plan);
const isCampaignAllowed = (campaign?: Campaign) => !campaign || campaign.active;
const isRegionWhitelisted = (region: string) => !blockedRegions.includes(region);
const isMarketingApproved = (userId: string) => !marketingBanList.includes(userId);

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


Где ещё помогает именование условий

  • 📆 Планы и подписки. В нашем проекте больше 30 пакетов, и каждый имеет свои особенности. Функция canAccessStoryEditor(plan) избавляет от длинного списка сравнений прямо в условии.
  • 🧪 Фича-флаги и эксперименты. Вместо if (flagA && !flagB && user.country !== 'DE') используйте предикат isStoryExperimentEnabled(user).
  • 🔁 Асинхронные проверки. Когда нужно учесть время последнего обновления, состояние очереди и флаги доступности, объедините их в shouldSyncAnalytics().
  • 🌐 Разные окружения. Логика для dev, stage, trunk и prod может отличаться. Функция isProdEnvironment() читается лучше, чем сравнение env === 'production' && cluster !== 'staging' внутри условия.

Чек-лист перед рефакторингом

  1. Поймите бизнес-правило. Сформулируйте условие словами: «Мы показываем баннер, если…».
  2. Дайте имя. Название должно объяснять намерение, а не перечислять флаги (shouldShowBanner, canTriggerReminder).
  3. Вынесите детали. Повторяющиеся куски логики превратите в функции или константы.
  4. Покройте тестами. Убедитесь, что каждая ветка условия проверена отдельно.

Итог

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