Некоторое время назад вышел первый релиз ветки 5.x, а потом несколько меньших патч-версий, так что опять есть чего рассказать.
Предыдущие изменения: часть 1, часть 2, часть 3, часть 4.
Комментарии под предыдущей статьей и в чатиках были весьма полезными, отдельное спасибо fesor, который хоть и не согласен, но предоставляет конструктивную критику, которая имеет позитивные последствия.
Множество изменений сделали систему быстрее, легче и удобнее чем когда-либо до этого. В статье кратко об основных изменениях, их причинах и последствиях.
Прощай jQuery
В версиях 4.x jQuery сначала была объявлена устаревшей, позже в 5.x она была полностью выпилена из фреймворка.
Множество рутинных операций с использованием Polymer становятся декларативными и тянуть jQuery ради небольшого количества методов не хотелось.
Ещё jQuery активно использовалась для XHR запросов, но с широкой поддержкой XHR2 исчезла необходимость писать несколько реализаций, и была написана функция cs.api(), которая:
- обеспечивает 95% потребностей с гораздо более удобным синтаксисом
- поддерживает отправку форм и файлов
- интерфейс базируется на ES2015 Promise
- поддерживает обработку ошибок с выводом пользователю красивых всплывающих сообщений
Некоторые модули использовали jQuery плагины, они теперь используют NPM версию jQuery.
Так же один из jQuery плагинов что использовался в ядре был отрефакторен без использования jQuery, патч принят upstream, так что фреймворк включает чистую оригинальную версию: github.com/voidberg/html5sortable/pull/204
Больше нет плагинов и шаблонов блоков
Раньше отдельно были модули и плагины. Плагины были похожи на модули, но без собственных страниц, админок, настроек, API и прочего.
В связи с тем, что наличие второго типа компонентов, который фактически является подвидом первого, усложняло поддержку, было решено упразднить его, все плагины были конвертированы в модули.
Так же components/blocks
и components/modules
впоследствии перенеслись в blocks
и modules
по аналогии с themes
.
Шаблоны блоков были достаточно кривой штукой изначально и по факту были слишком привязаны к конкретному проекту. Если добавить к этому невозможность установки блоков из пакетов — польза и вовсе сводилась к нулю.
Поэтому шаблоны блоков тоже были выпилены, теперь блоки сами беспокоятся о собственном внешнем виде.
Консистентность интерфейсов
Вместе с чисткой второстепенных фич было проведено много работы по консистентности внутреннего API фреймворка.
К примеру, csCRUD
при работе с разными движками БД теперь приводит числовые типы к одному виду (MySQL даже для числовых столбцов возвращал строки, а SQLite возвращал числа).
Ещё один пример — удаление поддержки вызовов csDB::instance()->$db_id
и csDB::instance()->$db_id()
вместо csDB::instance()->db($db_id)
и csDB::instance()->db_prime($db_id)
. Когда-то давно это использовалось, но это не очень удобно и усложняет вывод типов для IDE.
Множество подобных мелочей было исправлено и приведено к общему виду.
Тестирование
Тестированию в последних версиях было уделено гораздо больше времени чем разработке новых фич, также было добавлено вычисление покрытие кода фреймворка тестами.
В результате общее покрытие фреймворка тестами 66%+ на момент написания статьи, в покрытие системных классов 96%+ (папка modules
практически полностью состоит из контроллеров, поэтому приоритет ниже):
Так же учет покрытия кода позволил найти участки, которые раньше не тестировались, а так же ряд мелких багов, которые было бы сложно найти другим способом.
Фронтенд ещё легче, опциональное отключение поддержки веб-компонентов
Поскольку не все ещё прониклись веб-компонентами, может показаться слишком дорогим грузить Polymer, полифиллы и HTML импорты если они не будут использоваться. Именно для этих случаев в последнем релизе поддержка веб-компонентов стала отключаемой для продвинутых пользователей в админке.
Второе важное улучшение — переход на асинхронные интерфейсы работы с переводами на фронтенде.
Раньше было так:
cs.Language.system_profile_hello('Username')
// или
cs.Language('system_profile_').hello('Username')
Теперь же нужно подождать:
cs.Language.ready().then(function (L) {
L.system_profile_hello('Username');
});
// или
cs.Language('system_profile_').ready().then(function (L) {
L.hello('Username');
});
На самом деле под капотом до 6.x оно всё ещё синхронно, но в итоге переводы будут загружаться только когда нужны.
Все эти изменения позволят уменьшить объем обязательно загружаемого JS кода с 312 КиБ до меньше чем 30 КиБ (это всё без учета gzip), а объем HTML импортов из 107 КиБ до 0 КиБ (0 файлов).
По сути, будет загружаться Alameda (RequireJS) и несколько вспомогательных системных функций/объектов.
Производительность серверной части
Очередная порция изменений привела к ещё большей скорости работы (хотя низко висящих фруктов уже нет).
Особенно полезным является оптимизация API запросов. Существенными (относительно) накладными расходами обладала работа с переводами, большой JSON занимал как время на парсинг, так и память. Теперь же во время API запроса, не работающего с многоязычностью, переводы вообще не будут загружены в память.
Для сравнения с конкурентами был сделан форк популярного бенчмарка с кучей разных фреймворков, так что результаты можете воспроизвести сами:
В текстовом виде:
|framework |requests per second|relative|peak memory|relative| |-------------------|------------------:|-------:|----------:|-------:| |silex-1.3 | 3,029.75| 8.8| 0.59| 1.0| |symfony-2.7 | 1,423.83| 4.2| 1.41| 2.4| |symfony-3.0 | 995.79| 2.9| 1.64| 2.8| |laravel-5.2 | 342.99| 1.0| 1.98| 3.4| |zf-2.5 | 671.20| 2.0| 1.36| 2.3| |cleverstyle-5.15 | 1,939.17| 5.7| 0.66| 1.1|
Так же выросла пиковая производительность под встроенным Http сервером вместе с отличной масштабируемостью (HHVM, 16 процессов, Core i7 4900MQ):
nazar-pc@nazar-pc /w/t/www> ab -c500 -n100000 -k http://test.com:9990/api/System/blank
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking test.com (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requests
Server Software: nginx/1.10.1
Server Hostname: test.com
Server Port: 9990
Document Path: /api/System/blank
Document Length: 4 bytes
Concurrency Level: 500
Time taken for tests: 9.375 seconds
Complete requests: 100000
Failed requests: 0
Keep-Alive requests: 0
Total transferred: 24400000 bytes
HTML transferred: 400000 bytes
Requests per second: 10666.64 [#/sec] (mean)
Time per request: 46.875 [ms] (mean)
Time per request: 0.094 [ms] (mean, across all concurrent requests)
Transfer rate: 2541.66 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 8 69.2 1 1013
Processing: 0 39 30.9 31 272
Waiting: 0 37 30.5 29 272
Total: 0 47 75.3 35 1199
Percentage of the requests served within a certain time (ms)
50% 35
66% 48
75% 57
80% 63
90% 83
95% 104
98% 137
99% 166
100% 1199 (longest request)
А в однопоточном режиме запросы отрабатывают начиная с 0.6 мс (0.0006 секунд), что очень достойный результат, хотя и хотелось бы забраться под 0.5 миллисекунды.
Напоследок
Как обычно, буду благодарен за конструктивные комментарии.
Репозиторий на GitHub: github.com/nazar-pc/CleverStyle-Framework
Автор: nazarpc