Друзья, поздравляю вас с Новым Годом! 🎄
У меня, как всегда, много планов и целей на этот год и очень скоро я сделаю очень важный для меня анонс. И пусть в новом году у всех нас все наши планы реализуются 🚀
У меня, как всегда, много планов и целей на этот год и очень скоро я сделаю очень важный для меня анонс. И пусть в новом году у всех нас все наши планы реализуются 🚀
Привет! Исследую одну, как мне кажется, интересную тему - определение неиспользуемых ветвей в больших объектах. Это может пригодиться, например, для анализа стейта вашего приложения с целью определить какая часть стейта является избыточной для вашего приложения, чтобы не присылать ее на клиент.
Я вижу здесь два варианта реализации: статический анализ и анализ в рантайме.
Хочу узнать что думаете и может встречали какие-то готовые решения ☺️
PS: реализовал свое решение, чуть позже расскажу
Я вижу здесь два варианта реализации: статический анализ и анализ в рантайме.
Хочу узнать что думаете и может встречали какие-то готовые решения ☺️
PS: реализовал свое решение, чуть позже расскажу
Немного подбробнее раскрою тему, которую начал выше.
Понять какие части объекта используются, а какие нет, надажнее всего через рантайм. Статический анализ не всегда помогает:
- код можно написать так, что его довольно сложно будет проанализировать статически
- не поможет в кейсах, когда обращение к свойствам в коде есть, но фактически этот код мертвый и до него дело никогда не доходит (ранее писал большой пост про DCE)
Итого, искать неиспользуемые куски объекта лучше в рантайме. В плане реализации, нужно перехватывать все попытки обратиться к любым свойствам объекта, даже к тем свойствам, которых еще нет. При попытке обратиться к свойству - фиксруем эту попытку и в нужный момент извлекаем инфрмацию о usage coverage (какие ветки используются, а какие нет).
Для этого можно использовать Proxy, что я собственно и сделал и запилил для этих целей библиотечку Gettie.
При помощи Gettie можно обернуть любой объект и следить за попытками доступа с его свойствам (без ограничения глубины).
Почитайте описание, посмотрите демку, попробуйте сами и поделитесь мыслями/идеями ☺️
Смысл демки в том, в у каждой todo в стейте приложения есть два заведемо неиспользуемых поля: createdTS и editedTS
Создавая/редактируя todo-шки, нажимайте на Refresh и смотрите как растет количество неиспользуемых веток в стейте.
Понять какие части объекта используются, а какие нет, надажнее всего через рантайм. Статический анализ не всегда помогает:
- код можно написать так, что его довольно сложно будет проанализировать статически
- не поможет в кейсах, когда обращение к свойствам в коде есть, но фактически этот код мертвый и до него дело никогда не доходит (ранее писал большой пост про DCE)
Итого, искать неиспользуемые куски объекта лучше в рантайме. В плане реализации, нужно перехватывать все попытки обратиться к любым свойствам объекта, даже к тем свойствам, которых еще нет. При попытке обратиться к свойству - фиксруем эту попытку и в нужный момент извлекаем инфрмацию о usage coverage (какие ветки используются, а какие нет).
Для этого можно использовать Proxy, что я собственно и сделал и запилил для этих целей библиотечку Gettie.
При помощи Gettie можно обернуть любой объект и следить за попытками доступа с его свойствам (без ограничения глубины).
Почитайте описание, посмотрите демку, попробуйте сами и поделитесь мыслями/идеями ☺️
Смысл демки в том, в у каждой todo в стейте приложения есть два заведемо неиспользуемых поля: createdTS и editedTS
Создавая/редактируя todo-шки, нажимайте на Refresh и смотрите как растет количество неиспользуемых веток в стейте.
Telegram
Сергей Мелюков
📝 Мои мысли по поводу поиска неиспользуемого кода (dead code) и его устранения (DCE - dead code elimination).
Для начала, давайте определимся в каких ситуациях код может никогда не исполняться:
Что-то пошло не так
function foo() {
console.log(1); //…
Для начала, давайте определимся в каких ситуациях код может никогда не исполняться:
Что-то пошло не так
function foo() {
console.log(1); //…
Статистику можно собирать двумя путями:
1) Оборачивать стейт в рамках А/Б тестирования, например, собрать статистику только с 1% пользователей
Более правдивые результаты. И чем на больший % раскатываем - тем более правдивые результаты получаем.
Минус такого подхода - импакт по производительности клиента из-за постоянных оберток (зависит от размера стейта и частоты обращений к нему)
2) Собирать статистику во время e2e-тестов
Менее правдивые результаты, т.к. e2e-тесты лишь эмулируют поведение пользователя
1) Оборачивать стейт в рамках А/Б тестирования, например, собрать статистику только с 1% пользователей
Более правдивые результаты. И чем на больший % раскатываем - тем более правдивые результаты получаем.
Минус такого подхода - импакт по производительности клиента из-за постоянных оберток (зависит от размера стейта и частоты обращений к нему)
2) Собирать статистику во время e2e-тестов
Менее правдивые результаты, т.к. e2e-тесты лишь эмулируют поведение пользователя
🎉 Замержили мой PR в вебпак, который добавляет возможность очищать содержимое выходной директории перед сборкой:
{ output: { clean: true } }
Эдакая замена WebpackCleanPlugin
{ output: { clean: true } }
Эдакая замена WebpackCleanPlugin
Всем привет! В блоге Яндекса на Хабре я опубликовал свои мысли по поводу типизации и ее применимости к JS
https://habr.com/ru/company/yandex/blog/541338/
Делитесь своими мыслями в комментах, приятного чтения ☺️
https://habr.com/ru/company/yandex/blog/541338/
Делитесь своими мыслями в комментах, приятного чтения ☺️
Хабр
Сага о типизации и тайпчекинге для JavaScript
Привет! Хочу поделиться своими мыслями по, казалось бы, простой теме — типизации. В частности, поговорить о тайпчекинге в JavaScript. Часто люди воспринимают типизацию как эдакую серебряную пулю,...
А еще, я ищу JS-разработчиков, прямо в мою команду инфраструктуры фронта 🚀
Если для вас это актуально, то присылайте резюме в личку ☺️
https://yandex.ru/jobs/vacancies/dev/front_develop_market/
https://yandex.ru/jobs/vacancies/dev/nodejs_market/
Если для вас это актуально, то присылайте резюме в личку ☺️
https://yandex.ru/jobs/vacancies/dev/front_develop_market/
https://yandex.ru/jobs/vacancies/dev/nodejs_market/
Привет! Небольшая заметка о том, как я затаскивал поддержку больших статов в генерируемые Статоскопом HTML-отчеты.
Как мы с вами уже знаем, у JS-движков есть ограничение на максимальный размер строки (например 512мб для V8)
Это значит, что при попытке получить строку большего размера, мы получим ошибку
Очевидно, что для статов размером больше 512mb тот же
Обойти ограничение можно при помощи поточного JSON-парсера. Такому парсеру нужен источник строки, который будет отдавать ее не целиком, а кусочками (например по 64кb). По мере того, как парсер получает кусочки, он пытается их распарсить - превратить в объект. Очевидно, что этот объект растет по мере парсинга. Смысл в том, что мы не обрабатываем большие строки, а следовательно, у нас не возникает исключения
Ну хорошо, делаю первый подход - взял поточный парсер от @rdvornov, формирую HTML и инъекчу в него код вроде такого:
Запускаю - не работает, браузер просто зависает 🤔
Методом проб и ошибок выяснил, что бразуер просто не переваривает такой большой тег скрипт (несколько сот мегабайт). Никакой особо полезной информации я по этому ограничению не нашел, но стало ясно, что теперь я воткнулся в проблему лимитов самого браузера. Стал думать что здесь можно сделать. Пришла идея попилить на куски не только JSON, но и теги script:
Запустил, заработало! Теперь я смог обойти и ограничение на
Учитывая то, что загружать в отчет можно сразу несколько файлов со статами, например, для сравнения сборок, предусмотрел пуш чанка по идентификатору стата:
Таким образом даже не важен порядок, в котором статы сбрасываются в отчет.
Прошло какое-то время и @rdvornov задал интересный вопрос: "Слушай, а почему бы не использовать теги script не как скрипт, а как текст, тогда можно было бы сэкономить на парсинге?"
И действительно, если сказать браузеру, что содержимое script - это не скрипт, а текст, то браузер не будет тратить время на парсинг сожержимого. А, на минуточку, 64kb x Nk тегов script - это ощутимо.
В итоге получилось что-то вроде:
Там конечно чуть сложнее, полную версию изменений можно посмотреть тут
Итог этой простой манипуляции такой: время загрузки отчета со статами в 650mb сократилась с 21 секунды до 14 (профит в 33%!!!)
Мораль: почти всегда можно что-то придумать, чтобы стало лучше (даже когда кажется, что нельзя) 😉
Как мы с вами уже знаем, у JS-движков есть ограничение на максимальный размер строки (например 512мб для V8)
Это значит, что при попытке получить строку большего размера, мы получим ошибку
RangeError: Invalid string length
Очевидно, что для статов размером больше 512mb тот же
JSON.parse
работать не будет, но как раз JSON.parse
нам и нужен.Обойти ограничение можно при помощи поточного JSON-парсера. Такому парсеру нужен источник строки, который будет отдавать ее не целиком, а кусочками (например по 64кb). По мере того, как парсер получает кусочки, он пытается их распарсить - превратить в объект. Очевидно, что этот объект растет по мере парсинга. Смысл в том, что мы не обрабатываем большие строки, а следовательно, у нас не возникает исключения
RangeError
, а сам объект путь себе растет пока хватает оперативной памяти.Ну хорошо, делаю первый подход - взял поточный парсер от @rdvornov, формирую HTML и инъекчу в него код вроде такого:
const chunks = [
сюда вставляю большой JSON порубленный на строки по 64kb
];
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);
Запускаю - не работает, браузер просто зависает 🤔
Методом проб и ошибок выяснил, что бразуер просто не переваривает такой большой тег скрипт (несколько сот мегабайт). Никакой особо полезной информации я по этому ограничению не нашел, но стало ясно, что теперь я воткнулся в проблему лимитов самого браузера. Стал думать что здесь можно сделать. Пришла идея попилить на куски не только JSON, но и теги script:
<script>
chunks.push(КУСОК_JSON)
</script>
<script>
chunks.push(СЛЕДУЮЩИЙ_КУСОК_JSON)
</script>
..... здесь еще много подобных тегов script
<script>
const data = await jsonExt.parseChunked(() => chunks);
Statoscope(data);
</script>
Запустил, заработало! Теперь я смог обойти и ограничение на
JSON.parse
и ограничение браузера на размер тега script.Учитывая то, что загружать в отчет можно сразу несколько файлов со статами, например, для сравнения сборок, предусмотрел пуш чанка по идентификатору стата:
<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>
<script>
api.pushChunk("stat2.json", КУСОК_JSON)
</script>
<script>
api.pushChunk("stat1.json", КУСОК_JSON)
</script>
Таким образом даже не важен порядок, в котором статы сбрасываются в отчет.
Прошло какое-то время и @rdvornov задал интересный вопрос: "Слушай, а почему бы не использовать теги script не как скрипт, а как текст, тогда можно было бы сэкономить на парсинге?"
И действительно, если сказать браузеру, что содержимое script - это не скрипт, а текст, то браузер не будет тратить время на парсинг сожержимого. А, на минуточку, 64kb x Nk тегов script - это ощутимо.
В итоге получилось что-то вроде:
<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>
<script type="text/plain" data-id="stat1.json">КУСОК_JSON</script>
......
<script>
for (const element of document.querySelectorAll('script')) {
api.pushChunk(element.dataset.id, element.textContent);
}
const data = await jsonExt.parseChunked(() => api.getChunks());
Statoscope(data);
</script>
Там конечно чуть сложнее, полную версию изменений можно посмотреть тут
Итог этой простой манипуляции такой: время загрузки отчета со статами в 650mb сократилась с 21 секунды до 14 (профит в 33%!!!)
Мораль: почти всегда можно что-то придумать, чтобы стало лучше (даже когда кажется, что нельзя) 😉
GitHub
(feat): improve HTML-report loading time · smelukov/statoscope@9b58295
Analyzes webpack stats and shows detailed info about it on the screen. - smelukov/statoscope
Выпустил Statoscope 3.5
Туда вошло изменение, ускоряющее получения списка npm-пакетов и их инстансов https://github.com/smelukov/statoscope/pull/43
Это значительно уменьшило время генерирования отчета при помощи плагина.
Кстати, это первый сторонний ПР в Statoscope, который что-то улучшает 🚀
А еще, видимо что-то пошло ТАК и Statoscope начали использовать на CI, т.к. количество скачиваний резко возросло https://npm-stat.com/charts.html?package=%40statoscope%2Fui-webpack 🤘🏻
Хотя, если вы большой проект, то лучше использовать кеширующий npm-proxy, например Verdaccio
Туда вошло изменение, ускоряющее получения списка npm-пакетов и их инстансов https://github.com/smelukov/statoscope/pull/43
Это значительно уменьшило время генерирования отчета при помощи плагина.
Кстати, это первый сторонний ПР в Statoscope, который что-то улучшает 🚀
А еще, видимо что-то пошло ТАК и Statoscope начали использовать на CI, т.к. количество скачиваний резко возросло https://npm-stat.com/charts.html?package=%40statoscope%2Fui-webpack 🤘🏻
Хотя, если вы большой проект, то лучше использовать кеширующий npm-proxy, например Verdaccio
Привет!
Году в 2017 я залип на соревновании return true
Вам дается функция, нужно изучить исходный код и понять что нужно передать в функцию в качестве аргумента так, чтобы функция вернула true.
Проблема в том, что задание нужно не просто решить, а сделать это за минимальное количество символов.
Есть простые задания, а есть и зубодробительные.
Я тут раскопал свои решения из первого сезона соревнования, но с тех пор вышло много других задач.
Интересно было бы видеть тут разбор этих задачек с моими размышлениями и комментариями? В виде ссылок на статьи в телеграфе (чтобы не спойлерить тем, кто хочет решить все сам)
Году в 2017 я залип на соревновании return true
Вам дается функция, нужно изучить исходный код и понять что нужно передать в функцию в качестве аргумента так, чтобы функция вернула true.
Проблема в том, что задание нужно не просто решить, а сделать это за минимальное количество символов.
Есть простые задания, а есть и зубодробительные.
Я тут раскопал свои решения из первого сезона соревнования, но с тех пор вышло много других задач.
Интересно было бы видеть тут разбор этих задачек с моими размышлениями и комментариями? В виде ссылок на статьи в телеграфе (чтобы не спойлерить тем, кто хочет решить все сам)
Telegraph
Telegra.ph is a minimalist publishing tool that allows you to create richly formatted posts and push them to the Web in just a click. Telegraph posts also get beautiful Instant View pages on Telegram.
27 февраля пройдет конференция Я Люблю Фронтенд и в рамках конференции был запущен челледж в формате Capture The Flag
Прошел где-то за 3.5 часа ✅
Рекомендую, помогает встряхнуть мозг 😉
Прошел где-то за 3.5 часа ✅
Рекомендую, помогает встряхнуть мозг 😉
Я ❤ Фронтенд
27 февраля тысячи неравнодушных разработчиков и разработчиц подключились к конференции «Я люблю фронтенд», чтобы посмотреть доклады от классных спикеров, поучаствовать в воркшопах и разобраться, что скрывается за улыбкой Айзелуортской Моны Лизы.
https://www.joinclubhouse.com/event/M1zov8YL
Сегодня в 19:00 по МСК мы с коллегами будем болтать про сборку и отвечать на вопросы, подключайтесь ;)
Сегодня в 19:00 по МСК мы с коллегами будем болтать про сборку и отвечать на вопросы, подключайтесь ;)
Сергей Мелюков
Хотите разбор return true?
Привет! Судя по результатам опроса, почти все проголосовавшие хотят разбора.
Подготовил для вас первую статью серии
Милости прошу в комменты с вопросами/предложениями по содержимому и формату 😉
Подготовил для вас первую статью серии
Милости прошу в комменты с вопросами/предложениями по содержимому и формату 😉
Teletype
return true: length
Привет! Разбираем решение задачки length из второго сезона RT.
За что люблю return true, так это за то, что он побуждает вгрызаться в особенности языка и иногда заставляет читать спеку, даже если не очень-то и планировалось. Например, с удивлением обнаружил, что при постинкременте, старое значение тоже приводится к числу:
f = () => 0
f++ // NaN
Я ожидал увидеть здесь f вместо NaN, т.к. это ПОСТинкремент.
Но спека говорит примерно следующее:
...
oldValue = ToNumeric(lhs)
...
Return oldValue
В результате чего, мы вполне логично получаем NaN при попытке привести функцию к числу.
О некоторых вещах часто не задумываешься и не замечаешь, пока дело не доходит до нестандартных кейсов 🤷🏻♂️
f = () => 0
f++ // NaN
Я ожидал увидеть здесь f вместо NaN, т.к. это ПОСТинкремент.
Но спека говорит примерно следующее:
...
oldValue = ToNumeric(lhs)
...
Return oldValue
В результате чего, мы вполне логично получаем NaN при попытке привести функцию к числу.
О некоторых вещах часто не задумываешься и не замечаешь, пока дело не доходит до нестандартных кейсов 🤷🏻♂️
А вот и вторая статья цикла про разбор задач из return true 🏆
Teletype
return true: countOnMe
Привет! Сегодня разбираемся с задачкой countOnMe из второго сезона RT.
А давайте немного поболтаем и порешаем задачки? 🙂
Как вы уже знаете, я люблю всякие челледжи и недавно я наткнулся на такую вот задачку:
Иначе говоря: На вход функции поступает число, каждый разряд которого нужно возвести в квадрат. Полученные квадраты разрядов нужно объединить и вернуть из функции.
На входе и на выходе должны быть именно числа (`typeof x === 'number'`). Примеры:
Как вы решали бы эту задачу? При условии, что вам надо сразу сделать так, чтобы с точки зрения кода все было круто и эффективно.
Будет круто, если пришлете кусочки кода в какой-нибудь code pen. Или просто поделитесь мыслями.
PS: очевидно, не все так просто, иначе я бы не поднял этот вопрос 😉
Чуть позже поделюсь своими мыслями и решением 😉
PPS: Возможно такой формат окажется интересным.
Как вы уже знаете, я люблю всякие челледжи и недавно я наткнулся на такую вот задачку:
You are asked to square every digit of a number and concatenate them.
For example, if we run 9119 through the function, 811181 will come out, because 9^2 is 81 and 1^2 is 1.
Note: The function accepts an integer and returns an integer
Иначе говоря: На вход функции поступает число, каждый разряд которого нужно возвести в квадрат. Полученные квадраты разрядов нужно объединить и вернуть из функции.
На входе и на выходе должны быть именно числа (`typeof x === 'number'`). Примеры:
fn(3212) // 9414
fn(9119) //811181
Как вы решали бы эту задачу? При условии, что вам надо сразу сделать так, чтобы с точки зрения кода все было круто и эффективно.
Будет круто, если пришлете кусочки кода в какой-нибудь code pen. Или просто поделитесь мыслями.
PS: очевидно, не все так просто, иначе я бы не поднял этот вопрос 😉
Чуть позже поделюсь своими мыслями и решением 😉
PPS: Возможно такой формат окажется интересным.
Сергей Мелюков
А давайте немного поболтаем и порешаем задачки? 🙂 Как вы уже знаете, я люблю всякие челледжи и недавно я наткнулся на такую вот задачку: You are asked to square every digit of a number and concatenate them. For example, if we run 9119 through the function…
А вот и небольшая статейка про решение этой задачки https://teletype.in/@smelukov_dev/codewars-square-every-digit
Teletype
codewars: square every digit
⚠️ Статья наполнена спойлерами. Если вы хотите сами решить задачу, то вернитесь к статье только после того как решите ее сами или если...
❤1