Вся правда про MVC (Model View Controller)

MVC залишається одним з найбільш популярних архітектурних патернів, що використовується у більшості фреймворків. Нажаль, безліч публікацій, що присвячені MVC, лише вводять людей в оману, та не пояснюють багатьох важливих моментів для розуміння архітектури загалом, та MVC як одного з архітектурних патернів. У цій публікації я спробую виправити це і надати найбільш повне розуміння MVC та поділитися думками про фреймворки та організацію коду загалом.

Дуже складно пояснити MVC лінійно і послідовно, тому я буду викладати інформацію дещо тезисно, а уважний читач вже самостійно складе усі пазли разом.

Невірне розуміння Model

В інтернеті існує безліч різноманітних діаграм, що покликані пояснити MVC. Усі вони досить сильно відрізняються одна від одної і це явна ознака того, що у спільноті немає чіткого розуміння MVC.

Найбільш знайомим особисто для мене, як розробника в т.ч. на Ruby on Rails, прикладом помилкового розуміння MVC є те, що у Ruby on Rails моделями називають класи, що знаходяться у директорії app/models (зверніть увагу на множину!) та переважно спадкують від абстрактного класу ApplicationRecord (ActiveRecord::Base).

Насправді, модель – це не клас. Це шар/рівень, що має обмежений контекст (bounded context) та у більшості випадків, якщо говорити про т.з. “ООП мови”, складається із декількох класів. Тобто, моделлю у Ruby on Rails додатку, насправді, є усе, що знаходиться у app/models.

Невірне розуміння Controller

Якщо говорити про Ruby on Rails та подібні веб-фреймворки, то Controller у них розмазаний між класами, що називаються *Controller та маршрутизатором. Тобто MVC контроллер – це сукупньсть усіх контролерів додатку на Ruby on Rails та машрутів.

Варто згадати, що MVC патерн був створений першопочатково для GUI додатків, а вже потім мігрував до web-додатків, які, принаймні до недавнього часу, також були переважно GUI додатками. Model – це те, чим оперують спеціалісти у предметній області, View – це те, з чим працюють користувачі додатку (включно зі спеціалістами у предметній області), а Controller – це такий Anti Corruption Layer для моделі, який транслює модель у GUI та взаємодію користувача з GUI у запити до моделі.

“Товсті моделі та тонкі контроллери”

Попрацювавши з Ruby on Rails, Laravel та іншими веб-фреймворками, багато хто почав пропагандувати підхід, що отримав назву “Товсті моделі та тонкі контроллери” (зверніть увагу на множину!), який полягав у тому, що уся т.з. “бізнес логіка” має знаходитися у “моделях”, а контроллери мають бути її позбавлені. Іншими словами, код моделі має знаходитися у моделі. Вау!

Спільнота Ruby on Rails та інших веб-фреймворків розвивалася у певній ізоляції від Domain Driven Development (DDD) та інших подібних рухів/методологій. З цієї причини, розуміння що таке модель (domain model) було відсутне, як і розуміння такої основної ідеї для DDD, як обмежений контекст (bounded context).

В Ruby on Rails та в інших подібних фреймворках “модель” User буде містити усе лайно, що хоч якось стосується користувача. Проте, згідно  DDD (яке недалеко відійшло від простого здорового глузду), велика предметна область не може бути однорідною мішаниною, а представляє собою кластери, кожен із яких являє собою окримий обмежений контекст та містить не “модель”, а сутність (реалізацію патерну Entity), що називається User. Перекладаючи на мову, зрозумілу розробникам на Ruby on Rails: у додатку має бути декілька “моделей” User, кожна з яких призначена для свого власного обмеженого контексту.

Так майже ніхто не робив і тому з’явилася нова проблема – занадно товсті “моделі”, вирішенням якої вважалося використання паттерну Service (ServiceObject), який згодом багато хто визнав антипатерном і який певним чином пропагандував використання патерну “Anemic Model”, що є анти-патерном у т.з. “ООП мовах”.

Якщо Вам здається це дуже дивним та навіть тупим, то так воно і є. Люди граються зі словами, роблять якісь логічні побудови, але упускають найголовніше – значення слів, які є фундаментом будь-яких логічних побудов. Що може вийти у результаті такої діяльності, окрім нісенітниці?

MVC та фреймворки

Патерн MVC був створений ще наприкінці семидесятих, але найбільшої популярності досяг з появою великої кількості веб-фреймворків на початку нульових. Фреймворки відрізняються від бібліотек тим, що бібліотеки ми використовуємо у власному коді, а фреймворки, навпаки, використовують наш код. По-суті, використовуючи фреймворки, ми пишемо ін’єкції коду для них. Ми не можемо робити які завгодно ін’єкції, бо тоді зникає сенс у використанні того чи іншого фреймворку. Фреймворк очікує досить конкретних ін’єкцій і патерн MVC використовується у фреймворках саме для типізації та уніфікації ін’єкцій коду.

MVC – це не найкращий варіант того, як ми маємо організовувати наш код, але компроміс, якого вимагає той чи інший MVC-фреймворк. Окрім MVC є й інші патерни, які пропагандуються іншими фреймворками.  MVC, MV* та інші подібні патерни орагнізації мають мало сенсу поза тим чи іншим фреймворком, що вимагає відповідних ін’єкцій коду.

Альтернатива

Просто слідування принципам SOLID та/або low-coupling/high-cohesion дозволяє розробляти значно більш гнучкі та якісні додатки без використання фреймворків.

Варто зазначити, що фреймворки значно знижують вхідний поріг та дозволяють значно швидше виконувати розробку на ранніх її етапах, але у довгостроковій перспективі фреймворки швидше заважають своїми обмеженнями та необхідністю постійно оновлюватися, особливо при виході т.з. мажорних версій.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *