Деловая неделя

Принцип разделения данных и их визуального представления сильнее конкретных «шаблонов проектирования». Принцип отделения вычислений от «картинки» менее очевиден, но всё равно его применить легче, чем «шаблон»...

ЕЖЕНЕДЕЛЬНАЯ РЕКЛАМНАЯ ГАЗЕТА ДЛЯ ПРЕДПРИЯТИЙ «Деловая неделя» (Иркутск)

Распознавание design pattern «модель – контроллер – представление» в В

Немного о переводе

Часто можно встретить (даже в Википедии) сочетания слов типа «паттерн mvc». Такие вещи следует искоренять безжалостно. Потому что они запросто могут перерасти, например, в «образец дизайна mvc» (или «шаблон дизайна mvc») – никакого отношения к дизайну не имеющие. Не надо тупо транслитерировать термины без должной необходимости. В данном случае, к счастью, необходимости нет: design вполне устойчиво переводится как «моделирование» (или «конструирование»), а pattern как «шаблон» (или «образец», или «стиль»...). Существует вполне приличный перевод и для термина design pattern: шаблон проектирования.

История и теория «модели»

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

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

Контроллер или логика

Гораздо разумнее триаду mvc перевести как «данные – логика – представление» (слово «контроллер» тоже здесь довольно сомнительно). Или «данные – вычисления – представление». А своя модель, схема может быть у каждой из этих частей. Например, может быть «модель представления». Впрочем, так же, как у всего может быть и своя «логика». В простом случае файл с данными (data.htm) может быть таким:

А файл, управляющий «представлением» (view.css), таким:

И никакого «контроллера». Правда, контроллер (переключатель) немедленно появится, как только мы добавим на страницу хотя бы одну ссылку. И это – тоже повод для путаницы. Часто работу «контроллера» связывают именно с маршрутизацией: «роутер» анализирует УРЛ и передаёт результат анализа «контроллеру», а «контроллер» на основании данных «роутера» выбирает скрипт, который будет отображать данные.

А вот термин «логика» позволяет обрисовать ситуацию более точно: файл data.htm является одновременно и данными, и их представлением (для их связки в этом случае не нужен «преключатель»); логика же превращения данных в представление содержится в файле view.css.

Так из чего всё-таки состоит mvc?

Достаточно бесспорным выглядит разделение работы c веб-сайтом на две части – работа с данными в хранилище и представление данных пользователю. «Данные и представление». Data && View. Собственно, сам язык HTML уже был придуман именно для этого. Для этого (разделение оформления и содержания) и для навигации с помощью гиперссылок. (Видимо, отсюда растут ноги у современных идей постановки роутера во главе «логики»). Но сама эта возможность (кликать по ссылкам) per se не является частью шаблона проектирования «Данные – Представление». Благодаря ей лишь реализуется часть предметной логики.

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

Контроллер или логика – это цепочка правил, по которым данные из хранилища попадают на экран пользователя. Например, такое правило: при щелчке по ссылке <a href='price.htm'> откроется файл price.htm. А если данные хранятся не в файлах, а в базе данных, тогда щелчок по ссылке должен будет не открывать файл, а запускать процедуру извлечения данных из БД и вывода их на экран. И вот тут цепочка правил Контроллера может вырасти до очень больших размеров.

Логика

Было бы полбеды, если б шаблон mvc существовал один. Но шаблонов проектирования много, и можно легко запутаться в тонкостях отличий всех этих mmvc и pm. Чтобы не запутаться, нужно придерживаться каких-то простых принципов. О самом очевидном мы уже сказали: есть данные и есть (в веб-программировании) визуальное представление данных. (Есть много других областей, где данные отделены от своего визуального прдеставления. И ещё больше – где данные преобразуются в ещё какой-то другой вид. Все компьютеры только этим и занимаются, что переводят данные из одного вида в другой).

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

Шаблоны проектирования ведь не в XX веке придуманы, а ещё в античности. Правда, тогда не было никаких серьёзных прикладных наук, кроме риторики. Вот, на базе риторики и были выявлены некоторые «шаблоны», называемые фигурами речи. Фигуры речи присутствуют в любой речи (устной, письменной, романах, статьях, интервью...) всегда. Но разглядеть их могут только очень узкие специалисты. Создатели речи (журналисты, писатели, телеведущие, попутчики в поезде) постоянно пользуются фигурами речи, чаще всего об этом не подозревая. И речь не становится лучше (интереснее, эффективнее) от простого наличия или отсутствия фигур.

Так же и программирование: узкий специалист по design patterns может выявить кучу «фигур программирования» в конкретной программе, но эффективность программы не связана напрямую с их наличием (или количеством).

Используя второй принцип, попытаемся почувствовать, что не так в простой структуре сайта: три HTML-файла с меню из трёх ссылок в каждом. Один из приёмов такого прочувствования – довести функцию до крайности. Если будет один файл HTML, в нём будет меню из 1 ссылки на эту же страницу. Стрёмно, но не фатально. А если 20 файлов? У нас будет 20 кусков одинакового HTML-кода в 20-ти файлах. Невооружённым глазом видно, что это плохо. Например, если добавится одна страница, нужно будет менять код в 20-ти (или больше) местах.

Простейшее решение в этом случае – выделить общий код в отдельный файл и вставлять его на все страницы с помощью серверного include:

Теперь уже мы не сможем сказать, что данные из хранилища попадают на экран напрямую. У нас появилось правило логики соответствий (mapping): к каждой странице присоединять код из файла menu.htm. Какой шаблон (проектирования?) мы применили в данном случае?

Слово «проектирование» не случайно со знаком вопроса. Тут ведь важно, под каким углом смотреть. В каком, так сказать, разрезе. Можно сказать, что мы применили здесь принцип «экономии усилий» (теперь править код будет намного легче – не в 20 местах, а в одном). При взгляде с формальной стороны можно сказать, что мы воспользовались наличием у объектов свойства дистрибутивности – применили, так сказать, шаблон «выноса за скобки»: ax + ay + az = a(x + y + z).

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

Вернёмся к первой крайности – 1 страница с одной ссылкой на себя. «Стрёмно», строго говоря, тоже означает «что-то не так». На этот раз не в самом процессе программирования, а в предметной логике: ссылка всегда должна куда-то вести; ссылка, ведущая на уже открытую страницу, ведёт в никуда, обманывает пользователя. Эту проблему с помощью чисто серверного include не решить, нужна обработка скриптом, проверяющим условие (соответствие href ссылки адресу открытой страницы).

Предположим, мы написали этот скрипт (реализующий, кстати, шаблон «полезности ссылок» – или шаблон «уничтожения бесполезных ссылок»). Н-да. Уж сразу и со скриптом формирования меню, что-нибудь вроде:

Можно вставить этот код в файл menu.php и соответственно изменить код серверной вставки:

Контрольный вопрос систематизатора: к какой части программы относится приведённый код? Он по какой-то непонятной логике перелопачивает данные и меняет их представление. Но его логика не является логикой соответствий, предопределённой самой структурой данных (или структурой представления). Она – внешняя. Этот же ответ можно получить и с другой стороны, задав вопрос: для чего мы генерируем меню? Ответ: для удобной работы пользователя. Значит это – предметная логика.

Разделение властей

Определённым именем называют что-то для того, чтобы отличать это от всего остального, чтобы различать и разделять. По имени шаблона проектирования «Данные – Вычисления – Представление» примерно понятно, что от чего следует отделять. Правда, сущности этого шаблона неоднородны. Данные хранятся длительное время на сервере в устойчивом виде. Представление тоже может висеть на экране в одном виде долгое время, и можно сохранить его навсегда (в виде файла HTML на компьютере клиента). Вычисления же – быстротекущий процесс. Конечно, алгоритмы вычислений тоже должны где-то храниться постоянно (например, в программном коде). Но их неустойчивая, преходящая суть от этого не меняется.

Зачем вообще в процессе работы веб-сайта что-то там от чего-то [искусственно?] отделять? Разумеется, не из чистого любопытства. А потому что жизнь заставляет. При работе веб-сайта сталкивается как минимум три разных интереса (часто совершенно противоположных): пользователя (который может быть и автором сайта, но всё равно будет мыслить как пользователь), программиста и хозяина сервера (хостера). Все трое могут работать в одной конторе. Они могут быть даже одним и тем же человеком. Но функциональность возникает неизбежно.

Пользователь хочет как можно быстрее получать страницы. В этом он солидарен с хостером (который хочет их как можно быстрее отдать). Программист хочет, чтобы изменение структуры сайта производилось одной кнопкой (и ему, строго говоря, похиг, с какой скоростью будут отдаваться страницы). Пользователь (особенно автор) тоже заинтересован в лёгкой перестройке сайта. Хостеру это совершенно без разницы, его интересует только максимальная скорость при минимальных затратах (место на диске, процессорное время...).

Продолжаем «делить меню по mvc»

В нашем примере генерации меню (menu.php) всё пока перемешано (например, вычисления и визуализация). Но мы не увидим, что с чем, пока не возникнет причина. Самая главная причина в этом случае – желание автора-пользователя изменить стуктуру сайта. Например, добавить страницу отправки заказа. Страница должна генерироваться серверным скриптом (хотя бы для того, чтобы не «терять» заполненные поля формы при ошибках). В самом простом случае (без ЧПУ) она будет называться add_order.php.

Вот и проблема: в цикле генерации меню мы вылавливаем файлы по расширению .htm. Добавить в алгоритм вылавливания расширение .php нельзя (в меню будут попадать служебные файлы). Надо добавить к меню только один файл .php (или избранную группу). Так возникает потребность отделить вычисления от представления. Самое очевидное – не одевать сразу получаемые значения заголовков и УРЛ страниц в HTML-тэги, а сохранять в виде массива, к которому потом можно будет добавить произвольные значения:

После этого можно будет делать с массивом ещё какие-то манипуляции (вычисления), а для отображения массив нужно будет пройти ещё раз в цикле и превратить в строку HTML. Заметим, что это уже противоречит интересам хостера – занимает больше процессорного времени (два раза проходить цикл, вместо одного, как в первом примере). Хостеру нужна за это какая-то компенсация. И мы её дадим.

Меню меняется редко (только вместе со структурой сайта). Почему нельзя его просто хранить в файле HTML, как другие страницы, (а не генерировать при открытии каждой страницы скриптом)? – Из-за одной паршивой овцы – ссылки «на себя». Это непреодолимо (потому что является требованием предметной логики, то есть требованием автора-пользователя). Но можно ведь для каждой страницы сохранить своё, отдельное меню. Тогда вставки include должны будут на разных страницах выглядеть как:

(Расширение у файлов меню должно отличаться от .htm, чтобы скрипт php не пытался включить в текст меню файлы самих меню; файлы меню лучше помещать в отдельную папку, чтобы не порождать путаницу в корневом каталоге сайта).

На первый взгляд, мы вернулись к тем же проблемам: 20 файлов меню, вместо одного. Но проблемы управления там уже не будет: все файлы генерирует один скрипт, без участия человека. Останется только проблема места на диске. Но тут уже программист должен советоваться с хостером: что лучше – сэкономить 1 Мб места или исключить вычисления меню при открытии страниц? К тому же «проблема 20 больших файлов меню» несколько надуманна – на самом деле, конечно, таких меню не бывает, меню для каждой страницы (или класса страниц) отличаются друг от друга гораздо более существенно, чем на одну ссылку.

То есть всё равно у каждой страницы должно быть своё меню. И если мы будем хранить его в готовом HTML-файле (а не вычислять каждый раз), это уже будет кэширование – очень приятное слово для слуха любого хостера. Да. Зато количество работы программиста возрастёт геометрически (спасибо, что не по экспоненте). Мы уже не сможем обойтись без функций. И без некоторых хитростей, ловкости рук. Создание самого массива меню станет проще (в этом месте нам не надо будет анализировать совпадение УРЛ страницы с адресом ссылки). После создания массива к нему можно будет добавить произвольные страницы:

...или произвольные классы страниц (по расширению):

Затем, пройдя массив в цикле, выгрузить для каждой страницы своё меню:

Ну, и нужна будет функция, «рисующая» собственно HTML-код меню:

Всё вместе – в файле menu3.php.

D.M., admin

Читать все комментарии (0)

Добавить комментарий:

*Автор:
E-Mail:
*Текст: