инструменты


Предыдущая статья про Ruby on Rails, как всегда, выродилась в грандиозный флейм вокруг PHP. Кто-то говорит, что Rails в самое ближайшее время вытеснит PHP на свалку истории, кто-то говорит, что Rails будет портирован на PHP и на свалку истории отправится как раз Ruby. Все остальные мнения — где-то посередине между этими крайностями.

Я считаю, что Rails займет нишу элитарного инструмента, а PHP продолжит доминировать в категории языков, совместимых с лоботомией. Но это тема для другой статьи…

Сегодня же давайте рассмотрим следующую по популярности тему религиозных войн Rails vs. Django vs. PHP — движки HTML-шаблонов. На самом деле, спор чаще всего идет о синтаксисе шаблонов. Такие особенности конкретных движков, как скорость рендеринга, способ обработки ошибок и т.д. с точки зрения религиозных войн не так интересны.

О важности качественного языка шаблонов

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

Таким образом, проблема продуктивного создания HTML-шаблонов является одной из ключевых проблем повышения продуктивности веб-разработки вообще.

Краткая классификация

Шаблонизатор — это библиотека, позволяющая с помощью специализированного синтаксиса описывать разметку динамических HTML-страниц. Разметка описывается в виде так называемых шаблонов. На основе шаблонов и данных, как правило, предоставленных кодом бизнес-логики (клинические случаи с включением бизнес-логики в шаблоны рассматривать не будем) генерируется результирующий HTML.

Большинство языков шаблонов относится к одной из следующих категорий:

Категория 1. Винегрет из кода и HTML

Шаблонизаторы данной категории позволяют с помощью специального синтаксиса вставлять в HTML блоки исполняемого кода, написанного на языке общего назначения (Java, PHP, Ruby и т.д.).

Примеры шаблонов этой категории: PHP, ASP, JSP, ERb (стандартный шаблонизатор в Ruby on Rails).

Пример синтаксиса:

<% for recipe in @recipes %>
  <tr>
    <td><%= link_to %Q{#{recipe.title}}, :action => 'show', :id => recipe %>
        <%= link_to '(delete)', { :action => 'destroy', :id => recipe },                             
                    :confirm => 'Are you sure?', :post => true %></td>
    <td><%= link_to %Q{#{recipe.category.name}},
                    {:action => 'list', :category_id => recipe.category.id} %></td>
    <td><%=h recipe.date %></td>
  </tr>
<% end %>
</table>

Категория 2. Специализированный синтаксис + HTML

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

Примеры шаблонов этой категории: движок шаблонов Django, Smarty

Пример синтаксиса (Django):

{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

Категория 3. Основанные на XML

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

Примеры шаблонов этой категории: Velocity, ASP.NET

Пример синтаксиса:

<form runat="server">
  Enter a number from 1 to 100:
  <asp:TextBox id="tbox1" runat="server" />
  <br /><br />
  <asp:Button Text="Submit" runat="server" />
  <br />
  <asp:RangeValidator
    ControlToValidate="tbox1"
    MinimumValue="1"
    MaximumValue="100"
    Type="Integer"
    EnableClientScript="false"
    Text="The value must be from 1 to 100!"
    runat="server" />
</form>

Категория 4. Специализированный язык разметки

Шаблоны данной категории целиком написаны на DSL (Domain-Specific Language), отвечающем за генерацию как динамического содержимого, так и, собственно, HTML-разметки.

Примеры шаблонов этой категории: HAML, Markaby

Пример синтаксиса (HAML):

!!!
%html
  %head
    %title= controller.controller_name
    = stylesheet_link_tag 'main'
  %body
    #header
    %h1 BoBlog
  #content= yield
  #footer
    %p All content copyright © Bob

Я уверен, что только четвертая категория шаблонизаторов подходит для серьезного использования. Если, конечно, вы цените свое время.

Сейчас попробую объяснить, почему.


Feel the pain

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

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

Ничего подобного.

Главная проблема большинства шаблонизаторов в том, что уродлив сам синтаксис HTML.

Этот кривой HTML

HTML избыточен и некрасив. Разметка содержит множество элементов, без которых можно было бы обойтись. Сами элементы тоже нельзя назвать образцом изящества. Подробности далее…

Немного истории

Давным-давно, в 60-х годах прошлого века был создан SGML, абстрактный язык разметки для представления максимально разнообразной информации в виде структурированных, пригодных для машинного чтения, данных. За универсальность SGML пришлось платить сложностью и громоздкостью синтаксиса. Этот недостаток SGML в полной мере распространяется на его потомков, HTML и XML.

HTML сложно читать.

Простота чтения языка программирования зависит, в первую очередь, от двух параметров:

Лаконичность. В первую очередь определяется количеством строк, необходимых для описания чего-либо. Во вторую очередь, длинной ключевых слов и других часто встречающихся элементов.

Пара примеров:

Java. Все плохо как с количеством строк, так и с их размером:

void cancelAll(Collection<TimerTask> c) {
    for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); ) {
        i.next().cancel();
    }
}

Python. Практически образец лаконичности:

def cancel_all(tasks):
    for task in tasks:
        task.cancel()  

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

Именно из-за проблем с понятностью синтаксис Perl’а, часто называемого write-only языком, нельзя считать удовлетворительным. Вот здесь, например, Steve Yeggie пишет как оператор .. в Perl может, в зависимости от контекста, иметь два абсолютно разных значения. Само собой, такие фокусы способствуют читабельности кода не лучше, чем выражение goto.

Можно предположить, простота чтения языка разметки зависит от тех же ключевых параметров: лаконичности и понятности.

С понятностью у HTML все в порядке: принцип построения документа из тегов способен без особого труда понять даже ребенок. А вот с лаконичностью…

HTML — ну очень многословный язык. Многие часто используемые теги имеют весьма длинные имена. Многие типичные конструкции (например, label и legend) приходится делать с помощью отдельного тега, хотя в большинстве случаев достаточно было бы атрибута. Нет универсального обозначения конца блока, аналогичного end в Ruby или закрывающей фигурной скобке в C-подобных языках — каждый блок HTML закрывается по-своему, в соответствии с именем открывающего тега, следовательно, читателю сложнее распознавать строки, не несущие полезной информации.

Буков много (c)

HTML сложно писать.

Пример из жизни.

В WordPress для написания постов можно использовать WYSIWG-редактор (What You See Is Shat You Get, можно перевести как “что видишь в редакторе, то и получишь в результате”), а можно писать чистый HTML. В моей версии WordPress WYSIWG кривой и то что я вижу в редакторе совсем не соответствует тому, что я получаю на выходе. Причиной проблем является большое количество паразитной разметки, генерируемой упомянутым редактором: пустые теги <p>, пустые теги <b> и <i>, время от времени появляющийся в конце текста незакрытый тег <a>… В результате, для того чтобы написанный пост выглядел хорошо, приходилось руками вычищать HTML.

Через некоторое время я убедился, что вручную писать правильный HTML быстрее, чем вручную же вычищать автоматически созданный. И я стал писать посты в чистом HTML. Жизнь стала легче, но это все же нельзя было считать удовлетворительным решением. Скорость написания форматированного текста в HTML не сравнится со скоростью создания форматированного текста в том же MS Word.

Сейчас я пишу свои тексты с помощью Markdown, специализированного языка разметки. По сравнению с HTML я получаю более симпатичный и читабельный исходный текст, который, к тому же, гораздо проще писать. В результате достигнута заметная экономия времени, притом за счет упразднения самого нудного аспекта создания постов. Мои исходные затраты на поиск и изучение специализированного языка разметки давно окупились. Учтите, что на блог я трачу совсем немного времени. Использование подходящего специализированного языка разметки в работе может принести гораздо большую отдачу.

Небольшое сравнение HTML и Markdown для иллюстрации.

HTML:

<p>Small example of Markdown syntax</p>

<ol>
<li>Red</li>
<li>Green</li>
<li>Blue</li>
</ol>

<p>If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:</p>

<pre><code><blockquote>
    <p>For example.</p>
</blockquote>
</code></pre>

Markdown:

Small example of Markdown syntax

1.  Red
2.  Green
3.  Blue

If you want your page to validate under XHTML 1.0 Strict,
you've got to put paragraph tags in your blockquotes:

    <blockquote>
        <p>For example.</p>
    </blockquote>

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

HAML как альфа-версия шаблонизатора будущего

Показанный выше Markdown очень эффективно решает задачу безболезненного написания HTML, но в относительно узкой нише — написание текстов. Того же самого для несколько более широкого спектра задач добиваются разнообразные wiki-разметки.

Шаблонизатор HAML пытается с использованием тех же принципов создать читабельный и лаконичный синтаксис HTML-шаблонов общего назначения. Дело, как говорится, благородное.

Посмотрим, как у него это получается?

Преимущества

HAML пронизан духом лаконичности. Сокращения, ключевые слова, обозначение блоков — все направлено на сокращение размера кода при максимальном сохранении его ясности.

Рассмотрим основные преимущества подробнее:

  • Наличие сокращений для большинства часто используемых элементов.

    • Какие два атрибута тегов используются чаще всего? Class и id. В HAML <tr class="odd" id="first_row"> превращается в %tr#first_row.odd. Используются те же обозначения что и в CSS, что заметно упрощает обучение.
    • Большинство ключевых слов состоят из одного символа: %, =, -, ., #. Думаю, не нужно говорить, насколько это сокращает получающийся в итоге код.
    • Любители верстки divами (а это заметная часть прогрессивного человечества) могут наслаждаться тем, что div является тегом по умолчанию. #header и %div#header — одно и то же.

    Это только самое основные сокращения. Полный список можно посмотреть в HAML Reference

  • Способ обозначения блоков. Блоки в HAML обозначаются с помощью отступов, аналогично Python. Вот такой код: %one %two %three Hey there преобразуется в: Hey there

    Можно по-разному относиться к Python’овскому стилю обозначения блоков (лично я — его большой поклонник), но нельзя не признать что этот способ гораздо удачнее, чем закрывающие теги, используемые в HTML (я уже писал про связанные с ними проблемы).

  • Возможность сочетать HAML и ERb в одном приложении. Допустим, нужно найти шаблон с именем ‘xyz’ (или partial, не суть важно). Плагин HAML переписывает стандартный загрузчик шаблонов так, чтобы сначала пытаться загрузить xyz.haml, а в случае неудачи — xyz.rhtml. Соответственно, можно не переписывать все ERb-шаблоны в проекте на HAML, а заменять их по одному и только там, где это наиболее оправдано.

Проблемы

HAML пока используется относительно небольшим количеством людей. Версия 1.0 была выпущена только два месяца назад, 15 января 2007 года. В результате, общая стабильность не может, разумеется, сравниться с ERb, а ваши шансы столкнуться в своем проекте с неизвестными багами гораздо выше.

Но это только абстрактные размышления.

Из конкретных проблем я встречался только со сложностью отладки. HAML реализован таким образом, что шаблоны компилируются в ERb, который затем рендерится с помощью ERb-библиотеки. В результате, в случае ошибки Stack Trace ссылается на фрагмент ERb-шаблона, который вы никогда не увидите целиком. Диагностика проблем в таких условиях может быть очень нетривиальной.

Грядущее упрощение языков разметки?

Я считаю, что существует четкий тренд развития языков разметки в сторону упрощения чтения и редактирования человеком. У HTML и XML, сегодняшних стандартов де-факто, с этим серьезные проблемы. Их синтаксис нацелен на максимальную универсальность применения и простоту парсинга, и жертвует при этом компактностью, а следовательно, легкостью чтения и редактирования. Такая ситуация не может быть сохраняться бесконечно.

Языки программирования со сборкой мусора (garbage collection) вытеснили из большинства ниш языки с непосредственным управлением памятью. Динамические языки вытесняют языки со статической типизацией. Оба этих изменения направлены на экономию времени разработчика за счет снижения производительности. Подобное изменение ждет и языки разметки.

Предсказание будущего — штука неблагодарная. Особенно — в области высоких технологий. Я знаю, что на самом деле все будет совсем не так, как мне сейчас представляется, и через пару лет я от души посмеюсь, читая эти строки. Тем не менее, осмелюсь сделать прогноз эволюции шаблонизаторов на ближайшие годы.

  • Шаблонизаторы категории “Винегрет” продолжают использоваться в большинстве PHP-разработок. Разработчики, обладающие достаточной квалификацией для использования продвинутых шаблонизаторов типа Smarty (и, что важнее, достаточной квалификацией, для того чтобы понять, зачем это нужно) будут постепенно откочевывать в сторону Rails, Django и других подобных фреймворков, которые наверняка появятся в ближайшем будущем.

    Шаблонизатором по умолчанию в Ruby on Rails 2.0 становится HAML, тем самым выводя Rails из группы платформ, использующих “Винегрет”.

  • Шаблонизаторы на основе специализированного синтаксиса + HTML также теряют часть своей аудитории в пользу HAML сотоварищи. Тем не менее, данная категория остается достаточно популярной благодаря простоте синтаксиса и возможности четкой диагностики ошибок. Именно такими шаблонизаторами, в большинстве своем. пользуются дизайнеры и HTML-верстальщики, не желающие/не способные переучиваться на без-HTML’ный DSL.

  • XML постепенно отступает в нишу машинной сериализации данных. С этой точки зрения громоздкость его синтаксиса не является большим недостатком (хотя и увеличивает объем трафика при передаче данных по сети). Гораздо важнее простота парсинга и возможность формальной валидации. Ruby, Python и другие динамические языки активно переходят к использованию вместо XML «облегченных» форматов, в частности YAML.

    Шаблонизаторы на основе XML, вероятно, сохранят популярность в C# и Javа. Хотя замена таких шаблонизаторов на более «легкие» решения и предоставляет значительные возможности экономии времени разработчиков, сознательный выбор языка со статической типизацией говорит о том, что скорость разработки, скорее всего, не является первым приоритетом при выборе технологий в данном проекте. В таких условиях использование XML вполне адекватно.

  • Специализированные языки шаблонов набирают популярность. За счёт значительно повышения удобства и скорости разработки при сохранении приемлемой производительности приложений шаблонизаторы этой категории становятся наилучшим выбором для большинства задач.

  • Столица, разумеется, переносится в Нью-Васюки :)

Материалы по теме

  • Серия статей Ивана Сагалаева с критикой использования XHML вместо HTML. Отлично изложены аргументы, доказывающие ущербность оптимизации парсинга разметки за счет увеличения трудоемкости ее создания.

Спасибо Артему Скорецкому и Анатолию Иванову, читавшим черновики этой статьи и внесшим немало ценных идей.

« Previous PageNext Page »