Статьи

«Изящная деградация» vs. «постепенное улучшение»

Автор статьи: Кристиан Хейльманн (Christian Heilmann)
Оригинал: http://dev.opera.com/articles/view/graceful-degradation-progressive-enhance/ (3 февраля 2009)

Вступление

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

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

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

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

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

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

«Мобильность в мобильном» — движение в постоянно изменяющемся окружении

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

Веб был изобретен и предназначен для использования с любого устройства отображения, на любом языке и из любого места. Единственное требование к конечным пользователям заключается в использовании браузеров, которые могут подключаться к вебу и понимать протоколы передачи данных: http, https, ftp и другие.

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

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

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

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

Мы трудимся в условиях неопределенности и нам необходимо найти путь, чтобы выполнить свою работу. Именно в этот момент «изящная деградация» и «постепенное улучшение» вступают в игру.

«Изящная деградация» и «постепенное улучшение» под микроскопом

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

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

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

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

Пример

Давайте рассмотрим пример, иллюстрирующий использование обоих методов: и метода «изящная деградация», и метода «постепенное улучшение».

Ссылка «Распечатать эту страницу»

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

Проблема с ссылками «Распечатать эту страницу» заключается в том, что в HTML нет никакой возможности связать их с функцией печати, имеющейся в браузере — для этого необходимо использовать JavaScript. В JavaScript это делается очень просто. Объект браузера window имеет метод print(), который может быть вызван для старта процедуры печати.

Пожалуй, наиболее распространенный способ сделать это заключается в использовании псевдо-протокола javascript::

<p id="printthis">
  <a href="javascript:window.print()">Распечатать эту
    страницу</a>
</p>

Этот способ будет работать, если JavaScript доступен для использования, его поддержка при отображении страниц включена, а браузер поддерживает команду print. Однако, если JavaScript недоступен (например, как на некоторых мобильных устройствах), то эта ссылка работать не будет, и клик по ней ни к чему не приведет.

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

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

Распространенное решение заключается в использовании тега noscript. Все, что находится внутри этого тега, будет показано пользователю с отключенным JavaScript.

В нашем случае это может выглядеть так:

<p id="printthis">
  <a href="javascript:window.print()">Распечатать эту
    страницу</a>
</p>
<noscript>
  <p>
    Для печати страницы необходима поддержка JavaScript.
    Пожалуйста, включите ее в вашем браузере.
  </p>
</noscript>

Это и считается изящной деградацией. Мы объяснили пользователю, что что-то не так и как это исправить. Однако, это предполагает, что посетитель вашего сайта:

  • знает, что такое JavaScript;
  • знает, как его включить;
  • обладает правами и возможностью сделать это;
  • чувствует себя счастливым каждый раз, когда включает JavaScript только для того, чтобы распечатать документ.

Если попробовать перефразировать, то получится немного лучше:

<p id="printthis">
  <a href="javascript:window.print()">Распечатать эту
    страницу</a>
</p>
<noscript>
  <p>
    Для печати копии вашего подтверждения
    кликните иконку “Печать” в вашем браузере
    или выберите пункт “Печать” в меню “Файл”.
  </p>
</noscript>

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

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

Кнопки предназначены для поддержки скриптовой функциональности уже по определению. В спецификации W3C сказано:

Кнопки:
Кнопки не имеют поведения по умолчанию. Каждая кнопка может иметь на клиентской стороне скрипт, связанный с ней через атрибут события. Когда происходит событие (например, пользователь нажимает кнопку, отпускает ее и т.д.) вызывается связанный скрипт.

Далее, мы не проверяем, включен ли у пользователя JavaScript и может ли браузер отправлять документы на печать. Вместо этого мы просто уведомляем пользователя, что ему нужно распечатать документ, и оставляем то, как это будет сделано, на его усмотрение:

<p id="printthis">Спасибо за ваш заказ.
Пожалуйста, распечатайте эту страницу,
чтобы не забыть его параметры.</p>

Этот вариант будет работать в любом случае. Для остальной части функциональности мы используем «ненавязчивый JavaScript», который позволит добавить кнопку печати только тогда, когда браузер это поддерживает:

<p id="printthis">Спасибо за ваш заказ.
Пожалуйста, распечатайте эту страницу,
чтобы не забыть его параметры.</p>
<script type="text/javascript">
(function(){
  if(document.getElementById){
    var pt = document.getElementById('printthis');
    if(pt && typeof window.print === 'function'){
      var but = document.createElement('input');
      but.setAttribute('type','button');
      but.setAttribute('value','Распечатать');
      but.onclick = function(){
        window.print();
      };
      pt.appendChild(but);
    }
  }
})();
</script>

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

  • Оборачивая всю функциональность в анонимную функцию и незамедлительно ее выполняя (это то, что делает конструкция (function(){})()), мы оставляем глобальную область видимости чистой.
  • Мы тестируем браузер на поддержку DOM и пытаемся получить элемент, в который хотим вложить кнопку.
  • Далее мы проверяем, существует ли этот элемент и имеет ли браузер объект window с методом print (путем тестирования этого свойства на тип «функция»).
  • В случае, когда оба условия выполняются, мы создаем новую кнопку и назначаем для нее window.print() в качестве обработчика на клик мышью.
  • Последний шаг — вставляем кнопку внутрь тега параграфа.

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

Когда и что использовать

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

Когда мой ноутбук не может найти беспроводное подключение, я использую для выхода в сеть смартфон Blackberry и очень расстраиваюсь, если веб-сайты сообщают мне о том, что им нужен JavaScript и что я должен его включить. Ведь я не могу это сделать! Но, тем не менее, я — полноправный пользователь ваших продуктов. Особенно тогда, когда плачу кучу денег за GPS- и EDGE-доступ к вашим сервисам.

Однако, метод «изящная деградация» жизнеспособен в ситуации, если:

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

Во всех других случаях метод «постепенное улучшение» сделает вас и ваших пользователей счастливее:

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

Заключение

Можно сказать, что оба метода: и «изящная деградация», и «постепенное улучшение» — делают одну и ту же вещь. Они помогают сделать наш продукт полезным для каждого пользователя.

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

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

Вопросы для самотренировки

  1. В статье рассматриваются ссылки на печать как пример, для реализации которого можно использовать оба метода. Какие другие примеры вы можете привести?
  2. Допустим, что вы хотите использовать JavaScript, чтобы перед отправкой формы проверить, содержит ли поле ввода адрес электронной почты. Чем бы характеризовалась разница в методах для этого случая? Какие сопутствующие проблемы необходимо принять во внимание?
  3. Допустим, что вам нужно отобразить географическую карту и при этом использовать метод «постепенное улучшение». Какой должна быть та базовая функциональность, с которой вы начнете?
  4. Представим себе, что у вас есть интерфейс, состоящий из формы с двумя выпадающими списками. Выбор одного из вариантов в первом списке изменяет список вариантов во втором списке. Что может выступать в роли запасного варианта решения при использования таких типов элементов управления? Какие проблемы при этом могут возникнуть?

Об авторе

Крис Хейльманн занимается веб-разработкой более 10 лет, до этого пробовал себя в радио-журналистике. Работал в английском подразделении компании Yahoo! в качестве тренера и ведущего разработчика, контролировал качество клиентского кода для проектов с аудиторией из Европы и Азии.

Крис ведет блог «Wait till i come», а также присутствует во множестве социальных сетей, таких как «codepo8».

Picture of the article author Chris Heilmann
Photo credit: Bluesmoon

Реклама
Стандартный

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

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s