30.03.2008

5 копеек

Гуляя сегодня по набережной Москвы-реки в Марьино, обнаружил престранное сооружение. В центре этой мраморной конструкции находится пятикопеечная монета. Вокруг монеты написаны названия московских вузов.

Что бы это значило? Мое предположение, что это сродни носу у собаки на станции метро «Площадь Революции» за который нужно подержаться перед сдачей экзамена. Здесь же, видимо, нужно встать в центр на пятикопеечную монету и мысленно сказать «халява на экзамене, приди!»

Второй вариант использования — для выбора вуза куда поступать. Становишься в центр, закрываешь глаза и бросаешь монетку вверх. На какой вуз попала — туда и пошел :-)

27.03.2008

JavaScript: Closure

На русский closure обычно переводят как «замыкание».

John Resig в своей книге Pro JavaScript Techniques, которую я сейчас читаю, привел ссылку на статью JavaScript Closures. Это очень мощная, пожалуй, самая глубокая и фундаментальная статья по JavaScript, которую я когда-либо читал. Респект автору, Ричарду Корнфорду.

Стал копать дальше, нашел еще замечательную статью: JavaScript Closures for Dummies. Написано очень понятно, с хорошими примерами. Рекомендую начать с этой статьи, если вы только осваиваете closure. Отдельно отметим оригинальную находку автора поместить кусочек JavaScript-кода на кнопку, который этот код запускает.

Также достойны вашего внимания еще две статьи о closure: на Википедии и Мартина Фаулера. В этих статьях речь идет о closure вообще как о концепции программирования, безотносительно к JavaScript.

Что касается книги Ресига, то я несколько разочарован. Материал изложен поверхностно, не хватает глубины как в статье Корнфорда. Много опечаток и ошибок. Как раз в одном из примеров на closure есть концептуальная ошибка, пример не работает. Не понятно как так можно, что он, не оттестировал примеры перед публикацией что-ли?

UPD: Ошибка в примере на closure (листинг 2-16) есть только в исходном коде, который можно скачать с сайта книги. В самой книге этой ошибки нет.

Жду книгу Дугласа Крокфорда. Надеюсь, старина Крокфорд не подведет :-)

26.03.2008

XSLT: сборная солянка

Несколько неочевидных моментов по XSLT.

1. avg, min, max

В XSLT нет агрегатных функций avg(), min(), max(). Есть только count() и sum().

Предположим, у нас есть такой XML:

<list>
   <item>10</item>
   <item>5</item>
   <item>25</item>
</list>

Среднее значение можно посчитать так:

<xsl:variable name="avg" select="sum(/list/item) div count(/list/item)"/>

Минимум и максимум чуть сложнее. Бежим по отсортированным по возрастанию/убыванию нодам и берем первую:

<xsl:variable name="min">
   <xsl:for-each select="/list/item">
      <xsl:sort data-type="number" order="ascending"/>
      <xsl:if test="position() = 1"><xsl:value-of select="."/></xsl:if>
   </xsl:for-each>
</xsl:variable>

<xsl:variable name="max">
   <xsl:for-each select="/list/item">
      <xsl:sort data-type="number" order="descending"/>
      <xsl:if test="position() = 1"><xsl:value-of select="."/></xsl:if>
   </xsl:for-each>
</xsl:variable>

2. current()

current() внутри квадратных скобок позволяет выйти из контекста ноды к которой применены эти скобки и вернуться к контексту текущей ноды (которая была заматчена шаблоном или заселекчена <xsl:for-each>).

То есть вместо того, чтобы создавать переменную:

<xsl:template match="navigation">
   <xsl:variable name="status" select="@status"/>
   <xsl:value-of select="/captions/caption[@status = $status]"/>
</xsl:template>

можно написать так:

<xsl:template match="navigation">
   <xsl:value-of select="/captions/caption[@status = current()/@status]"/>
</xsl:template>

3. concat()

Работает быстрее:

<xsl:value-of select="concat(@Name, ' ', @Surname)"/>

чем:

<xsl:value-of select="@Name"/>
<xsl:value-of select="' '"/>
<xsl:value-of select="@Surname"/>

Потому что в первом случае происходит только одна операция вставки в результирующее XML-дерево.

Не говоря уже о том, что первый вариант компактнее.

4. not() vs. !=

В некоторых версиях XSLT-процессоров есть разница:

not(@name = 'Stepan')

<a name="Stepan"/> => false
<a name="Leechy"/> => true
<a/> => true

@name != 'Stepan'

<a name="Stepan"/> => false
<a name="Leechy"/> => true
<a/> => false

Пару раз когда использовал != сталкивался с тем, что вылезала бага при переносе кода с разработческого сервера на хостинг, где стоял другой XSLT-процессор. Поэтому рекомендую всегда использовать not().

5. Глобальные переменные → ускорение

Переменная Regions вычисляется каждый раз при вызове шаблона для <MuscatRow>:

<xsl:template match="MuscatRow">
   <xsl:variable name="Regions" select="/Imprimatur/Element[@Name = 'Regions']/Document"/>
   <xsl:value-of select="$Regions[@Name = current()/@Name]/content"/>
</xsl:template>

Используя глобальную переменную можно добиться некоторого ускорения. Переменная Regions вычисляется один раз:

<xsl:variable name="Regions" select="/Imprimatur/Element[@Name = 'Regions']/Document"/>
<xsl:template match="MuscatRow">
   <xsl:value-of select="$Regions[@Name = current()/@Name]/content"/>
</xsl:template>

Актуально при большом количестве <MuscatRow>.

6. Отсчет preceding-sibling-ов

preceding-sibling[1] — это ближайший предыдущий элемент.

Получается вот что:

preceding-sibling[last()]
...
preceding-sibling[2]
preceding-sibling[1]
current item
following-sibling[1]
following-sibling[2]
...
following-sibling[last()]

HTML: контейнеры

Как бы вы заверстали копирайт? Варианты ответов:

<p id="copyright">(с) 2005 Company Inc.</p>

<div id="copyright">(с) 2005 Company Inc.</div>

<div id="copyright">
   <p>(с) 2008 Company Inc.</p>
</div>

Первый вариант ограничивает нас только одним абзацем. Если со временем потребуется добавить второй абзац копирайта, то верстку придется переделать. Кроме того, представим, что вдруг потребовалось вставить в копирайт блок с какой-то сложной версткой (очередное дизайнерское извращение). Тег <p> не может содержать блоковых элементов, поэтому опять-таки придется переделать.

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

Однако, я выбираю третий вариант, не смотря на то, что он самый длинный. Тег <p> добавляет еще немного семантики — получается «параграф текста внутри блока копирайта».

Еще один плюс: в версии без стилей блоки текста не слипнутся.

Простой пример.

В версии без стилей текст слипнется:

<div id="some_additional_info">Some additional info.</div>

<div id="copyright">(с) 2008 Company Inc.</div>

А так не слипнется:

<div id="some_additional_info">
   <p>Some additional info.</p>
</div>

<div id="copyright">
   <p>(с) 2008 Company Inc.</p>
</div>

Кстати, проверять верстку с отключенными стилями вообще очень полезно. Если сайтом по-прежнему можно пользоваться, значит сверстано семантически грамотно.

21.03.2008

Про компромиссы

Важно уметь найти компромисс.

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

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

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

— Знать грань, когда лучше пойти договориться с дизайнером, чтобы он немного перерисовал, вместо того чтобы умирать, верстая ебанистический макет.

XSLT: sort

Используя <xsl:sort> нужно иметь в виду два момента.

— При хождении от текущего элемента по осям preceding-sibling и following-sibling, мы ходим по исходному дереву.

<xsl:for-each select="item">
   <xsl:sort select="name" />
   <!-- preceding-sibling и following-sibling работают по исходным,
        не отсортированным данным -->
</xsl:for-each>

position() после <xsl:sort> возвращает позицию в отсортированном дереве.

CSS: line-height

Как-то я долго мучился с line-height.

Задавал его в em и процентах у body и были жуткие глюки с наследованием.

Я уже было отчаялся и решил жахнуть стиль для звездочки:
* {line-height: 1.4em;}

Но тут, коллега подсказал мне, что line-height нужно указывать без единиц измерения.

Оказывается, если указывать line-height в em или %, то при наследовании браузеры не пересчитывают line-height в зависимости от размера шрифта текущего элемента. Из-за этого у меня в <h1> слипались строчки.

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

Правки в чужом коде

Когда меня просят помочь по какому-либо проекту, я всегда сначала потрачу 15 минут на изучение особенностей написания кода в данном проекте. Как именуются классы и айдишники в CSS, переменные и методы в JavaScript, шаблоны и моды в XSL. Как отбиваются блоки кода пустыми строками, где стоят пробелы, а где нет. И постараюсь сделать в этом же стиле, как бы он не был мне противен.

Никто не любит править чужой код. Но также неприятно открыть свой код и увидеть, что кто-то нагадил там в другом стиле :-) Это все равно как если бы Зюсмайер, дописывая «Реквием» Моцарта, вставил бы туда какую-нибудь отсебятину, пусть и хорошую. Хорошо, но не в кассу. Нужно уважать автора и его стиль программирования.

JavaScript: return this;

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

myObj.prepare().activate();

Напомню, что если метод явно ничего не возвращает, то он возвращает undefined. Исключение составляют конструкторы, которые по умолчанию и так возвращают this, то есть указатель на новый созданный объект. Поэтому в конструкторах не нужно писать return.

20.03.2008

Смотреть в будущее

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

27 июня 2005 года эта фраза висела на главной странице Студии.

19.03.2008

Мысли по поводу организации работы

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

Я за такую схему работы: более опытный технолог начинает проект, задает направление, закладывает фундамент, создает базовые шаблоны, основные механизмы и прочее. Менее опытный технолог затем продолжает, а более опытный присматривает и корректирует («ведет») менее опытного.

Нельзя давать человеку одному делать новый проект на незнакомой для него системе (CMS). Человеку сложно сходу придумать хорошую архитектуру решения в новой для него среде разработки. Вопросов которые нужно решить много: где как что хранить, как структурировать шаблоны и прочее. Дай мне сейчас новую систему, отличную от Имприматур I или II, и если мне никто не поможет, я скорее всего тоже сначала сделаю не лучшим образом.

Можно проводить семинары, это, конечно, дает какой-то результат. Однако после семинара человек остается один на один с системой и начинает «ваять».

У менее опытных технологов возможно поначалу будет «ломка». Привыкать к чужому стилю программирования и структурирования информации не просто. Зато они чему-то научатся и не сделают проект, который потом придется переделывать.

Переключение режимов в IE8

Кстати, если кто еще не знает. Микрософт передумали и теперь IE8 по умолчанию будет рендерить в режиме IE8 Standards. Но с помощью <meta> ему можно будет сказать «рендери как IE7». Ранее анонсировалось обратное поведение.

Итого в IE8 будет 3 режима: Quirks, IE7 Standards и IE8 Standards.

Поведение такое:

1. Задан DOCTYPE для стандартного режима или неизвестный DOCTYPE — включается IE8 Standards mode

2. Задан DOCTYPE для режима Quirks или DOCTYPE отсутствует — Quirks mode

3. Есть <meta equiv="X-UA-Compatible" content="IE=7"> — вне зависимости от DOCTYPE, включается IE7 Standards mode

Ссылки по теме:
Microsoft's Interoperability Principles and IE8
The Default Layout Mode