Не так давно мне довелось выступать на конференции FFConf с докладом «Вам следует использовать <впишите нужную библиотеку/фреймворк>, это самое лучшее!». И основные мысли я решил изложить в публикации, в надежде, что это спровоцирует в профессиональной среде более широкую дискуссию о «стоимости» современных фреймворков на мобильных устройствах.
Для желающих обратиться к оригиналу моего выступления вот видео:
и слайды презентации: speakerdeck.com/paullewis/framework-here-its-the-bestestest.
В начале года я писал о зависимости производительности фреймворка React от увеличения размера дерева, которым он оперирует (TL;DR: чем оно крупнее, тем больше задействуется вычислительных мощностей). Я получил немало откликов на эту публикацию, варьирующихся в очень широком диапазоне — от признательных и конструктивных до ярко негативных. Благодаря этой обратной связи я собрал дополнительные сведения, которые в большей или меньшей степени можно отнести ко всем фреймворкам:
Причём важнейшим фактором оказалось удобство использования — явно или неявно его отметило большинство разработчиков. Это собирательное мнение можно сформулировать так: «Если мне будет проще жить, я смогу сделать для пользователей кое-что получше». Вроде бы звучит неплохо. Но, как мне кажется, при такой позиции из виду упускается много важных моментов.
Нельзя забывать, что у пользователей есть свои нужды. В частности, такие:
Возникает неувязка: с одной стороны — удобство и комфорт разработчиков, с другой — пользовательские нужды. А поскольку фреймворки не бесплатны в плане использования ресурсов, то всё это необходимо как-то увязать друг с другом, нравится нам это или нет.
Здесь я предлагаю исключить из рассмотрения отдельные библиотеки. Ведь если с ними возникают какие-то проблемы, то их можно заменить другими. Не нравится, как библиотека задаёт формат даты? Просто подключи ещё какую-нибудь. А вот сменить фреймворк не так просто. Зачастую это требует пересборки всего приложения. К тому же фреймворки занимают куда больше места и вовлечены в приложения гораздо шире и глубже.
У каждой разработки есть своя «цена». Но я считаю, что каждый фреймворк вносит свой уникальный вклад в общую «стоимость».
Тот волшебный момент, когда фреймворк сообщает тебе о чём-то нерекомендуемом (недопустимом). Вероятно, сообщение выдала Java. Странно.
Пользователи тоже «платят» свою цену:
Учитывая всё сказанное, я предлагаю обсудить измерение некоторых из этих стоимостей. Возможно, общими усилиями нам удастся придумать, как лучше всего достигнуть компромисса по выбранным моментам. Начну со времени начальной загрузки фреймворков на смартфонах. Для тестирования я выбрал TodoMVC. Для меня это MVP веб-приложение, а с точки зрения пользователя все варианты функциональности получаются идентичными.
Я измерял следующие параметры: время, полосу пропускания и использование ЦПУ. Тесты проводились на Nexus 5 и iPhone 5S.
Я решил измерить, сколько времени уходит у каждого фреймворка:
Стоимость применения стилей, макетов, заливки и прочего я игнорировал, поскольку она не должна сильно меняться в разных реализациях TodoMVC. Также я не измерял продолжительность передачи данных.
Для загрузки страниц на Nexus 5 я применял WebPagetest. Для каждого прогона создавался таймлайн-файл, который затем обрабатывался в Big Rig. Результаты с iPhone я снял и обработал самостоятельно, поскольку профилирование JavaScript в Safari, судя по всему, не поддерживает экспорт трассировок и таймлайнов.
Использование Big Rig
Между прочим, поэтому я и создал Big Rig — хотелось облегчить всем нам обработку данных подобного рода.
Если вы хотите протестировать самостоятельно, например на устройстве с запущенным Chrome, то следуйте этому алгоритму:
Вот пример того, как это делаю я:
Мною получены такие данные:
Примечания:
С моей точки зрения, выводы однозначны: на мобильных устройствах использование фреймворков сопряжено с серьёзным ростом нагрузки, особенно в сравнении с написанием обычного JavaScript. Наилучшие результаты показал Polymer 1.2.2, но даже он оказался в три раза медленнее «ванильки». React по скорости сравним с Polymer, но у меня есть вопросы относительно его масштабируемости.
Чтобы уж совсем прояснить ситуацию, отмечу:
Вероятно, какие-то моменты проведённого тестирования могут вызвать возражения, на которые необходимо дать ответ:
И неизбежно возникает вопрос: а нужно ли использовать фреймворк? Я не могу дать на него ответ. Это должно быть целиком ваше собственное решение. Существует миллион причин, почему вам позарез нужен фреймворк. Вот мои собственные мысли по этому поводу:
Да, фреймворки предлагают разработчику немалый комфорт. Но я не могу отделаться от мысли, что лучше вложиться в собственные знания и навыки в рамках самой веб-платформы. Фреймворки приходят и уходят, они словно приливы и отливы интернета, помогающие реализовать и отточить идеи и шаблоны. Но если вы однажды обнаружите, что ваш любимый фреймворк больше не работает или какой-то важный баг так и не пофиксили, то способность разобраться в устройстве платформы окажет вам неоценимую услугу.
Я как-то писал, что комфорт разработчика менее важен, чем нужды пользователей. Я всё ещё верю в это. Хоть меня тоже привлекает лёгкая жизнь, я не хочу создавать плохо работающие продукты. И не хочу, чтобы пользователи платили за них высокую «цену». Сейчас меня волнует скорость начальной загрузки фреймворков на мобильных устройствах. Но это лишь первый шаг. Есть и другие метрики: использование памяти, длительная нагрузка на ЦПУ, частота смены кадров. В целом нам нужно искать менее затратные для пользователей решения.
Если нам удастся реализовать быстро загружаемые фреймворки, потребляющие мало памяти и работающие с большим фреймрейтом, да ещё и обеспечивающие комфортность разработки, то это было бы идеально. Но до той поры я бы предпочёл использовать обходиться без фреймворков, по крайней мере в мобильном сегменте.
Для желающих обратиться к оригиналу моего выступления вот видео:
и слайды презентации: speakerdeck.com/paullewis/framework-here-its-the-bestestest.
Преимущества фреймворков
В начале года я писал о зависимости производительности фреймворка React от увеличения размера дерева, которым он оперирует (TL;DR: чем оно крупнее, тем больше задействуется вычислительных мощностей). Я получил немало откликов на эту публикацию, варьирующихся в очень широком диапазоне — от признательных и конструктивных до ярко негативных. Благодаря этой обратной связи я собрал дополнительные сведения, которые в большей или меньшей степени можно отнести ко всем фреймворкам:
- Фреймворки приятны и удобны в использовании. Я не знаю ни одного разработчика, который искал бы пути потруднее и поскучнее. Да, эргономика и комфорт однозначно важны.
- Фреймворки позволяют быстрее создавать MVP. Это особенно важно для небольших, малоопытных компаний и организаций. Быстрый старт может сыграть определяющую роль в успехе продукта.
- Фреймворки помогают обходить особенности и баги платформы. Сегодня это уже не столь актуально, поскольку в последние годы браузеры стали куда больше соответствовать стандартам. Но вспомните, какая это была боль во времена IE5 и 6, а также ранних версий Firefox, Safari и Chrome.
- Если я знаю [вставьте название фреймворка], значит, мне за это будут платить. Ваше владение новинками и лучшими фреймворками может сыграть большую роль при поиске работы.
Причём важнейшим фактором оказалось удобство использования — явно или неявно его отметило большинство разработчиков. Это собирательное мнение можно сформулировать так: «Если мне будет проще жить, я смогу сделать для пользователей кое-что получше». Вроде бы звучит неплохо. Но, как мне кажется, при такой позиции из виду упускается много важных моментов.
Комфорт разработчика и нужды пользователя
Нельзя забывать, что у пользователей есть свои нужды. В частности, такие:
- Сайты и приложения должны загружаться быстро.
- Их интерфейсы должны работать плавно.
- Они не должны быть слишком «тяжёлыми» для телефона.
- Они не должны «ломаться».
- В них должен быть необходимый набор функций.
Возникает неувязка: с одной стороны — удобство и комфорт разработчиков, с другой — пользовательские нужды. А поскольку фреймворки не бесплатны в плане использования ресурсов, то всё это необходимо как-то увязать друг с другом, нравится нам это или нет.
Небольшое отступление
Здесь я предлагаю исключить из рассмотрения отдельные библиотеки. Ведь если с ними возникают какие-то проблемы, то их можно заменить другими. Не нравится, как библиотека задаёт формат даты? Просто подключи ещё какую-нибудь. А вот сменить фреймворк не так просто. Зачастую это требует пересборки всего приложения. К тому же фреймворки занимают куда больше места и вовлечены в приложения гораздо шире и глубже.
«Стоимость» кода
У каждой разработки есть своя «цена». Но я считаю, что каждый фреймворк вносит свой уникальный вклад в общую «стоимость».
Тот волшебный момент, когда фреймворк сообщает тебе о чём-то нерекомендуемом (недопустимом). Вероятно, сообщение выдала Java. Странно.
- Изучение. Вам приходится тратить время на изучение фреймворка: как писать под него «идиоматический» код, какие здесь используются шаблоны, практики и способы выполнения разных операций. Никакой разницы по сравнению с самой веб-платформой. Там тоже нельзя просто взять и начать использовать, приходится решать одну проблему за другой.
- Снова изучать. Однажды в ходе разработки вы увидите в консоли предупреждение о чём-то недопустимом, какой-то устаревшей операции и предложение обновить код. В таких случаях обычно приходится вычислять, что же в ваших действиях не понравилось новой версии фреймворка. И это может повлечь за собой обновление проектов, выпущенных со старыми версиями.
- Отладка. Как и любое ПО, фреймворки содержат баги. К этому нужно быть готовым, даже если вы напишете собственный вариант. А сложность отладки фреймворка обычно попадает в диапазон от «трудно» до «невозможно». Обнаружив какую-то проблему, вы можете попытаться сваять патч своими руками, пока баг не будет официально пофиксен в очередной версии фреймворка.
Пользователи тоже «платят» свою цену:
- Время. Сколько времени займёт загрузка того, что переслали по проводам?
- Полоса пропускания. Какая ширина канала нужна для работы?
- Ресурсы процессора (аккумулятора). Насколько интенсивно используется процессор? Коррелируют ли друг с другом потребление вычислительных ресурсов и заряда аккумулятора?
- Частота кадров. Как часто обновляется экран (ведь пользователям нравится плавность работы интерфейса)?
- Память. Сколько памяти потребляет ваш продукт? Приходится ли выгружать из памяти другие приложения? Может быть, даже ценой их падения?
Данные на стол
Учитывая всё сказанное, я предлагаю обсудить измерение некоторых из этих стоимостей. Возможно, общими усилиями нам удастся придумать, как лучше всего достигнуть компромисса по выбранным моментам. Начну со времени начальной загрузки фреймворков на смартфонах. Для тестирования я выбрал TodoMVC. Для меня это MVP веб-приложение, а с точки зрения пользователя все варианты функциональности получаются идентичными.
Начальная загрузка
Я измерял следующие параметры: время, полосу пропускания и использование ЦПУ. Тесты проводились на Nexus 5 и iPhone 5S.
Я решил измерить, сколько времени уходит у каждого фреймворка:
- на оценку и исполнение полезной JavaScript-нагрузки,
- обработку и помещение в модель первичного набора данных.
Стоимость применения стилей, макетов, заливки и прочего я игнорировал, поскольку она не должна сильно меняться в разных реализациях TodoMVC. Также я не измерял продолжительность передачи данных.
Методология
Для загрузки страниц на Nexus 5 я применял WebPagetest. Для каждого прогона создавался таймлайн-файл, который затем обрабатывался в Big Rig. Результаты с iPhone я снял и обработал самостоятельно, поскольку профилирование JavaScript в Safari, судя по всему, не поддерживает экспорт трассировок и таймлайнов.
Использование Big Rig
Между прочим, поэтому я и создал Big Rig — хотелось облегчить всем нам обработку данных подобного рода.
Воспроизведение теста
Если вы хотите протестировать самостоятельно, например на устройстве с запущенным Chrome, то следуйте этому алгоритму:
- Установите Big Rig CLI: npm install -g bigrig.
- Зайдите на WebPagetest.
- В качестве своего местоположения выберите Даллес (Dulles).
- В качестве браузера выберите Nexus 5 — Chrome (или Beta/Dev).
- На закладке с настройками Chrome поставьте галочку «Capture Dev Tools Timeline».
- Запустите тест.
- Загрузите таймлайн-файл слева от результатов.
- Запустите bigrig --file /path/to/timeline.json --pretty-print.
Вот пример того, как это делаю я:
Результаты
Мною получены такие данные:
Фреймворк | Размер | Время начальной загрузки Nexus 51, 3 | Время начальной загрузки iPhone 5S2, 3 |
---|---|---|---|
Polymer v1.1.4 | 41 Кб5 | 409 мс | 233 мс |
Polymer v1.2.2 | 47 Кб5 | 155 мс | 232 мс |
AngularJS v1.4.3 | 324 Кб | 518 мс | 307 мс |
React v0.13.3 [JSX не преобразован] | 311 Кб | 1,201 мс | 1,463 мс |
React v0.13.3 [JSX преобразован с помощью Babel]4 | 162 Кб | 509 мс | 282 мс |
React v0.13.3 [JSX преобразован; production-сборка]4, 6 | 160 Кб | 174 мс | 118 мс |
Backbone v1.2.2 [включая jQuery и Underscore] | 139 Кб | 248 мс | 168 мс |
Ember v1.10.0-beta.3 | 580 Кб | 1,992 мс | 1,440 мс |
Vanilla | 16 Кб | 50 мс | 33 мс |
Примечания:
- Тесты выполнены на Nexus 5 с запущенным Chrome 47.
- Тесты выполнены на iPhone 5S с запущенным Safari 9.
- Начальная загрузка включает в себя обработку данных первичного списка задач.
- Вырезана JSX Transformer. JSX-файлы преобразованы с помощью Babel.
- За исключением Web Components Polyfill (12 Кб).
- Использована минифицированная production-сборка React.
С моей точки зрения, выводы однозначны: на мобильных устройствах использование фреймворков сопряжено с серьёзным ростом нагрузки, особенно в сравнении с написанием обычного JavaScript. Наилучшие результаты показал Polymer 1.2.2, но даже он оказался в три раза медленнее «ванильки». React по скорости сравним с Polymer, но у меня есть вопросы относительно его масштабируемости.
Чтобы уж совсем прояснить ситуацию, отмечу:
- В случае с React я самостоятельно преобразовывал JSX, поскольку TodoMVC этого не делает. Вместо этого в него включена библиотека JSX Transformer. Чтобы выполнение этой библиотеки не влияло на результат, я её выпилил и протестировал получившуюся «кастомную» версию. К сожалению, в этом случае я использовал не минифицированную версию React, поэтому пришлось тестировать третий вариант.
- Представленные в таблице результаты не включают в себя продолжительность передачи данных. Я измерял только время начальной загрузки фреймворка в JavaScript, вплоть до финальной отрисовки интерфейса. Обратите внимание, что некоторые фреймворки в TodoMVC не минифицированы. Если у вас есть желание, можете изучить дискуссию относительно объёмов передачи данных на сайте Filament Group.
Возможные возражения
Вероятно, какие-то моменты проведённого тестирования могут вызвать возражения, на которые необходимо дать ответ:
- «TodoMVC не идиоматичен». Я проверял это утверждение. Насколько я понимаю, каждая реализация является идиоматичной. А когда это не так, фреймворк анализирует необходимые вычислительные ресурсы для каждого файла.
- «TodoMVC не отражает мои сценарий». Возможно. Но готов поспорить, что в вашем случае «стоимость» ещё выше, чем у TodoMVC. Пол Айриш не так давно исследовал производительность мобильной версии сайта Reddit и обнаружил, помимо прочего, что на мобильных устройствах загрузка компонентов React занимает 22 секунды!
- «У наших пользователей нет Nexus 5 / iPhone 5S». Это тоже вполне реально. У меня была возможность провести тесты на хороших устройствах, и я могу себе представить, что многие пользователи не обладают дорогими и мощными смартфонами. Так что в действительности ситуация со временем загрузки ещё хуже.
- «В следующей версии <вставьте название фреймворка> ситуация будет лучше». Допускаю. Но это вряд ли поможет тем, кто уже пользуется вашими продуктами на предыдущих версиях фреймворка.
Вопрос на $64 000
И неизбежно возникает вопрос: а нужно ли использовать фреймворк? Я не могу дать на него ответ. Это должно быть целиком ваше собственное решение. Существует миллион причин, почему вам позарез нужен фреймворк. Вот мои собственные мысли по этому поводу:
- Фреймворки облегчают реализацию идей и концепций. Именно благодаря им можно понять, какие подходы работают, а какие — нет. Это стимулирует процесс улучшения программных продуктов на уровне платформы. С этой точки зрения фреймворки представляются мне некими тестовыми площадками, на которых можно испытывать будущие нововведения в рамках платформ. С их помощью можно понять, какие возможности обретёт мобильный веб ближайшего будущего.
- Фреймворки являются инверсией контроля. Выше я исключил из рассмотрения библиотеки, потому что их можно легко переключать. Фреймворки же контролируют жизненный цикл приложения, дают вам точку входа для начала работы вашего кода. Да, вы отвечаете за сам код, но вы не контролируете ситуацию целиком.
- Фреймворки дороги при использовании на мобильных устройствах. По крайней мере, по сравнению с базовыми языками. И с моей точки зрения — недопустимо дороги. Но у каждого своё представление о границах допустимости.
Да, фреймворки предлагают разработчику немалый комфорт. Но я не могу отделаться от мысли, что лучше вложиться в собственные знания и навыки в рамках самой веб-платформы. Фреймворки приходят и уходят, они словно приливы и отливы интернета, помогающие реализовать и отточить идеи и шаблоны. Но если вы однажды обнаружите, что ваш любимый фреймворк больше не работает или какой-то важный баг так и не пофиксили, то способность разобраться в устройстве платформы окажет вам неоценимую услугу.
В сухом остатке
Я как-то писал, что комфорт разработчика менее важен, чем нужды пользователей. Я всё ещё верю в это. Хоть меня тоже привлекает лёгкая жизнь, я не хочу создавать плохо работающие продукты. И не хочу, чтобы пользователи платили за них высокую «цену». Сейчас меня волнует скорость начальной загрузки фреймворков на мобильных устройствах. Но это лишь первый шаг. Есть и другие метрики: использование памяти, длительная нагрузка на ЦПУ, частота смены кадров. В целом нам нужно искать менее затратные для пользователей решения.
Если нам удастся реализовать быстро загружаемые фреймворки, потребляющие мало памяти и работающие с большим фреймрейтом, да ещё и обеспечивающие комфортность разработки, то это было бы идеально. Но до той поры я бы предпочёл использовать обходиться без фреймворков, по крайней мере в мобильном сегменте.