Отчёт по пользователям считается в контроллере — и это не ревью-придирка

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

Первый: где должна жить логика отчёта. В присланном коде весь расчёт — агрегация по сессиям, подсчёт среднего времени, сортировка топа — лежит прямо в @RestController, в теле метода на сорок строк. Контроллер должен принять запрос, передать его в сервис и вернуть результат. Когда бизнес-логика расчёта переезжает в контроллер, её нельзя переиспользовать из джобы, нельзя протестировать без поднятия MVC-контекста, и со временем контроллер обрастает ещё десятком похожих отчётов.

Второй вопрос жёстче: эндпоинт объявлен как @GetMapping, но внутри метода вызывается userRepository.save() для обновления поля lastReportGeneratedAt. GET не должен иметь побочных эффектов — это ломает кэширование, предзагрузку браузером, идемпотентность для ретраев клиента.

@GetMapping("/users/report") public ReportDto getReport() { List users = userRepository.findAll(); users.forEach(u -> u.setLastReportGeneratedAt(Instant.now())); userRepository.saveAll(users); // побочный эффект в GET return buildReport(users); }

Третий вопрос — самый неприятный на ревью: findAll() без пагинации. Сейчас база на тысячу пользователей, отчёт строится за 40 мс. Через год пользователей сто тысяч — и каждый вызов этого отчёта тянет всю таблицу в память, сортирует её в хипе приложения вместо того, чтобы отдать сортировку и агрегацию базе.

Что спросят следом на собесе: как бы вы переписали это с пагинацией и агрегацией на уровне SQL? Ожидаемый ответ — агрегатные функции и GROUP BY в запросе вместо loading всей таблицы, плюс Pageable для самого отчёта, если он всё равно возвращает список. И отдельно спросят: а почему GET с побочным эффектом — это не просто стиль, а нарушение контракта HTTP-метода, который кэши и прокси воспринимают всерьёз.

Логика отчёта в контроллере, побочный эффект в GET и findAll без пагинации — три разных проблемы, но их чаще всего находят в одном и том же PR.

Тренажёр: 900+ вопросов и задач, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки