При закрытии подписчики были переданы в рассылку "Работа в сети Интернет" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Здравствуйте, дорогой читатель. Вы уже знаете, что Давайте разберём эту тему. Она, кстати, будет ещё откликаться эхом в последующих статьях. Историческая справка«Ты помнишь, как всё начиналось...» © А. Макаревич Я помню. Начиналось всё с опыта и выводов. ∙Было обнаружено, что данные, с которыми работает программа, являются ключевой субстанцией в решении возложенных на программу задач. Мы можем иметь несколько разных программ, написанных разными людьми и этот зоопарк будет решать задачу заказчика, если все они будут работать с общими согласованными данными. Sic! Не верите? Представьте обратную ситуацию. Бухгалтер работает с 1C, а его директор смотрит данные в Excel. Директор увидит только то, что принесёт ему бухгалтер, после выгрузки. То есть данные, из которых уже изъяты все следы украденного. Нет. Интеграция должна иметь общее основание, и такое основание данные. Далее. Если мы рисуем схему, то на ней должен быть прямоугольник, представляющий собой все данные. А название его должно указывать на то, что он имеет структуру, отражающую реальный мир. Остановились на слове Модель.
∙Далее была обнаружена ещё одна интересная вещь. Оказалось, что в настольных приложениях отрисовка рабочей области окна задача весьма техническая, напоминающая «вещь в себе». А отработка реакции на стандартные раздражители (вроде меню и кнопок) больше похожа на административную, то есть на прямое отражение ТЗ. Должна кнопка копировать в буфер? Вызываем pEditor->copy(); В Веб-приложениях картина та же, только в другом ракурсе. Есть часть, где мы воплощаем задумки дизайнера, а есть часть где мы воплощаем задумки клиента (или отчёт бизнес-аналитика, что с рабочего места программиста выглядит тем же самым). Так вот, если отделить одно от другого, получается удобно. Отрисовку уникального (логику дизайнера) назвали Представление. А всё, что осталось Контроллер. О контроллере. ∙Только что обрисованный способ мышления называется MVC (ModelView-Controller) и имеет вариации, которые тоже полезны. Делим хозяйство с дизайнеромВ фокусе PHP и профессиональная разработка. Дизайнер отдал Вам шаблон, который Вы вряд ли сможете затолкать в строковую константу, поэтому Вы его разместили в отдельном файле. И, возможно, даже применили Smarty. А дальше начинаются детали, а в них, как говорят уже не только французы, дьявол. Дело в том, что решение отделить HTML от PHP заманчиво своей очевидностью. Но это рушит саму идею разделения. Смотрим исходную задачу: <table> <? $q = db_query('SELECT * FROM products'); ?> <? while ($row = db_fetch($q)) {?> <tr <?=$row['is_new']?'class="new"':''?>> <td><?=htmlspecialchars($row['title'])?></td> <td><?=number_format($row['price'], 2, ',', ' ')?></td> </tr> <? } ?> </table> И смотрим очевидное разделение: PHP $q = db_query('SELECT * FROM products'); $list = array(); while ($row = db_fetch($q)) { // Приводим поля к формату, пригодному для шаблона $row['is_new'] = $row['is_new'] ? 'class="new"' : ''; $row['title'] = htmlspecialchars($row['title']); $row['price'] = number_format($row['price'], 2, ',', ' '); // И набор к формату, пригодному для шаблонизатора $list[] = $row; } // Условно, вызов простейшего шаблонизатора. // То есть встроенного. Тут мог быть и Smarty. require 'template/products.php'; HTML <table> <? foreach ($list as $row) { ?> <tr <?=$row['is_new']?>> <td><?=$row['title']?></td> <td><?=$row['price']?></td> </tr> <? } ?> </table> Но существует поверье, что любой программный код в HTML к несчастью. Давайте тогда ещё вариант. PHP $q = db_query('SELECT * FROM products'); $list = array(); while ($row = db_fetch($q)) { // Приводим поля к формату, пригодному для шаблона $row['is_new'] = $row['is_new'] ? 'class="new"' : ''; $row['title'] = htmlspecialchars($row['title']); $row['price'] = number_format($row['price'], 2, ',', ' '); // И набор к формату, пригодному для шаблонизатора $list[] = $row; } // Условно, вызов шаблонизатора, изгоняющего PHP из HTML. $html->set('list', $list); exec_template('products'); HTML <table> <!-- begin_list --> <tr {is_new}> <td>{title}</td> <td>{price}</td> </tr> <!-- end_list --> </table>
Получилось разделение на дизайн В PHP у нас есть «class="new"». Это HTML. Более того, это та самая логика дизайнера, о которой мы говорили выше, то есть часть представления (view). Если дизайнер решит, что теперь строки должны выделяться не классом, а картинкой, то нам придётся а) корректировать код, б) думать, куда встроить URL картинки из дизайна не в PHP же, верно? А если наша программа поддерживает скины, и в одном из них нужен класс, а в другом картинка, а в третьем ещё большее непотребство, то приплыли. Поэтому тут пора признать, что разделение на HTML и PHP при всей своей видимой простоте убило изначальную идею разделения представления и контроллера. Вывод прост: логика, отвечающая за представление, должна находиться там же, где HTML: <table> <? foreach ($list as $row) { ?> <tr <?=$row['is_new']?'class="new"':''?>> <td><?=$row['title']?></td> <td><?=$row['price']?></td> </tr> <? } ?> </table> А где htmlspecialchars и number_format? А это типовые операции. Если поле title хранит простые строки, то их всегда нужно будет экранировать перед выводом. То же самое с форматированием валюты.
Делим хозяйство с клиентомТеперь вернёмся к задаче, решаемой программой. К бизнес-логике. Что хотел клиент от нашей странички? Вывести список продуктов. Всё. Если конспектировать это в терминах будущей программы, то переходное звено могло бы выглядеть так: SELECT FROM products // Что надо template() // Что с этим сделать Или так: template(SELECT FROM products) Собственно это, в совокупности с определением таблицы products, и есть вся бизнес-логика. Остальное делится на:
∙С представлением мы уже разобрались. ∙Доработкой среды по сути является весь код, который увязывает возможности языка и библиотек с желаемым результатом. Например, если мы пользуемся стандартной функцией mysql_query, нам необходимо сохранить дескриптор запроса в отдельной переменной, проверить её на предмет ошибок, обработать ошибку, если она есть, и дальше прогнать цикл по дескриптору. $q = db_query('SELECT * FROM products'); $list = array(); while ($row = db_fetch($q)) { // Приводим поля к формату, пригодному для шаблона $row['title'] = htmlspecialchars($row['title']); $row['price'] = number_format($row['price'], 2, ',', ' '); // Не обязательно: $row['is_new'] = (bool)$row['is_new']; // И набор к формату, пригодному для шаблонизатора $list[] = $row; } // Вызов шаблонизатора require 'template/products.php'; Желаемый код отмечен жёлтым. Остальное махинации над тем, чтобы оно вообще работало. Всё это вместе реализация бизнес-логики. А жёлтый код, Голубым отмечено то, что не относится к текущей части задачи, но следует из структуры таблицы. А структура эта тоже является частью бизнес-логики. Тем не менее, тут мы видим не саму структуру, а только реализацию её следствий.
∙Некоторые ритуалы позволяют сократить число ошибок. В PHP наиболее частым является проверка isset с целью подавления предупреждений. Как для работы программы, так и для её разработки, предупреждения не нужны. Но они очень полезны для выявления ошибок невнимательности на самых ранних стадиях. То же самое касается и этого примера на Java: public static final int THE_ANSWER = 42; Выделенный фрагмент не относится к бизнес-логике, но указывает компилятору на то, как мы собираемся использовать эту константу. Если мы попробуем использовать её Сравним с Ruby: THE_ANSWER = 42 Здесь тоже есть указание на то, что это константа, а не переменная (первая буква заглавная). Всё остальное просто подразумевается. ∙Прочими ритуалами можно назвать то, что сложилось исторически, но пользы не несёт. Например, в PHP нельзя вписать регулярное выражение в текст программы. Его нужно вписывать в строковую константу, с учётом экранирования символов. Это ненужно, но необходимо. ∙В дальнейших статьях я раскрою соображения о том, кто и как может отделить бизнес-логику от активности, касающейся исключительно самого программирования. Вот и всё на сейчасНапоминаю, что моя задача не столько показывать конкретные рецепты, сколько обратить Ваше внимание на неочевидные, но важные вещи. Развилки для мышления. Знание это способность различать больше, чем до его (знания) приобретения. Это позволяет формировать собственный стиль, вместо слепого использования неудобных, но привычных схем. Ещё это позволяет понимать коллег, воспитавших своё мышление на других приоритетах. Этот выпуск Вы можете прокомментировать в Живом Журнале. Задать вопросВы можете задать мне любой вопрос. Все полученные мною вопросы могут быть опубликованы в рассылке. Если Вы желаете скрыть свои личные данные из вопроса укажите это в тексте письма, поскольку в дальнейшем, письма будут публиковаться с полными подписями (без емейлов, разумеется). |
В избранное | ||