Логика в контроллерах это плохо?

Август, 2022

мысликсер, имхо

«Логика в контроллерах это плохо... понятненько». Мистер Маки

На данную тему есть блок в «bad-практиках» и для большинства ситуаций это действительно так, как минимум, потому что мы не сможем переиспользовать логику, которую написали в контроллере (хотя некоторые додумываются вызывать контроллеры из контроллера, как следствие полного непонимания роли контроллера в приложении).

Например, если мы пишем простейший CRUD контроллер, задача которого прочитать и записать данные, то, в случае с Laravel, вынос логики из контроллера может не принести пользы.

Я ни в коем случае не призываю писать логику в контроллерах, а говорю о том, что лаконичный синтаксис фреймворка позволяет это делать не захламляя контроллер и не нарушая DRY. Например:

1public function index()
2{
3 $posts = Post::query()
4 ->active()
5 ->orderByDesc('created_at')
6 ->paginate(config('post.per_page'));
7 
8 return response()->json(PostResource::collection($posts));
9}
10 
11public function store(PostCreateRequest $request)
12{
13 $post = Post::create($request->validated());
14 
15 return response()->json(new PostResource($post));
16}
highlight by torchlight.dev

Если говорить о перспективе, то конечно, код может обрасти логикой или понадобится где-то ещё. Вопрос когда это произойдёт и произойдёт ли вообще? А когда произойдёт, то мы легко перенесём этот код в сервис.

Да, кейс, когда создаётся пост без загрузки изображений и дополнительной логики достаточно редкий, но он встречается, ибо не все приложения должны иметь "сложную" логику, не надо заниматься самообманом, не все проекты это высоконагруженные соц. сети и платформы с огромной кодовой базой и не все станут такими в будущем. Если ты планируешь, что приложение будет расти и есть понимание "как", то конечно, лучше сразу вынести в "сервисы", но если приложение будет простым CRUD-ом и код похож на пример выше, то копипаст логики в "сервис" проблему не решает, а ставит новые задачи, например, передача данных в сервис (DTO) и их валидация, обработка ответа и ошибок от сервиса.

На практике, к сожалению, я часто встречаю перенос логики из контроллера в другой класс, который находится в директории app/Services/, состоит из статических методов, данные пробрасываются массивом или ещё хуже, как Request, а обработка ошибок отсутствует полностью. В итоге такой сервис всё равно затруднительно использовать где-то ещё, а попытка кастомизации приводит к многочисленным ошибкам в разных местах приложения. И появляется вопрос что хуже: такой "сервис" или логика в контроллерах?

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

Данный вопрос не является простым и ответ не может быть однозначным, т.к. относится к архитектуре приложения, а на архитектуру влияет множество факторов, учесть которые без опыта и конкретного ТЗ, к сожалению, невозможно. В разделе «ссылки» можешь найти немного литературы, которая, возможно, продвинет тебя в понимании. Удачи.