Model-View-Controller (MVC) — это шаблон проектирования для структурирования программных систем. Шаблон MVC отделяет логику приложения от пользовательского интерфейса. MVC означает Model, View и Controller, три основных компонента архитектуры веб-приложений MVC. Каждый из этих компонентов должен работать как отдельные блоки. Дискретная природа компонентов MVC имеет решающее значение для обслуживания и тестирования приложений.
Мы часто слышим, что лучший способ написать ясный и лаконичный код в Rails — это следовать подходу «Толстые модели и тощие контроллеры», который относится к тому, как модель и контроллер в архитектуре MVC должны идеально работать вместе. Наличие «тощего» контроллера (что является обычной практикой) означает, что вся некритическая логика перемещается в модель; это упрощает тестирование и обслуживание. Тем не менее, мы рекомендуем сделать «тощий» подход еще на шаг вперед: сядьте на диету и ваших моделей, и ваших контроллеров. Часто мы фокусируемся на моделях и контроллерах, но как насчет View? Представление также может быть «толстым», и на самом деле мы считаем, что представление также должно придерживаться диеты.
Какова функция каждого компонента MVC?
Чтобы получить четкое представление о том, почему мы должны поддерживать все компоненты MVC тонкими, сначала нам необходимо выяснить, за что отвечает каждый из этих компонентов.
модели
Модель — это слой между базой данных и приложением, в котором хранится бизнес-логика, связанная с конкретной сущностью. Каждая модель отвечает за отдельный объект и за его связь с другими объектами. Модели обычно вызываются контроллерами.
Например, предположим, что пользователь хочет зарегистрироваться. Для этого они должны ввести свой адрес электронной почты, имя пользователя и пароль. Все эти атрибуты принимаются контроллером, который пытается создать нового пользователя (в архитектуре MVC этот пользователь концептуализируется как «запись модели»). Модель выполняет проверки: она проверяет, имеет ли введенный адрес электронной почты правильный формат, достаточно ли надежен пароль и уникальны ли адрес электронной почты и логин. Если проверка прошла успешно, Модель затем сохраняет данные в базе данных и after_save
обратный вызов after_save
. Примером обратного вызова является уведомление по электронной почте, которое отправляется зарегистрированному пользователю и администратору. Если проверка не пройдена, Модель возвращает объект ошибки, который можно отобразить и показать пользователю.
Контроллеры
Контроллеры несут ответственность за чтение входных данных (запросов), выбор соответствующих действий (бизнес-действий) и возврат итоговых выходных данных (ответов).
Например, контроллер получает данные от клиента, а маршрутизатор выбирает соответствующее действие в существующем контроллере. На основании полученных параметров Контроллер выполняет следующие действия:
- Аутентификация, когда Контроллер проверяет, работает ли вошедший в систему пользователь с приложением в данный момент.
- Авторизация, когда Контроллер проверяет, авторизован ли пользователь для выполнения действия
- Фильтрация входных параметров (
permitted_attributes
), когда контроллер действия предоставляет интерфейс для защиты атрибутов от назначения конечным пользователем. - Вызывает методы в моделях или сервисах.
- Определяет, какой формат предоставлять информацию клиенту (JSON, HTML, PDF, XML) и выбирает правильный вид.
Взгляды
Представление — это визуализация присоединенного состояния модели. Проще говоря, представление — это то, что видит пользователь. Это единственный компонент MVC, с которым пользователи взаимодействуют напрямую.
Например, Контроллер выбирает шаблон для представления сообщений пользователя и вставляет его в правильный макет. Представление отображает информацию о пользователе и содержит некоторые элементы HTML, такие как ссылки на сообщения и форму для создания новых сообщений.
Что произойдет, если компонент MVC кто-то еще работает?
- Сложно поддерживать код в тех случаях, когда контроллер содержит большие методы, выполняющие несвязанные действия.
- Тестирование становится практически невозможным, поскольку написание модульных тестов означает тестирование конкретных классов и модулей, отвечающих за определенные функции. Трудно отследить цепочку вызовов методов в «коде спагетти» (запутанный код, который включает в себя множество неструктурированных и сложных объектов и методов).
- Каждый класс должен нести ответственность за одну часть всей функциональности, предоставляемой программным обеспечением. Но часто Контроллеры начинают включать бизнес-логику, которая не принадлежит, или даже формы логики View. В конечном итоге модель может содержать логику, не связанную с постоянством, а представления могут содержать вычисления, которые вообще не приветствуются.
Основное правило, которого мы должны придерживаться, чтобы избежать жирных компонентов MVC, сводится к следующему: «Каждый должен заниматься своим делом».
Как сделать компоненты MVC тонкими?
Чтобы получить тощие модели, представления и контроллеры, мы должны постоянно проводить рефакторинг. Рефакторинг — это процесс реструктуризации существующего кода. Хотя рефакторинг ничего не меняет с точки зрения конечного пользователя, он помогает поддерживать чистоту, удобство сопровождения и простоту тестирования, что полезно для разработчиков.
Рефакторинг следует простому принципу, что если вы делаете беспорядок, вы должны убирать за собой. Рефакторинг — это постоянная очистка, которая происходит после всех изменений кода. Вы не можете построить небоскреб или нарисовать шедевр без большого беспорядка в процессе, и то же самое с написанием качественного кода. Вот почему мы должны проводить рефакторинг каждый раз, когда внедряем новую функцию.
Мы можем использовать различные шаблоны проектирования, чтобы помочь нам в процессе рефакторинга, в том числе:
- Сервисные объекты (и объекты Interactor)
- Объекты значения
- Объекты формы
- Объекты запроса
- Просмотр объектов (сериализатор / ведущий)
- Объекты политики
- Декораторы
Чтобы лучше понять, как работает рефакторинг и когда это необходимо, мы расскажем о некоторых практиках, которые мы часто используем в RubyGarage, в следующем посте.