Этап 20 - Production checklist для Spring Boot API
Backend code становится тяжелым для поддержки, когда важное поведение спрятано в случайных controller methods. Эта статья про health checks, graceful shutdown и Docker config. Тема выглядит технической, но настоящий вопрос практический: что произойдет, когда реальный client отправит реальный request, а в нем что-то неполное, слишком большое, запрещенное, медленное или конфликтующее с текущим состоянием?
Service готов к production, когда его можно started, stopped, monitored, diagnosed и rolled back без угадывания. Checklist превращает скрытые operational assumptions в видимые requirements.

Картинка, которую нужно держать в голове
Представь маленький online shop. User открывает frontend, нажимает кнопку, и browser вызывает backend. Backend принимает HTTP data, преобразует их в Java objects, проверяет rules, трогает database и возвращает JSON. Если у каждого шага есть понятный владелец, систему можно читать. Если все шаги смешаны в одном методе, первый production incident становится болезненным.
Для этой темы последовательность такая:
- Build image.
- run with env config.
- health check.
- metrics.
| Часть | Ответственность |
|---|---|
| Controller | Принимает HTTP data и возвращает публичный response. |
| Service | Выполняет business use case и защищает business rules. |
| Repository/adapter | Работает с persistence или external systems. |
| DTO/contract | Описывает, что внешний мир может отправить или получить. |
Конкретный Spring пример
management.endpoint.health.probes.enabled=true
management.endpoints.web.exposure.include=health,info,metrics,prometheus
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s
# Docker memory should be explicit in deployment, not guessed after an outage.
Код специально маленький, потому что главное здесь - граница ответственности. Controller не должен незаметно решать business rules, которые принадлежат service. Service не должен зависеть от servlet objects. Repository не должен знать, какое JSON field name ожидает frontend. Когда граница чистая, то же поведение можно документировать, тестировать и менять без правок во всех слоях.
Почему это важно
В demo project многие shortcuts выглядят безобидно. Вернуть все records нормально, пока в таблице пять строк. Вернуть entity нормально, пока в ней не появилось скрытое поле. Логировать без request id нормально, пока несколько users не падают одновременно. Работать с вручную созданной database нормально, пока staging не получает другую schema. Production work в основном состоит в том, чтобы убрать такие hidden assumptions до того, как они станут incidents.
Самое простое полезное правило: сделай behavior явным на границе, enforce его в правильном слое и держи public contract стабильным. Если frontend знает request format, response format и error behavior, он работает увереннее. Если tests проверяют тот же contract, refactoring становится безопаснее. Если logs и configuration отражают тот же design, operations меньше зависят от угадывания.
Частые ошибки
- Помещать весь use case в controller method.
- Позволять persistence details протекать в API contract.
- Обрабатывать happy path, но оставлять failure behavior неопределенным.
- Использовать local shortcut, который не сможет работать в staging или production.
Чеклист понимания
- Я могу нарисовать последовательность этой темы от request до response.
- Я могу объяснить, какой слой владеет решением.
- Я могу назвать production problem, которую эта тема предотвращает.
Вопросы для самопроверки
- Что произойдет, если каждый endpoint реализует это правило по-своему?
- Какая часть behavior должна быть задокументирована для API clients?
- Какой test докажет, что правило работает, а не только happy path?