S.Tominoff

Fullstack JavaScript разработчик

Как мы избавились от магических констант для времени

Рефакторинг на 15 минут

Проблема

В каждом проекте есть код с временными интервалами. Вот типичные примеры:

const COOKIE_TTL = 2592000; // 30 дней в секундах?
const CACHE_EXPIRE = 1800000; // 30 минут в миллисекундах?
const API_TIMEOUT = 5000; // 5 секунд?

Проблемы этого кода:

  1. Неочевидные единицы измерения
    Разные API и системы ожидают время в разных форматах:
    Куки → секунды
    setTimeout → миллисекунды

    Без явного указания единиц легко ошибиться
  2. Когнитивная нагрузка
    Даже зная, что:
    3600 = 1 час в секундах
    86400 = 1 день в секундах

    Приходится мысленно преобразовывать значения
  3. Ошибки в расчётах
    Особенно при:
    Составных интервалах (30 * 24 * 3600 * 1000)
    Изменении требований (например, переход с минут на секунды)

    Один пропущенный множитель — и таймеры работают неверно

Решение - TimeInterval

В JavaScript нет встроенного класса для работы с временными интервалами, но его легко добавить в проект. Вот как это меняет подход к работе со временем:

  • Делает код самодокументируемым и интуитивно понятным
  • Автоматизирует преобразование единиц
  • Исключает ошибки в расчётах

Как это выглядит на практике:

Было

/*
  Магия чисел в деле, но тут хотя бы по расчёту можно понять
*/
const TIMEOUT = 3600 * 24 * 30;

/*
  Уже лучше, но что если требования поменяются и нужно будет использовать миллисекунды?
*/
const TIMEOUT_SEC = 3600 * 24 * 30;

/*
  А вот сколько тут?
*/
const DELAY = 300000; // Это 5 минут в миллисекундах или 5000 минут?

Стало

/*
  Сразу видно сколько времени установлено и в каких единицах его требуется отобразить
*/
const TIMEOUT = TimeInterval.fromDays(30).toSeconds();
const DELAY = TimeInterval.fromMinutes(5).toMillis();

 

Реальные кейсы из нашего проекта

1. Конфигурация сервисов

// Было

// 12 часов в миллисекундах
const ATOL_TOKEN_EXPIRES = 43200000;

// Стало
const ATOL_TOKEN_EXPIRES = TimeInterval.fromHours(12).toMillis();

2. Работа с куками

// Было:
// 180 дней в секундах
response.cookie('session', token, {
  maxAge: 15552000
});

// Стало
response.cookie('session', token, {
  maxAge: TimeInterval.fromDays(180).toSeconds()
});

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

Основные преимущества такого подхода

  1. Самодокументируемость
    fromHours(2).toMillis() читается лучше, чем 7200000. Не нужно добавлять поясняющие комментарии, сразу видно какие единицы измерения требует сервис
  2. Безопасность
    Невозможно перепутать секунды и миллисекунды
  3. Гибкость
    Изменяем единицы измерения в одном месте

 

 

Итог:

 

Да, можно запомнить, что 86400 — это сутки в секундах. Но зачем напрягать память, если код может быть понятным сразу?

Простой класс вроде TimeInterval делает временные интервалы очевидными без лишних комментариев и вычислений.

 

После внедрения мы:

  • Перестали тратить время на расшифровку чисел
  • Уменьшили количество ошибок
  • Сделали код понятнее для новых разработчиков
 

Пример реализации TimeInterval

Полную реализацию можно найти в GitHub Gist