Как лучше хранить числовые значения вместо хардкода
Что проверяют
Умеете ли вы решать, где должно жить число, исходя из того, кто и как часто его меняет. Следом обычно спрашивают, как поменять таймаут на проде без пересборки и как не пустить в конфиг невалидное значение.
Как отвечать
Разложите по уровням:
- именованная константа:
private static final int MAX_RETRIES = 3для значений, которые часть логики и не зависят от окружения. Константа даёт «магическому числу» имя, но поменять её можно только релизом; - enum: когда значения образуют закрытый набор, например тарифы с лимитами. Число привязано к смыслу, а не лежит отдельно;
- конфигурация приложения:
application.ymlв Spring Boot с переопределением через профили и переменные окружения (APP_CLIENT_TIMEOUTпопадёт вapp.client.timeoutблагодаря relaxed binding). Читать лучше не россыпью@Value, а типизированным классом с@ConfigurationProperties, в Spring Boot 3 это может быть record; - валидация при старте:
@Validatedи@Min,@Max,@NotNullна полях при подключённомspring-boot-starter-validation. Кривое значение уронит запуск, а не проявится ночью; - единицы измерения: поля типа
DurationиDataSizeпринимают30sили10MB, и не надо гадать, секунды там или миллисекунды; - изменение на лету: если значение правит бизнес без деплоя, нужна таблица настроек с кешем или конфиг-сервер (Spring Cloud Config, Consul) вместе с
@RefreshScope. Цена: аудит изменений и риск, что кто-то поставит ноль.
Пароли и токены в эту схему не входят: их место в хранилище секретов (Vault, секреты Kubernetes), а не в YAML в репозитории.
Где спотыкаются
Выносят в конфиг всё подряд. Параметр, который никто никогда не меняет, в YAML становится ещё одним местом для ошибки, причём без тестов.
Заводят общий класс Constants или, хуже, интерфейс с константами на весь проект. Число лучше держать рядом с кодом, который его использует.
Не знают, что static final примитивы и строки с литеральным значением компилятор подставляет прямо в байткод классов, которые их используют. Поменяли константу в библиотеке, а зависимый модуль без перекомпиляции продолжит работать со старым числом.