Недостатки Preact
Большая часть особенностей описана в документации.
От себя добавлю:
- проблемы с типами при использовании реакт кода / либ, в основном из-за отсутствия синтетической системы событий (привет порталы) и плохой типизации DOM впринципе (проще всего сразу использовать реактовские типы, благо так можно, JSX и там и там).
- экосистема никакая. Хотя недавно появился Fesh, (Deno full stack modern web framework), не пробовал.
- это отдельная либа с отдельными багами, стоит это понимать и быть к этому готовым.
- девтулзы отдельные, немного отличаются, что-то лучше, что-то хуже.
- некоторые операции могут быть медленнее чем в реакте. Некоторые быстрее. В среднем по больнице (это намек) одинаково. Хотя ОЗУ должно потреблять заметно (десятки процентов) меньше, это плюс.
В целом хорошо для лендосов / обособленных виджетов, где можно обойтись чистым преактом и весь код приложения меньше чем ~два бандла реакта. Если пишешь код и тянешь preact/compat это уже звоночек что преакт мб и не нужен. Но для реактовода выбор между свелтом и преактом должен быть очевиден.
Из прикольного, есть глобал хуки, возможность на клиенте процессить html, ленивая гидрация. Самое главное - сигналы, они радикально упрощают и уменьшают код и улучшают перф.
Большая часть особенностей описана в документации.
От себя добавлю:
- проблемы с типами при использовании реакт кода / либ, в основном из-за отсутствия синтетической системы событий (привет порталы) и плохой типизации DOM впринципе (проще всего сразу использовать реактовские типы, благо так можно, JSX и там и там).
- экосистема никакая. Хотя недавно появился Fesh, (Deno full stack modern web framework), не пробовал.
- это отдельная либа с отдельными багами, стоит это понимать и быть к этому готовым.
- девтулзы отдельные, немного отличаются, что-то лучше, что-то хуже.
- некоторые операции могут быть медленнее чем в реакте. Некоторые быстрее. В среднем по больнице (это намек) одинаково. Хотя ОЗУ должно потреблять заметно (десятки процентов) меньше, это плюс.
В целом хорошо для лендосов / обособленных виджетов, где можно обойтись чистым преактом и весь код приложения меньше чем ~два бандла реакта. Если пишешь код и тянешь preact/compat это уже звоночек что преакт мб и не нужен. Но для реактовода выбор между свелтом и преактом должен быть очевиден.
Из прикольного, есть глобал хуки, возможность на клиенте процессить html, ленивая гидрация. Самое главное - сигналы, они радикально упрощают и уменьшают код и улучшают перф.
Организация redux кода
- папки в репо должны называться по доменному / сервисному смыслу, описывая что за задачу решает код в них, а не по используемой там библиотеке. Чаще всего папка redux должна назваться model / logic / service.
- есть разные подходы к разделению многословного кода для редакса: утки и фичаслайсы, много подробностей в официальной документации. Конечно, такие вещи зависят от решаемых приложением в общем и редаксом в частности задач, но в подавляющем большинстве случаев деление по фичам проще и эффективнее всего. При этом ко всем паттернам найдутся вопросы с неоднозначными ответами и совершенно идеальной структуры нет и быть не может.
- лично я стараюсь придерживаться model trash подхода, который предполагает описание всей логики приложения (иногда, и части view model) в одном огромном файле (до 2к строк). Это самый простой подход, в котором не так уж и просто написать кашу при использовании flux архитектуры (в описываемых сущностях мало циклов). С таким подходом очень просто стартовать, плавно, со временем, рефакторя устоявшиеся участки кода.
- как рефакторить код на редаксе, набор простых советов. Все селекторы должны объявляться как отдельные именованные функции и лежать рядом с соответствующем редьюсером или местом использования (саги \ санки). Бойлерплейт редакса просто решается фабриками. Можно делать фабрики фабрик. Фабрика фабрики фабрики уже попахивает, скорее всего нужно выделить реиспользуемый модуль \ сервис \ пакет. Используйте Code Splitting. Используйте Reatom :)
- папки в репо должны называться по доменному / сервисному смыслу, описывая что за задачу решает код в них, а не по используемой там библиотеке. Чаще всего папка redux должна назваться model / logic / service.
- есть разные подходы к разделению многословного кода для редакса: утки и фичаслайсы, много подробностей в официальной документации. Конечно, такие вещи зависят от решаемых приложением в общем и редаксом в частности задач, но в подавляющем большинстве случаев деление по фичам проще и эффективнее всего. При этом ко всем паттернам найдутся вопросы с неоднозначными ответами и совершенно идеальной структуры нет и быть не может.
- лично я стараюсь придерживаться model trash подхода, который предполагает описание всей логики приложения (иногда, и части view model) в одном огромном файле (до 2к строк). Это самый простой подход, в котором не так уж и просто написать кашу при использовании flux архитектуры (в описываемых сущностях мало циклов). С таким подходом очень просто стартовать, плавно, со временем, рефакторя устоявшиеся участки кода.
- как рефакторить код на редаксе, набор простых советов. Все селекторы должны объявляться как отдельные именованные функции и лежать рядом с соответствующем редьюсером или местом использования (саги \ санки). Бойлерплейт редакса просто решается фабриками. Можно делать фабрики фабрик. Фабрика фабрики фабрики уже попахивает, скорее всего нужно выделить реиспользуемый модуль \ сервис \ пакет. Используйте Code Splitting. Используйте Reatom :)
Оценка производительности библиотек
Телеграм не хочет все вмещать в одно сообщение, поэтому вот вам сслыка.
Я наверняка не описал еще несколько важных пунктов, но общая картина у вас, я надеюсь, сложилась. Невозможно, написать абсолютно верный с формальной точки зрения перф тест. Вы можете приблизиться к этому потратив несоразмерно много сил и времени, но зачем? Напомню, что подобные тесты нужны для помощи в какой-то общей аналитики курса(!) кодовой базы: все драматически медленно или норм. Какие-то уточнения и погони за десятками, а не сотнями, процентов - уже узлишки для продуктиности и относяться скорее к хобби или уталению собственного эго, хотя бывают и какие-то специфические случаи для крупных заказчиков.
Конечно, лучше всего мерить производительность кода на реальных задачах (вы ждали этой фразы?), но когда библиотке решает наишироченный спектр задач, как стейт менеджер, невозможно сделать релевантный сразу для всех тест, даже несколько тестов.
Я, в итоге, выбрал следующие условия измерения: несколько запусков с разным количеством итераций, разбивка каждой итерации итерациями других тестов, медианное значение, средняя (из головы) сложность тестируемого кода и сложение интеджеров как юзерленд код.
Телеграм не хочет все вмещать в одно сообщение, поэтому вот вам сслыка.
Я наверняка не описал еще несколько важных пунктов, но общая картина у вас, я надеюсь, сложилась. Невозможно, написать абсолютно верный с формальной точки зрения перф тест. Вы можете приблизиться к этому потратив несоразмерно много сил и времени, но зачем? Напомню, что подобные тесты нужны для помощи в какой-то общей аналитики курса(!) кодовой базы: все драматически медленно или норм. Какие-то уточнения и погони за десятками, а не сотнями, процентов - уже узлишки для продуктиности и относяться скорее к хобби или уталению собственного эго, хотя бывают и какие-то специфические случаи для крупных заказчиков.
Конечно, лучше всего мерить производительность кода на реальных задачах (вы ждали этой фразы?), но когда библиотке решает наишироченный спектр задач, как стейт менеджер, невозможно сделать релевантный сразу для всех тест, даже несколько тестов.
Я, в итоге, выбрал следующие условия измерения: несколько запусков с разным количеством итераций, разбивка каждой итерации итерациями других тестов, медианное значение, средняя (из головы) сложность тестируемого кода и сложение интеджеров как юзерленд код.
Telegraph
Оценка производительности библиотек.
У всех, и у меня в том числе, пригорает от перформанс тестов и выводов, которые делаются на их основе. В недавнем посте и треду к нему идут рассуждения о том, как правильно и неправильно делать оценку производительности. В нем я немного расписываю мотивацию…
Про контроль легаси
Неделю назад занимался задачей обновления зависимостей в сервисе, который не обновляли уже около полугода.
Мы используем 8 нпм и он не умеет сам исправлять (форсить одну) версии конфликтных тредисятых зависимостей. Раньше для этого мы использовали пакет npm-force-resolutions, но он не обновлялся уже 10 месяцев, а значит ничего не знает о том что в 8 нпм используется новая версия лок файла
По какой-то причине, при установке зависимостей даже с исправленным лок файлом нпм в одной из верхнеуровневых зависимостей создавал
Поэтому я быстренько написал скрипт на ноде, который удаляет папку с третьесторонней зависимостей с не верной версией в нод модулях основной зависимости. Проблема решилась, все работает, но… Я решил перестраховаться и подумал что мог бы сделать, что бы этот скрипт не забылся или не стал делать лишнего, когда версия проблемной зависимости обновиться.
В итоге, дополнил скрипт таким кодом:
А рассказываю я все это, потому что сегодня как раз нужно было обновить версию graphql, но про ранее написанный скрипт я уже успел забыть. Но он выстрелел ошибкой и меня это очень порадовало 🙂
Мораль не нова: думайте о том что бы код было легко удалить и было понятно когда это нужно сделать.
Неделю назад занимался задачей обновления зависимостей в сервисе, который не обновляли уже около полугода.
Мы используем 8 нпм и он не умеет сам исправлять (форсить одну) версии конфликтных тредисятых зависимостей. Раньше для этого мы использовали пакет npm-force-resolutions, но он не обновлялся уже 10 месяцев, а значит ничего не знает о том что в 8 нпм используется новая версия лок файла
"lockfileVersion": 2 (ишье на эту тему тоже нет). К счастью есть новый пакет force-resolutions, который умеет в новый лок файл и с ним проблем не возникло. Почти.По какой-то причине, при установке зависимостей даже с исправленным лок файлом нпм в одной из верхнеуровневых зависимостей создавал
node_modules и ставил туда не нужную зависимость, версию которой нужно было зафорсить для всего проекта. Из-за этого и в проект загружалось две версии третьестороннего пакета и все ломалось. Я хотел быстро решить проблему, потому что в ближайшем будущем все равно планировался еще один апдейт и была надежда что конфликты уйдут совсем.Поэтому я быстренько написал скрипт на ноде, который удаляет папку с третьесторонней зависимостей с не верной версией в нод модулях основной зависимости. Проблема решилась, все работает, но… Я решил перестраховаться и подумал что мог бы сделать, что бы этот скрипт не забылся или не стал делать лишнего, когда версия проблемной зависимости обновиться.
В итоге, дополнил скрипт таким кодом:
const packageJson = JSON.parse(await fs.readFile('package.json'))
if (packageJson?.resolutions?.graphql !== "14.7.0") {
throw new Error('The fix is outdated, apparently')
}
А рассказываю я все это, потому что сегодня как раз нужно было обновить версию graphql, но про ранее написанный скрипт я уже успел забыть. Но он выстрелел ошибкой и меня это очень порадовало 🙂
Мораль не нова: думайте о том что бы код было легко удалить и было понятно когда это нужно сделать.
👍2
Менеджеры состояний
UfoStation-s01e09
Менеджеры состояний
Гости выпуска:
— Артем Арутюнян: twitter, telegram
— Александр Колесников: twitter
Содержание выпуска:
- 00:03:12 - Состояние и менеджер состояний (SM)
- 00:06:00 - Множество состояний
- 00:10:18 - Зачем SM, если есть встроенные API
- 00:12:28 - Единый интерфейс, единственный API
- 00:20:13 - Принципы, лежащие в основе SM
- 00:27:46 - Почему появляются новые SM
- 00:35:58 - Влияние SM на архитектуру приложения
- 00:42:12 - Как быть непосвященному разработчику
- 00:47:32 - Переход на новый SM в приложении
- 00:51:52 - Стандартизация API
- 00:59:41 - Проблемы больших состояний
- 01:05:18 - Синхронизация c бекэндом
- 01:09:05 - 2 менеджера состояний и 1 состояние
Слушать подкаст на других платформах
Гости выпуска:
— Артем Арутюнян: twitter, telegram
— Александр Колесников: twitter
Содержание выпуска:
- 00:03:12 - Состояние и менеджер состояний (SM)
- 00:06:00 - Множество состояний
- 00:10:18 - Зачем SM, если есть встроенные API
- 00:12:28 - Единый интерфейс, единственный API
- 00:20:13 - Принципы, лежащие в основе SM
- 00:27:46 - Почему появляются новые SM
- 00:35:58 - Влияние SM на архитектуру приложения
- 00:42:12 - Как быть непосвященному разработчику
- 00:47:32 - Переход на новый SM в приложении
- 00:51:52 - Стандартизация API
- 00:59:41 - Проблемы больших состояний
- 01:05:18 - Синхронизация c бекэндом
- 01:09:05 - 2 менеджера состояний и 1 состояние
Слушать подкаст на других платформах
👍1
Forwarded from UfoStation
Материалы к выпуску s01e09:
- Архитектура менеджера состояния
- Ромбовидное наследование
- Ромбовидные зависимости
- ECMAScript proposal for the Record and Tuple value types
- yjs: Shared data types for building collaborative software
- BuilderIO/partytown
- Архитектура менеджера состояния
- Ромбовидное наследование
- Ромбовидные зависимости
- ECMAScript proposal for the Record and Tuple value types
- yjs: Shared data types for building collaborative software
- BuilderIO/partytown
YouTube
02. Артем Арутюнян — Архитектура менеджера состояния
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
Мозговой штурм
В статье описывается методика мозгового штурма и ее проблемы, а также доказывается ее общая неэффективность. Прямых ссылок на исследования не приводится, но я склонен согласиться с описываемыми утверждениями, правда с парой оговорок.
1. Мозговой штурм, как любая метододика, не универсальное средство, и лучше всего его применять при желании получить результат быстро, а не самый качественный.
2. Ключевая сила методики - обработка невероятных вариантов. Смысл не в том что бы перебрать больше вариантов и попробовать найти правильный. Смысл в озвучивании каждым самых безумных теорий, которые помогут другим участникам сассоциировать что-то оригинальное и продуктивное. При таком фокусе проблемы изначального направления и лидера мнений вносят коррективы в наименьшей степени.
Я часто применял эту методику в творческих и инженерных задачах и она мне здорово помогала. Эффективнее всего она работает в тупиковых случаях, а не как точка отчёта.
#soft
В статье описывается методика мозгового штурма и ее проблемы, а также доказывается ее общая неэффективность. Прямых ссылок на исследования не приводится, но я склонен согласиться с описываемыми утверждениями, правда с парой оговорок.
1. Мозговой штурм, как любая метододика, не универсальное средство, и лучше всего его применять при желании получить результат быстро, а не самый качественный.
2. Ключевая сила методики - обработка невероятных вариантов. Смысл не в том что бы перебрать больше вариантов и попробовать найти правильный. Смысл в озвучивании каждым самых безумных теорий, которые помогут другим участникам сассоциировать что-то оригинальное и продуктивное. При таком фокусе проблемы изначального направления и лидера мнений вносят коррективы в наименьшей степени.
Я часто применял эту методику в творческих и инженерных задачах и она мне здорово помогала. Эффективнее всего она работает в тупиковых случаях, а не как точка отчёта.
#soft
Хабр
Мозговой штурм не работает. Почему его до сих пор используют?
Давайте представим себе ситуацию: группе экспертов нужно решить сложную задачу. Она необычная и не решается стандартными способами. Одна из самых распространённых методик поиска решения таких задач —...
usePureCallback
Опубликовал свои мысли и пример кода на счет мемоизации функций в реакте. Пакета нет в НМП, потому что вся реализация занимает чуть больше ста байтов. Без гзипа 🙂
Проблема в том что в реакте нет апи для ленивого чтения данных.
Пример (даю эту задачку на интервью): есть тяжелый компонент таблицы с пропом функцией `
Идея простая: зачем пересоздавать функцию на каждое изменение зависимых данных и ломать этим нижележащую мемоизацию, если можно отделить функцию от зависимостей, сделав ее чистой и получить неизменяемую ссылку.
Проблема в таком подходе в том что данные в мутабельной структуре храняться всегда от последнего рендера, и если рендер будет выброшен ошибкой в нижележащем рендере или данные изменяться параллельным рендером, а функция будет вызвана из старого поддерева с расчетом на старые зависимости, то что-то может пойти не так. Обнадеживает то что такая ситуация не очень часто может встретиться еще и потому что данные в зависимостях не обязательно меняются при новом ререндере, да и нужны нам старые данные не всегда - если старое поддерево будет работать с новыми данными, может оно так и надо.
Конечно, описанные проблемы, при их проявлении, будет очень не приятно дебажить, но на моей практике это какие-то совсем редкие случаи, а профит от постоянных ссылок на функции заметен сильно (у меня с этим постоянно проблемы).
Материалы по теме:
- ссылочная прозрачность
#perf #immutable
Опубликовал свои мысли и пример кода на счет мемоизации функций в реакте. Пакета нет в НМП, потому что вся реализация занимает чуть больше ста байтов. Без гзипа 🙂
Проблема в том что в реакте нет апи для ленивого чтения данных.
Пример (даю эту задачку на интервью): есть тяжелый компонент таблицы с пропом функцией `
getData`, которая дергается по таймауту / инпуту или еще чему. Есть отдельно фильтры, которые нужно учитывать при запросе в getData. Как менять фильтры, что бы не ререндерить таблицу? Идея простая: зачем пересоздавать функцию на каждое изменение зависимых данных и ломать этим нижележащую мемоизацию, если можно отделить функцию от зависимостей, сделав ее чистой и получить неизменяемую ссылку.
Проблема в таком подходе в том что данные в мутабельной структуре храняться всегда от последнего рендера, и если рендер будет выброшен ошибкой в нижележащем рендере или данные изменяться параллельным рендером, а функция будет вызвана из старого поддерева с расчетом на старые зависимости, то что-то может пойти не так. Обнадеживает то что такая ситуация не очень часто может встретиться еще и потому что данные в зависимостях не обязательно меняются при новом ререндере, да и нужны нам старые данные не всегда - если старое поддерево будет работать с новыми данными, может оно так и надо.
Конечно, описанные проблемы, при их проявлении, будет очень не приятно дебажить, но на моей практике это какие-то совсем редкие случаи, а профит от постоянных ссылок на функции заметен сильно (у меня с этим постоянно проблемы).
Материалы по теме:
- ссылочная прозрачность
#perf #immutable
GitHub
GitHub - artalar/usePureCallback: useCallback doing right
useCallback doing right. Contribute to artalar/usePureCallback development by creating an account on GitHub.
👍5
Производительность вам не подконтрольна
Разработчики постоянно переоценивают производительность своего продукта и недооценивают тормознутость пользовательского устройства. Понятно, что средняя машина программиста скорее всего мощнее среднего устройства пользователя, но от незнания количественного соотношения значимость этого факта стремится к нулю. Т.к. продукты и ЦА у всех разные, невозможно вывести какой-то средний и понятный коэффициент, но вы можете попытаться прикинуть его сами на основе следующих пунктов.
Разработчик не имеет задержки в доступах к ресурсам, т.к. большая их часть чаще всего находится на том же localhost. Если же вы используете пару CDN'ок, пару сервисов аналитики ну и собственный домен, то около четверти секунды уйдет только на обращение к DNS и еще больше на handshake. Хотелось бы понадеяться на то что запросы будут обрабатываться параллельно, но у браузеров лимит на это дело (около 6 запросов одновременно), который быстро забивается загрузкой собственных ресурсов.
Кстати, про аналитику, вы же не грузите ее в дев режиме, но сколько требуется клиентскому устройству времени что бы скачать, распарсить и запустить какие-нибудь 100KB GTM? Google Tag Manager vs Page Speed: The Impact and How to Improve.
Некоторые пользователи имеют блокировщики рекламы и аналитики и таким образом за разработчика ускоряют его сайт, но в браузере могут быть установлены и другие расширения, которые на секунды могут увеличивать появление, а в дальнейшем и отзывчивость сайта.
У пользователя могут быть запущены программы кроме браузера или может быть просто большой износ системы (накопленные кеши от долгого аптайма, фрагментированный диск замедляет своп и тп). Естественно, и само устройство может быть малопроизводительным.
Разные браузеры могут иметь различия в реализации разных фич и иметь разницу в их исполнении в десятки раз. Особенно, это касается новых возможностей.
#perf #soft
Разработчики постоянно переоценивают производительность своего продукта и недооценивают тормознутость пользовательского устройства. Понятно, что средняя машина программиста скорее всего мощнее среднего устройства пользователя, но от незнания количественного соотношения значимость этого факта стремится к нулю. Т.к. продукты и ЦА у всех разные, невозможно вывести какой-то средний и понятный коэффициент, но вы можете попытаться прикинуть его сами на основе следующих пунктов.
Разработчик не имеет задержки в доступах к ресурсам, т.к. большая их часть чаще всего находится на том же localhost. Если же вы используете пару CDN'ок, пару сервисов аналитики ну и собственный домен, то около четверти секунды уйдет только на обращение к DNS и еще больше на handshake. Хотелось бы понадеяться на то что запросы будут обрабатываться параллельно, но у браузеров лимит на это дело (около 6 запросов одновременно), который быстро забивается загрузкой собственных ресурсов.
Кстати, про аналитику, вы же не грузите ее в дев режиме, но сколько требуется клиентскому устройству времени что бы скачать, распарсить и запустить какие-нибудь 100KB GTM? Google Tag Manager vs Page Speed: The Impact and How to Improve.
Некоторые пользователи имеют блокировщики рекламы и аналитики и таким образом за разработчика ускоряют его сайт, но в браузере могут быть установлены и другие расширения, которые на секунды могут увеличивать появление, а в дальнейшем и отзывчивость сайта.
У пользователя могут быть запущены программы кроме браузера или может быть просто большой износ системы (накопленные кеши от долгого аптайма, фрагментированный диск замедляет своп и тп). Естественно, и само устройство может быть малопроизводительным.
Разные браузеры могут иметь различия в реализации разных фич и иметь разницу в их исполнении в десятки раз. Особенно, это касается новых возможностей.
#perf #soft
👍6
valueOf
В моем личном списке, “что должен сделать успешный программист за свою карьеру”, есть два пункта: найти уязвимость в чужом ПО и исправить такую уязвимость. Я никогда не надеялся их реализовать т.к. предметная область мне кажется достаточно сложной. Но вчера, совершенно случайно, при регулярном использовании nanoid у меня что-то стрельнуло в голове, и я пошел копать исходники.
Через несколько минут у меня в голове уже созрел план как сломать библиотеку, а через 20 минут был код воспроизведения ошибки, он позволял получить предыдущий сгенерированный идентификатор. Фактически, это воспроизводимые коллизии, что плохо для подобного рода библиотеки, но т.к. условия эксплуатации подразумевают прямой доступ к ссылке инстанс библиотеки, проблема не выглядит серьезной.
Для нетерпеливых вот ПР с кодом воспроизведения проблемы и ее фиксом.
Детали. В вызов генератора идентификатора можно передать число для указания его длины. Чаще всего его не указывают и используется значение по умолчанию -
Проанализировав код библиотеки, я понял, что переданный параметр длинны идентификатора передается по ссылке и в какой-то момент участвует в трех математических операциях с условиями, в которых можно создать логическую ошибку, если значение переменной будет меняться для каждого условия. В ПРе есть наглядный пример реализации.
В итоге, можно было создать такую логическую последовательность работы valueOf, при которой внутреннее состояние библиотеки не менялось бы и генерация идентификатора производилась бы на старом значении, условно говоря, сгенерированным под предыдущий идентификатор.
Интересно было и придумать исправление для этой ошибки. Не хотелось вносить большой оверхед в нано библиотеку, я сам увлекаюсь микрооптимизациями производительности и бандлсайза и для меня это был отдельный челендж. Несколько часов я экспериментировал. Первая реализация добавляла 4 байта, последующая
Библиотека разрешает передавать число строкой в аргумент, поэтому необходимо было использовать именно минус, который конвертирует строку в число, а не плюс, который для строк имеет приоритет как операция конкатенации.
В течении дня я нашел уязвимость, связался с автором, сделал фикс, отрепортил все это в snyk, который завел CVE-2021-23566. Андрей со всем помогал и сразу же зарелизил новую версию 3.1.31, за что ему отдельно спасибо.
В общем, опыт был интересный, наконец удалось получить фан от слабой динамической типизации ЖСа 🙂
#security
В моем личном списке, “что должен сделать успешный программист за свою карьеру”, есть два пункта: найти уязвимость в чужом ПО и исправить такую уязвимость. Я никогда не надеялся их реализовать т.к. предметная область мне кажется достаточно сложной. Но вчера, совершенно случайно, при регулярном использовании nanoid у меня что-то стрельнуло в голове, и я пошел копать исходники.
Через несколько минут у меня в голове уже созрел план как сломать библиотеку, а через 20 минут был код воспроизведения ошибки, он позволял получить предыдущий сгенерированный идентификатор. Фактически, это воспроизводимые коллизии, что плохо для подобного рода библиотеки, но т.к. условия эксплуатации подразумевают прямой доступ к ссылке инстанс библиотеки, проблема не выглядит серьезной.
Для нетерпеливых вот ПР с кодом воспроизведения проблемы и ее фиксом.
Детали. В вызов генератора идентификатора можно передать число для указания его длины. Чаще всего его не указывают и используется значение по умолчанию -
21. Одна из особенностей JS заключается в том что для математических операций над значениями вызывается их метод valueOf, который для Number возвращает само число, но для любых других объектов мы можем его переопределить. И возвращать разные числа по условию!Проанализировав код библиотеки, я понял, что переданный параметр длинны идентификатора передается по ссылке и в какой-то момент участвует в трех математических операциях с условиями, в которых можно создать логическую ошибку, если значение переменной будет меняться для каждого условия. В ПРе есть наглядный пример реализации.
В итоге, можно было создать такую логическую последовательность работы valueOf, при которой внутреннее состояние библиотеки не менялось бы и генерация идентификатора производилась бы на старом значении, условно говоря, сгенерированным под предыдущий идентификатор.
Интересно было и придумать исправление для этой ошибки. Не хотелось вносить большой оверхед в нано библиотеку, я сам увлекаюсь микрооптимизациями производительности и бандлсайза и для меня это был отдельный челендж. Несколько часов я экспериментировал. Первая реализация добавляла 4 байта, последующая
size += size добавляла 2 байта. В итоговой версии я добавил всего 3 символа -=0, а магия минификатора и архиватора смогла нивелировать это до ничего - бандлсайз не изменился!Библиотека разрешает передавать число строкой в аргумент, поэтому необходимо было использовать именно минус, который конвертирует строку в число, а не плюс, который для строк имеет приоритет как операция конкатенации.
В течении дня я нашел уязвимость, связался с автором, сделал фикс, отрепортил все это в snyk, который завел CVE-2021-23566. Андрей со всем помогал и сразу же зарелизил новую версию 3.1.31, за что ему отдельно спасибо.
В общем, опыт был интересный, наконец удалось получить фан от слабой динамической типизации ЖСа 🙂
#security
👍25
Небольшой статус по каналу. Отправляю без нотификации 🙂
(lofi трек, который играл пока я писал этот пост)
За два месяца количество подписчиков увеличилось в четыре раза, если подбирать красивые цифры. Это круто, я это очень ценю, правда. Для меня важен этот канал и каждый подписчик, потому что мне нужно общаться и делиться всем тем хаусом, что происходит в моей голове. Канал помогает структурировать информацию и подводить какой-то итог мыслей - завершать их, хоть на какой-то стадии, переставать о них беспокоиться.
Сейчас комментарии отключены. Их включение точно будет негативно сказываться на моих повседневных обязанностях, буду что-то не успевать. Но мы можем устраивать войсы по следам постов и я буду вносить в них правки или писать новые итоги. Чуть позже.
Если сильно хочется дать / получить доп комментарии - пишите в личку.
Ключевой приоритет для меня - @reatom_ru. Планов очень много, и они даже как-то движутся. За прошедшие полгода накопилось много продуктового фидбека, и я пилю новые крутые фичи. Скоро будут анонсы.
А пока, буду понемногу выкладывать в текстовом виде, в этот канал, расшифровку доклада уже годовалой давности про архитектуру менеджера состояния.
Конечно, будут посты и на другие темы. Не так насыщенно, как на этой неделе 😊 Но мыслей и экспериментов у меня еще много как на работе, так и в петах, так что ждите.
(lofi трек, который играл пока я писал этот пост)
За два месяца количество подписчиков увеличилось в четыре раза, если подбирать красивые цифры. Это круто, я это очень ценю, правда. Для меня важен этот канал и каждый подписчик, потому что мне нужно общаться и делиться всем тем хаусом, что происходит в моей голове. Канал помогает структурировать информацию и подводить какой-то итог мыслей - завершать их, хоть на какой-то стадии, переставать о них беспокоиться.
Сейчас комментарии отключены. Их включение точно будет негативно сказываться на моих повседневных обязанностях, буду что-то не успевать. Но мы можем устраивать войсы по следам постов и я буду вносить в них правки или писать новые итоги. Чуть позже.
Если сильно хочется дать / получить доп комментарии - пишите в личку.
Ключевой приоритет для меня - @reatom_ru. Планов очень много, и они даже как-то движутся. За прошедшие полгода накопилось много продуктового фидбека, и я пилю новые крутые фичи. Скоро будут анонсы.
А пока, буду понемногу выкладывать в текстовом виде, в этот канал, расшифровку доклада уже годовалой давности про архитектуру менеджера состояния.
Конечно, будут посты и на другие темы. Не так насыщенно, как на этой неделе 😊 Но мыслей и экспериментов у меня еще много как на работе, так и в петах, так что ждите.
👍14