Производительность web: Why Performance Matters
Как сделать сайт, который понравится пользователю? Какой он должен быть: красивый, с удобной навигацией, с запоминающимся URL? Прежде всего, сайт не должен тормозить — у пользователя должно складываться впечатление, что всё летает. Это первично. Всё остальное решается по мере разработки. О том, как воспринимают сайт пользователи, от чего это зависит и когда производительность решает, мы поговорили с Денисом Мишуновым, руководителем отдела фронтенд разработки. Остальные слова излишни — просто читайте, это квинтэссенция знаний для любого фронтендера.
— Расскажи о себе. Какой был путь к web-разработке, почему именно она? Чем ты сейчас занимаешься?
— До того, что сейчас называют веб-разработкой, я дошёл быстро, уверенно и предсказуемо: первый компьютер, первый, никому не нужный, сайт, осознание бренности бытия. Дальше было чтение первых страниц «Программирование на Perl» Ларри Уилла и Тома Кристиансен с депрессивным верблюдом на обложке, повторное осознание бренности бытия и, как следствие, откладывание верблюдокниги. А потом я открыл для себя «Designing with Web Standards» Джеффри Зельдмана. Потом было, конечно же, «Ководство» Лебедева и много всего остального. Но книга Зельдмана была переломной. Хотелось бы сказать что-то красивое типа: «мир веба захватил меня после прочтения», но на самом деле я просто понял, что по сравнению с «конструктор электронных аппаратов» (которых из нас тщетно пытались сделать в институте), интернет-разработчик, а именно так это называлось в начале нулевых, звучит откровенно круче.
После этого были поиски себя в многолетней работе с системой управления содержимым Plone, работе над сайтами больших и не очень компаний, очередное осознание бренности бытия и, как следствие, переезд в Норвегию.
Сейчас я работаю в небольшой, но очень амбициозной компании Digital Garden AS, где возглавляю отдел фронтенд разработки. Занимаюсь архитектурой и внедрением всего стека фронтенд-технологий от A до Å, как говорят у нас в Норвегии. Отдел у нас дружный и состоит только из меня. Поэтому конфликты сведены к минимуму, хотя разногласия иногда и возникают.
— Расскажи о «симптомах торможения». Где начинать искать причины сразу, а куда заглядывать в последнюю очередь?
— «Главный симптом торможения — это торможение.» Это можно цитировать. Если серьезно, виды проблем с производительностью могут быть различные и, соответственно, решать их нужно по- разному. Но, скорее всего, потеря производительности либо происходит постепенно: вы загружаете все больше и больше кода, который все хуже и хуже поддается оптимизации в браузере; либо потеря производительности происходит мгновенно, и, соответственно, причины нужно искать в последнем коммите, последней загрузке на сервер и так далее. В последнем случае рецепт прост — откатить до предыдущей версии и подвергнуть тщательному тестированию последние изменения перед повторной загрузкой в проект. В случае с постепенной потерей производительности дела обстоят сложнее, но по теме написания качественного кода и его оптимизации информации в интернете на данный момент больше, чем фотографий котиков, и обсуждать это не совсем благодарное дело — у каждого свой рецепт качественного кода.
— Кто чаще всего виноват в снижении производительности: фронтенд или бекенд?
— Знаете, как и любую другую проблему, снижение производительности нельзя рассматривать однобоко и говорить, что виноват тот или другой. У любой медали две стороны. Бывают проблемы на стороне сервера: например запросы к API обрабатываются слишком долго, или сам ответ по причине неоптимальной архитектуры доходит от сервера слишком медленно. Но, как показывает практика, все эти «неурядицы» на сервере не должны быть причиной медленного интерфейса, и фронтенд должен быть готов «подставить плечо» в такой момент. Каким образом это должно происходить — зависит от ситуации. В начале июня в Питере, в рамках конференции HolyJS я представлю доклад «В погоне за производительностью. Психология пользователя» в котором расскажу про некоторые такие моменты.
— Допустим, сайт готов, но постепенно выявляются проблемы. Как замаскировать их перед пользователем, пока вносятся фиксы?
— Не ждите — запускайте проект, и ваши пользователи сами сообщат вам, где нужно маскировать проблемы, будьте уверены. А в зависимости от проблемы вы поймете как ее замаскировать. Я понимаю, что не все проекты могут позволить себе такой подход. Да и разработчики, как правило, имеют исключительно ранимые души, и минимальная критика повергает их в депрессию. Я, наверное, и сам такой. Тем не менее, без тестирования на реальных пользователях, будь то тестировщики или конечные пользователи, предположение о том, что будет иметь значение для пользователя, а что нет, остается на уровне спекуляции. Само собой, это если мы говорим про производительность, а не про очевидные проблемы типа отказов сервера, кучи ошибок в JS консоли и других «прелестей».
— Может ли повлиять на производительность сторонний код? Допустим, счётчики (на сайте), виджеты (в случае приложения). Кто виноват? Как обойти?
— И опять «Кто виноват?» Этот вопрос для русского человека сакральный. Он почему-то гораздо важнее, чем «Что делать?», хотя искать виновных дело неблагородное. На самом деле есть реальность, в которую надо вписаться, и в данном случае мы имеем следующее:
- на сайт нужно прикрутить *необходимый* виджет;
- виджет, зачастую, замедляет быстродействие сайта;
Как видите, тут некого винить — вы сами решили, что этот виджет нужен, и сами же «прикрутили» его, понизив производительность. Так что вопрос «Что делать?» в данном случае гораздо более актуальный, но возможные ответы на него предельно просты и, я уверен, знакомы большинству читателей Хабра.
Прежде всего асинхронность — загружать сторонние виджеты без блокировки страницы. Если вы не пользуетесь каким-либо AMD загрузчиком типа require.js, а пишите script напрямую, то все модули, не задействованные в построении страницы, желательно загружать с параметром async. Поддержка этого атрибута достаточна для современного приложения. Для браузеров, не поддерживающих async, можно использовать классический вариант асинхронной загрузки виджетов.
Для более сложных зависимостей и задач можно использовать Service Worker или Web Workers API.
— Как с производительностью связан дизайн сайта или приложения?
— Иногда разработчики пытаются переложить вину за низкую производительность своих проектов на все что угодно, включая дизайн (возвращаемся к вопросу «Кто виноват?»). Все мы слышали рассказы вроде: «Ой, у нас дизайнер такие большие картинки на сайт закатал…» или «Ну что вы, у нас сервер отдает ответ только в течение 5 секунд…» — которые, якобы, должны пояснить низкую производительность. Зачастую это означает: «У меня нет времени заниматься всякой ерундой — лучше пойду прикручу новый фреймворк.» Да, много чего влияет на производительность, но это отнюдь не значит, что это должно каким-то образом сказываться на ваших пользователях. Используйте психологию пользователя для «закрытия дыр» и выигрыша во времени для реального исправления реальных проблем. Как конкретно, об этом я буду рассказывать в своем докладе в Питере.
Ах, да! И никакой связи между производительностью и дизайном нет. Только тс-с-с-с — об этом никому.
— Порекомендуй стек технологий для разработки web-приложения? Есть универсальные подходы?
— Я порекомендую тот стек, с которым разработчик чувствует себя комфортно. Не нужно гнаться за баззвордами и браться за все, чем нас кормит сегодняшняя индустрия — времени и сил охватить все новинки не хватит никогда. Прежде чем переносить фронтенд на новый стек, например, спросите себя: «А что не устраивает в том стеке, что уже есть?» Если ответы закончатся на: «Стек устарел», то можно успокоиться и изучать новые технологии, инструменты и фреймворки, не трогая основной проект, выполняющий свои функции. Если же действительно есть необходимость что-то менять: безопасность, сложность или невозможность поддержания кода (например, разработчик текущей версии уволился, а новый разработчик не знаком с текущим решением или чувствует себя с другой технологией как рыба в воде), и так далее, то тут решения тоже нужно принимать осторожно, не загоняя самого или саму себя в угол.
Если разработчик чувствует себя комфортнее с чистым языками и технологиями типа Javascript и CSS без библиотек — прекрасно. В большинстве случаев это дает полный контроль и понимание того, что происходит «под капотом» проекта. Но этот контроль приходит, соответственно, за счет больших потерь времени при разработке — приходится изобретать велосипед снова и снова. Для решения этой проблемы у нас есть фреймворки, библиотеки, компиляторы и другие звери. Что из них выбрать — вопрос риторический. Разработчик должен психологически свыкнуться с мыслью о делегировании некоторых задач некоему неконтролируемому или плохо контролируемому объекту. Более того, разработчик должен понимать, что поддержка фреймворка может закончиться, новая версия может поломать старый код, может случиться что угодно. Такой подход, как правило, экономя время на разработку, тем не менее, либо диктует стиль написания приложений, либо понижает производительность приложения, либо оставляет какой-то другой отпечаток на процессах разработки и самих проектах.
Так что все зависит от гибкости и предпочтений разработчика. Например я чувствую себя достаточно комфортно, продолжая писать фронтенд приложения на Backbone. Когда я упомянул об этом во время панельной дискуссии о будущем Javascript на прошедшей в Минске FDConf в апреле, то поймал на себе много сочувствующих взглядов, как будто меня заставили тестировать под IE6. Тем не менее, мне комфортнее поддерживать проект на Backbone, с которым мы уже несколько лет, нежели кидаться от Angular к реакту, мотаясь между различными версиями, и тратить силы, обновляя код, который не работает в новой версии. Мне проще перейти на чистый Javascript в существующих проектах, чем переносить их на очередной баззворд без причины. Может быть это возраст :)
В моем стеке инструментов для разработки присутствуют:
- Backbone — для основной архитектуры и организации приложений;
- underscore — для упрощения жизни;
- require.js — опять-таки, для организации. Плюс, что немаловажно, для оптимизации кода для продакшена (r.js); node — в основном для написание скриптов, предназначенных для решения каких-то вспомогательных задач;
- Grunt — для сборки проектов;
- старый добрый bash — так как проектов много, и некоторые из них имеют общие модули, встает задача одновременной сборки всех проектов, содержащих модуль, в который внесены изменения. Покопавшись с node для решения этой задачи, я пришел к выводу, что node и git не самые лучше друзья — NodeGit простотой меня не порадовал. Так что node-скрипт я заменил понятным и предсказуемым bash-скриптом, который успешно все обновляет, собирает, загружает и все с помощью одной лишь команды для всех проектов сразу. Мне остается только обновиться на стороне сервера.
Тем не менее, для новых проектов я, конечно же, смотрю на новые технологии и изучаю их, чтобы понять, что может вписаться в моё видение разработки, а что нет. Например, параллельно, занимаюсь внедрением веб-компонентов на Polymer в различные, не сильно нагруженные, участки кода, так как идея таких компонентов соответствует моему видению организации кода.
— Какие web-приложения чаще всего страдают снижением производительности? Почему?
— Нет особой категории приложений более или менее подверженных проблемам с производительностью. Основной барьер на пути к производительности зачастую находится между стулом и клавиатурой. Тем не менее, некоторые приложения сложнее оптимизировать в плане производительности. Например, приложения типа агрегаторов для поиска авиабилетов или подбора туров с долгими и объемными запросами в базу данных. Идеи по поводу того, как справляться с проблемами ожидания в случае, если не удается оптимизировать техническую сторону вопроса, я раскрываю в третьей части своей статьи «Why Performance Matters» в Smashing Magazine.
— Как тестировать производительность web, какие метрики должны радовать, а какие — настораживать?
— Для меня основной параметр, который я всегда контролирую, — это время до начала отрисовки (RUM First Paint для тех, кто использует webpagetest.org).
Многие закладывают отдельный бюджет на производительность, который ограничивает максимальный объем данных различного типа для того, чтобы производительность была на уровне. Есть инструменты типа performancebudget.io, позволяющие получить такой бюджет. Но прежде всего нужно понимать откуда берутся цифры для такого бюджета, на чем основываются ограничения по времени загрузки страницы и так далее.
— Какие приложения в вебе, на твой взгляд, близки к совершенству и радуют тебя? Почему?
— Меня радуют приложения, которые работают. Которые предсказуемы. Если они ко всему прочему ещё и красивые — совсем хорошо. Но как только эстетика начинает преобладать над содержанием, становится скучно, а если есть альтернативные проекты, то и вообще бесполезно.
— Если что-то тормозит, висит и не открывается — первопричина плохо написанный код или всё не так банально?
— Наверное, если «что-то тормозит, висит и не открывается», то причина, скорее всего, в физиологии. Но если мы говорим про веб-проекты, то причин может быть масса — от простого try…catch в Javascript (не оптимизируется компилятором) до, само собой, задержек на сервере. Любые проблемы производительности рассматриваются в контексте отдельного проекта.
— Уровни приложений и сайтов разные: от приложения для друзей до нагруженных сервисов. Когда начинать заморачиваться по поводу производительности?
— Вы сами поймете когда. Но, скорее всего, заморачиваться вообще не стоит. Нужно трезво оценивать масштаб проблемы для того, чтобы применить адекватное решение. Например, если новая функция, которую вы загрузили на свой сайт замедляет его, скажем, на 100 миллисекунд, не нужно кидаться в бой и отвоевывать это время. Задумайтесь, а заметит ли пользователь это замедление? Играет ли оно какую-то роль для него? Играет ли это какую-то существенную роль для ранжирования вашего сайта в результатах поиска? Несмотря на то, что производительность очень важна в современных приложениях, зачастую мы тратим энергию на незначительные вещи, не имеющие никакого значения для кого-то ещё кроме нашего эго.
— Тема твоего будущего доклада звучит нетривиально, не терпится узнать подробности. На конференции ты будешь рассказывать о том, как управлять восприятием пользователя. Как это? Это технические приёмы, чистая психология или что-то на стыке? Расскажи об этом.
— На самом деле нетривиально только название. А по сути, все достаточно просто: производительность, которую мы измеряем в миллисекундах, килобайтах, количестве запросов к серверу и так далее, зачастую отличается от того, как пользователь воспринимает ваш сайт. Но, как бы это странно не звучало, мы, как разработчики, в состоянии влиять на это восприятие. Например, сайту uniweb.no для того, чтобы загрузить 1,8Мб контента при 70 серверных запросах из Москвы на среднем интернет-соединении (1,5 МБ/с), требуется 19,476 секунд. Тем не менее, если вы загрузите этот сайт в своем браузере, вы абсолютно не заметите этих секунд. Попробуйте.
Всё, что мы с вами видим вокруг — это результат нашего восприятия, наш мозг обрабатывает информацию вокруг нас, и то, что мы «видим» — это лишь следствие этой обработки. В этом докладе я на примерах расскажу основы того, что же такое психологическая оптимизация производительности, как это работает, какие методики для управления восприятия пользователя существуют и как их использовать во фронтенд-разработке.
— Даже не верится, что дело не только на стороне сайта. Как влиять на восприятие? Раскрой секреты.
— Способов влияния на восприятие человека масса: утюг, паяльник, различные запрещенные препараты, в конце концов. Но если серьезно, никаких секретов здесь нет, а есть определенные техники управления восприятием пользователя. Подробнее об этом я рассказываю в, уже упомянутой, серии статей «Why Performance Matters». Уверен, что пытливый читатель почерпнет из них массу полезной информации. А те, кому лень читать, могут получить информацию из первых уст на конференции… ну вы в курсе уже.
— А вообще, как пользователь видит сайт? Чем его взгляд отличается от взгляда разработчика? Что важно пользователю, а на чём он не заострит внимание?
— Пользователь — это такой себе «чёрный ящик». Никогда не известно, что происходит внутри него. Соответственно, никогда не известно, что действительно важно для каждого отдельного пользователя. Каждый из них находится в своем контексте: он может торопиться, а может спокойно сидеть, развалившись на диване; он может искать что-то конкретное, а может просто просматривать все товары, имеющиеся в вашем интернет-магазине. У всех этих пользователей будет различное восприятие вашего проекта. К сожалению, нельзя сделать проект, который будет работать одинаково для всех, и нужно это принимать как должное. Тем не менее, психология — это и есть общий знаменатель, объединяющий таких разных пользователей.
Психологически время у нас в голове обычно отличается от реального времени на часах
— Денис, напоследок поделись каким-нибудь коротким чек-листом с критическими проблемами фронтенда, которые вот прямо must have для каждого разработчика?
— Информации на эту тему в интернете масса. О ней не пишет разве что ленивый. Но вкратце всё сводится к какому-то такому варианту:
- Компрессия + оптимизация + снижение количества серверных запросов. Все это относится как к Javascript, так и к CSS. Про такие вещи, как оптимизация изображений с помощью ImageOptim, OptiPNG и так далее, я отдельно даже не упоминаю. Но стоит упомянуть про новый элемент picture, который, будучи предназначен для адаптивных решений, тем не менее, снижает нагрузку и на производительность сайта.
- Контролируйте время до начала отрисовки страниц (RUM First Paint), так как это один из самых важных параметров, характеризующих производительность вашего сайта с точки зрения пользователя.
- Минимизация количества блокирующих элементов. Асинхронность, асинхронность, асинхронность.
В апреле это года, после консультаций со многими специалистами по оптимизации производительности, KeyCDN собрали хороший список параметров и техник, помогающих держать производительность под контролем.
Но нужно понимать основное — как я уже сказал ранее, каждый проект, с которым вы работаете, уникален, и не существует универсальных решений для всего спектра возможных проблем, с которыми вы столкнетесь. Есть какие-то базовые вещи, которые нужно просто понимать и, исходя из этого понимания, принимать то или иное решение. Поэтому самый главные совет, который я могу дать читателям, — думайте и не старайтесь применять к своим проектам все, о чём пишут в статьях, туториалах и так далее. Вместо этого старайтесь понять почему так, а не иначе. В конце концов, ваши проекты зачастую это не поле для экспериментов, а рабочий организм, который должен продолжать работать.
Всех, кто хочет услышать подробности доклада Дениса и послушать других докладчиков по теме web-разработки, ждём на HolyJS 5 июня в Санкт-Петербурге. Не знаем, как с погодой, но у нас будет жарко!
P.S.: в посте использованы рисунки Дениса Мишунова