Рубрики
Без рубрики

Учебники MVC сломаны

ПРИМЕЧАНИЕ. Модель, вид, шаблон контроллера или «MVC», на самом деле поставляется во многих ароматах, но для … Помечено Python, Perl, программирование.

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

Проблема: заставить MVC неправильно – это обычная и дорогая ошибка.

Когда я начинаю работать с новым клиентом, я часто нахожу программное обеспечение с общими наборами ошибок. Одна вопиющая ошибка – это недоразумение моделей-контроллера контроллера («MVC»). MVC- который получил несправедливый плохой рэп – Тщательно неправильно поняты и большая часть этого можно обвинить на примерах и учебниках мусора.

Вот прекрасный пример Плохой MVC с помощью Python и Flask :

@app.route('/')
def main_page():
    """Searches the database for entries, then displays them."""
    db = get_db()
    cur = db.execute('select * from entries order by id desc')
    entries = cur.fetchall()
    return render_template('index.html', entries=entries)

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

Примеры и учебные пособия MVC являются преподавательскими разработчиками, как построить неизвестное программное обеспечение. В результате, когда я работаю с новым клиентом, используя «MVC», я часто вижу это:

def some_controller_method():
    """begin hundreds of lines of code"""

Как я ненавижу тебя? Позвольте мне посчитать пути. (С извинениями к Elizabeth Barrett Browning ). Ниже приходит следующее: многолетний опыт, увидев это снова и снова.

  • База данных или ORM выставлены на уровне контроллера
  • Вы не можете повторно использовать эту логику за пределами контроллера
  • Вы не можете проверить эту логику вне веб-контекста
  • Испытания намного медленнее из-за веб-контекста
  • Тестовый охват страдает, потому что трудно проверить условную логику в контроллере
  • Логика часто дублируется в других контроллерах
  • Разное поведение стало плотно связанным, что трудно развивать
  • Производительность страдает, потому что вы не можете чисто нацелиться на слой для оптимизации
  • Интеграция новых технологий сложнее, потому что слои плотно связаны
  • … и так на

Если вышеуказанный список кажется огромным, это потому, что это страшная проблема, которая стоит компании много денег. Это одна из худших проблем в современном разработке веб-приложений. Но что это значит на практике? Давайте рассмотрим реальный пример, который я столкнулся с несколькими годами назад.

Одна компания я работала с всеми вышеуказанными проблемами. В частности, у них было 3000 строки «Метод» для их поисковой системы. Это объединяет много вещей, включая поиск продуктов и фильтрацию результатов поиска. Таким образом, даже если я был поручено работать над этим, каждый раз, когда я коснулся поиска, он сломал фильтрацию. Каждый раз, когда я коснулся фильтрации, он сломал бы поиск. Это было медленно и утомительно, чтобы получить что-нибудь сделать. Кроме того, этот метод сгенерировал HTML, который был введен на веб-страницу!

Мне потребовалось некоторое время для разделения поиска, фильтрации и перемещения генерации HTML в представлении. Когда я был сделан, у меня был неожиданный визит от одного из разработчиков мобильной связи. Похоже, они хотели правильной поисковой системы для возрастов, но никогда не добавляли ее, потому что они не могут, потому что их потребности были так отличаются от веб-контекста. После этой работы потребовалось только их пятнадцать минут для реализации поисковой системы.

Позвольте мне повторить это, потому что важно: мобильное приложение никогда не имело правильной поисковой системы, потому что веб-приложение нажало всю логику в Веб контроллер. Фиксация, которая позволила мобильной команды получить поисковую систему, запущенную через пятнадцать минут.

Не получить это правильно промывает деньги в туалет Отказ Часто мы слышим, что новая функция займет много времени для реализации », потому что приложение не было разработано для этого случая использования. «Что на самом деле значит, это« потому что мы не поняли Разделение опасений И эта простая функция займет месяц для развития ».

Примечание: Вы можете исправить этот беспорядок , но требуется время, и вы должны понимать, что должен выглядеть MVC.

Чтобы противопоставить это, давайте посмотрим на контроллер для чрезвычайно сложной бит логики из свободного MMORPG, Тау станция , используя Perl и Катализатор MVC Framework :

sub station ( $self, $c, $station ) : Local Args(1) {
    $c->character->travel_to_station($station);
}

Не собираясь в подробности о том, что travel_to_station Делает (доверять мне, это сложно), все, что мы видим, – это запрос на сложные действия, которые должны быть выполнены. В контроллере мы можем увидеть:

  • Знание маршрута к этому методу контроллера ( Local атрибут)
  • Но Нет знаний о том, как модель построена
  • И никаких знаний о том, как данные будут использоваться

Наличие информации о маршруте жестко закодирована, немного несчастной, но это легко работать. Тем не менее, этот метод контроллера просто соединяет модель к представлению, и все это. Это то, что вы ищете в MVC. MVC, когда это уместно, принимает приложение с пользовательским интерфейсом (пользовательский интерфейс) и отказывается от ответственности в разумные слои.

Теперь легко проверить логику (вы тестируете модель, а не слой контроллера и все его веб-контекст). Это легко повторно использовать этот код. И, если модель правильно построена, у вас есть отличное разделение проблем, что позволяет легко поддерживать и расширить приложение.

  • Модель – приложение.
  • Вид – какой потребитель (пользователь) видит. Часто HTML, JSON или XML.
  • Контроллер – тонкий слой, соединяющий вид и модель.

Вот и все! Там ничего не нравится, но часто требует объяснения. Контроллер, как показано выше, должно быть максимально тонким. Вид должен иметь только логику отображения, а модель … что именно?

Итак, давайте копаемся в модель. Почти каждый учебник MVC, который я вижу, путает модель данных с моделью. Подумайте о модели как «Бизнес-логика», а не данные. Это то, что мы получаем (предполагаем, что все следующие примеры – псевдокод):

@app.route('/neighbors')
def neighbors():
    location = self.character.location
    neighbors = Character.query.filter_by(location_id=location.id).all()
    return render_template('people.html', people=neighbors)

Теперь это выглядит разумно. На самом деле, кажется, настолько разумно, что я использовал, чтобы написать свой код MVC таким, потому что это то, что учено учебники. В случае тау станции вышеизложенное было глубоко недостаточно. Приведенный выше запрос тесно пары методом контроллера к базовой структуре базы данных. Если вам нужно изменить эту структуру, упс! Но это просто один метод звонка, так что факторинг его глупо, верно?

Неправильно. Как оказывается, вы не хотели показывать любым персонажам, которые не были активны в прошлом дне.

Если они не были NPC.

Или другие персонажи не видны.

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

Итак, давайте попробуем это снова:

@app.route('/neighbors')
def neighbors():
    characters = self.get_orm().model.table('Characters')
    neighbors = characters.visible_to( self.character )
    return render_template('people.html', people=neighbors)

Ах, это лучше. За исключением, что мы выставили нашу ORM (и, таким образом, нашу базу данных). У нас есть много источников данных, которые имеют данные в файлах Redis или Configuration, или пользовательский кэш, или от всех видов местоположений, о которых контроллер никогда не должен знать. Некоторые из моих клиентов с этим анти-моделей работали вокруг этого, пытаясь имплантатировать эти другие источники данных непосредственно в их ORM. Это просто поражает муфту вокруг. Контроллер никогда не должен заботиться об источнике данных. Контроллер должен просить только данные. Вместо:

@app.route('/neighbors')
def neighbors():
    characters = self.model('Characters')
    neighbors = characters.visible_to(self.character)
    return self.template('people', people=neighbors)

Откуда приходят «Видимые» персонажи? Вам все равно. Скрывая все эти детали от контроллера, разработчики могут свободно реализовать получение этих данных, как они хотят, до тех пор, пока они уважают контракт, первоначально указанный при создании этого метода.

И мы возвращаем шаблон через имя, но мы не претендуем на его HTML. Экземпляр может понять свой контекст вызова и соответственно рендеринга.

Модель ваша Бизнес логика не ваша модель данных. И я пойду на шаг дальше и скажу хороший выбор дизайна – сделать модель предоставить услуги клиенту, с помощью A Безголовый приложение под. Создавая это, вы можете сломать контроллер и представление HTML на нем. Если вы осторожны, вы можете получить контроллер нацелить несколько просмотров и построить собственное мобильное приложение поверх него, требуя только нового представления. Вы можете создать собственный клиент/серверное приложение для рабочего стола. Если контроллеры слишком негибны, это нормально. Они крошечные и легко пропустить. Напишите тонкие контроллеры, специально для ваших приложений для мобильных и настольных компьютеров, безопасны в знаниях, что логика приложения все в вашем приложении без головы.

Контроллеры MVC должны быть как контроллеры воздушного движения: они не летают самолет, они просто говорят им, когда взлет и земля. Когда вы пишете контроллеры без логики, которые могут подключить только вид на модели, вы пишете лучшее программное обеспечение.

Оригинал: “https://dev.to/ovid/mvc-tutorials-are-broken-17lp”