Как мы избавились от магических констант для времени
Рефакторинг на 15 минут
Проблема
В каждом проекте есть код с временными интервалами. Вот типичные примеры:
const COOKIE_TTL = 2592000; // 30 дней в секундах?
const CACHE_EXPIRE = 1800000; // 30 минут в миллисекундах?
const API_TIMEOUT = 5000; // 5 секунд?
Проблемы этого кода:
- Неочевидные единицы измерения
Разные API и системы ожидают время в разных форматах:
Куки → секунды
setTimeout → миллисекунды
Без явного указания единиц легко ошибиться - Когнитивная нагрузка
Даже зная, что:
3600 = 1 час в секундах
86400 = 1 день в секундах
Приходится мысленно преобразовывать значения - Ошибки в расчётах
Особенно при:
Составных интервалах (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()
});
На самом деле мы избавились вообще от использования константных значений повсюду в коде и теперь всегда используем этот класс, когда речь идёт о времени.
Основные преимущества такого подхода
- Самодокументируемость
fromHours(2).toMillis() читается лучше, чем 7200000. Не нужно добавлять поясняющие комментарии, сразу видно какие единицы измерения требует сервис - Безопасность
Невозможно перепутать секунды и миллисекунды - Гибкость
Изменяем единицы измерения в одном месте
Итог:
Да, можно запомнить, что 86400 — это сутки в секундах. Но зачем напрягать память, если код может быть понятным сразу?
Простой класс вроде TimeInterval делает временные интервалы очевидными без лишних комментариев и вычислений.
После внедрения мы:
- Перестали тратить время на расшифровку чисел
- Уменьшили количество ошибок
- Сделали код понятнее для новых разработчиков
Пример реализации TimeInterval
Полную реализацию можно найти в GitHub Gist