Веб-скриптинг
За все годы своей практики программирования на PHP я так и не понял, как именно надо писать веб-приложения, чтобы уйти домой с чувством удовлетворения. Приблизительно таким, какое возникает по окончании какого-нибудь хорошего проекта на Си++. Может оказаться, что PHP не для меня, и вообще не для Си++ программистов. Но может он, PHP, и в самом деле настолько немодульный, неэстетичный и нестрогий, что никто в мире не уходит по окончании проекта домой с чувством удовлетворения. И может это касается не только PHP, но и вообще всех скриптинговых языков, используемых для веб-приложений.
И если в мире веб-приложений, в этой довольно молодой области, действительно "что-то не так", то пора бы рассмотреть проблему поглубже и понять что именно и в какой момент в концепциях функциального веба со своими неуклюжими историческими наслоениями пошло "не так".
Ну и printf() с вами!
Философия серверных приложений предельно проста: поскольку данные приходят с сервера, то этот самый сервер может порождать эти самые данные как угодно. Он может читать данные из файла, а может запускть программы, которые будут на основе чего-то там генерировать данные "на ходу". Или он может переспросить эти данные у другого сервера. Красота тут в том, что клиента это совершенно не касается, он видит только результат.
Работаем на результат! - сказали пионеры веб приложений, и понапридумали целую кучу довольно нехитрых способов генерирования данных "на ходу". И поскольку эти пионеры были по сути своей заядлые юниксоиды (thank goodness!), а не специалисты по маркетингу, или еще хуже, виндовозники или джависты, то все получилось очень просто: пишите программу на своем любимом языке, и имейте ввиду, что весь ваш стандартный вывод идет к клиенту. Выводите HTML, GIF, или и вовсе мусор какой - лишь бы клиент вас понял. Берите свой любимый printf() или echo - и вперед. Лепота!
Помнится, когда я впервые, в самый разгар эпохи статических веб-страниц, попробовал SSI, то вскочил на стул и запрыгал от радости приблизительно так же, как и в свое время, 15 лет назад - от своей самой первой программки "Hello, world!" на Фортране (который я называю языком программирования катафалков). Это было настоящее чудо - мой стандартный вывод выполз в клиентском браузере!
Средь зерен и плевел
Но есть, знаете ли, такие средства программирования, которые по сути не идут дальше "Hello, world!". Пробуешь сделать большую систему - и сразу всплывает куча неудобств. А веб - штука капризная хотя бы только потому, что его основная цель - выплюнуть мешанину в формате HTML. В обычных GUI приложениях все относительно более четко: графическая часть, ее создание (в смысле что где лежит на экране) и в конце концов вывод на экран, довольно хорошо отделены от собственно функциональной части. В вашем распоряжении - редакторы диалогов, а также стандартные системные интерфейсы, которые способны вызовом пары функций вывести ваше творение на экран. Главное - вы концентрируетесь на своем коде, и большую часть времени даже и не видите графическую часть своей программы.
Но веб... это совсем другое. По мере того, как ваше приложение усложняется, вы видите все больше и больше printf-ов и HTML кода в своих многострадальных исходниках. HTML - это совсем другая эстетика, которая (хорошая или плохая) никак не вяжется со стилем и эстетикой основного языка вашей программы. Это первый сигнал того, что вы вот-вот потеряете контроль над проектом: код становится нечитабельным.
Вы пытаетесь выделить в функции и модули и убрать с глаз долой какие-то, казалось бы, стандартные части, генерирующие HTML. Но от этого не легче: во-первых, так или иначе, HTML - вещь контекстно-зависимая, и лучше иметь большие куски HTML кода перед глазами, чем распихивать его по функциям и модулям. Во-вторых, с какого-то момента вас (или заказчика) перестает удовлетворять дизайн, и вы понимаете, что этот самый HTML лучше бы сначала получить в каком-нибудь WYSIWYG редакторе вроде Dreamweaver-а. Начинается поиск компромисса между HTML кодом, сгенерированным в WYSIWYG и "сотканным" вручную. Причем есть и еще одна сложность: WYSIWYG редактор не может показать вам хотя бы приблизительно вашу страничку, поскольку в режиме редактирования нет сырых данных (скажем, из ДБ), на основе которых она генерируется.
Вы оказались в бетономешалке веб-программирования. И должен вас огорчить: нет способа (по крайней мере известного мне способа) вылезти из нее и сделать все как-то поприличнее...
Код в крапинку
Шагом вперед в веб программировании можно считать момент, когда появилась возможность "вкраплять" исходный код языка программирования прямо в HTML, а не наоборот, как было раньше, что в какой-то мере решило проблему "бетономешалки". Главная проблема веб-скриптинга, однако, осталась в силе: смешивание стилей HTML и языка программирования X, будь то PHP или VB. Вот как выглядит снэпшот типичного куска на PHP.
Вот и ищите теперь где тут начало и конец ваших if-ов, while-ов, или еще хуже - <table>-ов и <div>-ов. Нет ни начала, ни конца, сплошное месиво. Отступы? Это не помогает, поскольку неясен вообще принцип комбинирования отступов в HTML и в PHP. Для каждого в отдельности - понятен, но вместе, мягко говоря, - не очень. О читабельности, и следовательно об удобстве сопровождения (maintainability, то бишь) и речи быть не может. А вот для сравнения снэпшот С. Чистенько, правда?
Были попытки создания языков, стиль и синтаксис которых очень близки к HTML. Это вроде бы хорошая мысль, но по какой-то причине такие языки не получили популярность. Не пробовал, но полагаю, неудобство с такими языками состоит в том, что в месиво тут уже превращаются чисто функциональные куски кода, в которых нет HTML. Представьте себе функцию сортировки, в которой все операторы окружены угловыми скобками. Почти абсурд. Тоже не годится.
Была даже такая идея... Раз уж это проблема со смешиванием стилей нерешаема, то хотя бы "вкраплять" в HTML наш родной Си++. Не кричите пожалуйста, это вполне осуществимо, и может даже выйдет что-то поприличнее "низкоинтеллектуальных" языков PHP и VB (ой, я кого-то обидел). Может, когда-то будет время и на такой проект.
По матрешкам!
Но есть в веб-программировании и проблемы посерьезнее, осознание которых, похоже, еще не пришло к нам полностью. Веб-приложение - это тоже приложение, но куда сложнее обычного, и вот почему.
В "обычном" программировании существуют традиции разграничения классов данных. Все это ковалось, можно сказать, десятилетиями, и стабилизировалось сравнительно недавно. Мы имеем статические данные, динамические, локальные в функциях, локальные в объектах, и т.д., плюс их многочисленные разновидности: приватные, защищенные, открытые, и проч. Итак, класс памяти, время жизни, права доступа и всевозможные их комбинации.
Клиент-серверные приложения по инерции унаследовали от обычных все перечисленное, но по сути они добавляют от себя и новые типы данных, требующие новых подходов: (1) теперь уже объекты могут "проживать" на сервере или у клиента, (2) времена жизни обогащаются такими понятиями как запрос и сессия, (3) область видимости требует вообще принципиально нового подхода ввиду того, что как правило веб-сайты разграничивают доступ клиентам в зависимости от их условных прав в системе (гость, зарегисрированный пользователь, администратор, итд.)
Что же нам дают в этом свете стандартные средства веб-программирования? Практически ничего, кроме неуклюжей надстройки над cookie в виде модуля управления сессиями. Уже неплохо, но и не хорошо. Даже такая надстройка находится на таком низком уровне, что позволяет легко ошибиться и/или непроизвольно допустить брешь в защите системы. Словом, хороших решений пока что нет и в этой области.
На мысли о новых концепциях в веб-программировании (и в клиент-серверных технологиях вообще) натолкнул Mark Lentczner своим проектом Wheat - это еще один скриптинговый язык, основанный на более ранней разработке Марка - GlyphicScript. (И хоть Wheat находится на стадии разработки, мне довелось познакомиться с этим проектом постольку, поскольку он использует библиотеку PTypes.) Марк ввел с свой язык интересную идею присваивания объектам таких же атрибутов, какие имеют файлы в системе UNIX, т.е. до боли знакомые всякому юниксоиду rw-rw-r--. Это может как-то решить проблему (3): область видимости и права доступа к данным в клиент-серверной среде (см. выше). В проекте Wheat для данных в приложении могут даже возникнуть такие понятия, как директория /cookies, наподобие юниксовских директорий /dev и /proc.
Как самый первый шаг в сторону новых концепций, которые позволят хотя бы классифицировать новые типы данных в клиент-серверной среде (и в частности в веб-приложениях), предлагается следующее. Это не есть решение, но какая-то зацепка, направление, в котором можно пойти дальше. Всякий объект (в широком смысле этого слова) в среде веб-приложения должен иметь как минимум атрибут области видимости/времени жизни, который может быть одним из:
(1) Запрос: объект создается, живет и уничтожается вместе с одним HTTP запросом. Уничтожение такого объекта может быть осуществлено "вручную", либо автоматически, по завершении запроса.
(2) Сессия: время жизни объекта ассоциируется с session cookie, т.е. он живет и умирает вместе с одной сессией браузера.
(3) Клиент: время жизни объекта привязано к persistent cookie, и таким образом он живет некоторое обозначенное приложением время, независимо от сессии браузера.
(4) Сервер: объект перманентный и область его видимости может быть любой, вплоть до глобальной.
Следует отметить, что объектами всех типов по умолчанию "владеет" клиент, который косвенно инициировал их создание в серверном приложении, по аналогии с тем, как в оперционных системах владельцем файла по умолчанию является его создатель.
Каждый из этих четырех классов потенциально является матрешкой, в которой могут быть спрятаны всевозможные комбинации уже известных нам традиционных классов видимости/времени жизни. И пусть не все комбинации возможны, но многие наверняка возникнут.
Словом, хотелось бы иметь в скрипте простые средства описания типа клиент-серверного объекта так, как это делается для обычных статических, локальных и динамических объектов в обычных языках. Мы пишем static, или new - и тем самым сразу же определяем "судьбу" объекта. В вебе этого пока нет: мы должны вникать в сущность управления сессиями, вызывать специальные функции, и т.д., наподобие того, как если бы вместо Си мы были бы вынуждены писать код на ассемблере и создавать фрейм стэка и прочие фокусы связанные с функциями "вручную".