Фиг с ним
227 subscribers
6 photos
28 links
@xnimorz фронтенд, разработка, Лондон, интриги, не расследования.
Download Telegram
to view and join the conversation
Алгоритмы, алгоритмы, а как применять и зачем они? В комментарии к прошлому посту как раз спросили об этом с примером про ML.
Давайте начну с собственного опыта, от нового к старому

1) У меня есть вот такой пет-проджект: https://www.boarder.app/, в которой я пишу заметки, прогоны спикеров, кучу всякого. Где там алгоритмы? Из того, что сходу назову:
- Для работы с выделением строк, особенно в первых версиях, когда не было блочного выделения, я писал поиск в глубину, который от общего родителя бегал к нужному Range. Вот пример простого алгоритма на графах, в рамках DOM модели.
- Туда же идет выбор структур данных: вот есть MutationList, он мне не удобен, он большой, записи сгруппированы не так, как мне в редактор нужно сохранять. Я превращаю это все ассоциативный массив (умное слово, по факту ключ-мутация) элементов.
- сериализация и десериализация модели — подобие дерева в итоге, плюс она важная, так как каждое изменение летит прямиком в window.cache. Нужно, чтобы изменения доставлялись максимально быстро без сериализации всего документа за раз

К этим алгоритмам еще разнообразие клиентов палки в колеса вставляет: например в IOS pointer events работают для моего кейса немного не так как надо и я ловлю pointer event с заведомо устаревшими данными. В итоге откатывался до touch + mouse (а они нужны для выделения строк)

Сюда же добавляется вопрос — насколько важна скорость: смотрю насколько тяжело работать js и браузерную лейауту, чтобы номер строки указывать слева (спойлер, больно при копировании книг), тестирую разные варианты, рисую в итоге через CSS (можно еще добавить браузерную виртуализацию, но я для таких объемов данных в своих заметках не дополз)

В итоге: описанные действия вполне простые и могут быть в повседневной работе. Если у вас есть алгоритмическая база — вам будет сильно проще.
2) Примеры с работы в HH, о которых я, либо ребята из хх рассказывали на публике (поэтому я могу ими поделиться и сейчас 😉

Переводы: 5 Мбайт brotli переводов. На клиент не отправить, искать по огромному масиву который до brotli будет ого-го тоже не самое полезное занятие.

Как искать? Префиксные деревья, например: https://github.com/s-yata/marisa-trie

Как хранить переводы в компонентах реакта? Единая ХешМапа (которая в js не хеш мапа), которая шарится по ссылке между всеми компонентами. Но если компонент не должен иметь доступ к переводу "Б"? Система guards через Proxy. Потому что если создавать для каждого компонента объект, у вас для 10000 реакт-компонентов на странице, на SSR будет вызываться нереальное количество GC (справедливо очень для SSR нодовского) и в итоге рендер страницы будет замедляться на 10-20%.

Babel плагины — те же обходы графа только в профиль. Дико рекомендую посмотреть на этот проект: https://github.com/hhru/babel-plugin-react-displayname — добавляет красивые пути в ваш проект, чтобы не погрязнуть в длинных названиях компонентов. Другой пример https://github.com/hhru/babel-plugin-react-source — удобно на хост компонентах иметь ссылку "а где он тут в коде"

ML: здесь я нуб, поэтому верить тут мне НЕ нужно и лучше уточнить у специалиста. Но насколько я в курсе, в ML есть вектора. Задача градиентного спуска и же с ними. Вектора нужно как-то оптимизировать и не заставлять пользователя ждать ответ год, градиентный спуск — чистые алгоритмы.

Отрисовка графиков: годик эдак назад, тот же телеграм проводил конкурс на "Нарисуй самый быстрый график на js для аналитики". Самые эффективные подходы: webGL, написание шейдеров. Копнем чуть дальше и там чистая математика работа и преобразование матриц. Сюда же смело можно тащить любую сложную графику.

Кстати, в свое время я писал диплом, посвященный отрисовке графов, там все те же алгоритмы. Применение банально — граф друзей vk красивый нарисовать, в твиттере круги общения и так далее. Под пласт "как эффективно нарисовать график" есть огромнейшее количество алгоритмов. Часть из которых базируется на представлении графов как физических тел, а грани между ними — пружины. Подход называется Force directed graph, посмотрите, это красиво
Если вдруг интересно какой-то случай отдельно-подробнее разобрать, пишите, расскажу 🙂
А перед тем как говорить, представьте: вы хотите научится разрабатывать. Например фронтенд. Как будете учиться? На что сделаете фокус? Даже если у вас уже есть опыт, было бы круто увидеть ваш ответ и мнение.
Anonymous Poll
68%
Самообразование — книги, pet-project
7%
Университет
43%
Онлайн-школы / курсы hexlet, geekbrains, htmlacademy
25%
Школа с дальнейшем трудоустройством в эту же компанию: ШРИ Яндекса, школа разработчиков хх, т.д.
10%
Найти личного ментора за деньги
20%
Стажировки: Яндекс, мейл ру, авито
2%
Другое? Что?
Наброшу тему на выходные:
Один из популярнейших вопросов «как научиться писать код».

В Твиттере, линкедине — везде эта тема огромное количество раз поднималась и обсуждалась.

На выходных поговорим про это как раз.
Из 42 ответов с явным отрывом лидирует самообразование. 

Окей. Я последнее время очень хорош с тайм-менеджментом, но лучше поздно, чем только в мечтах. 

Наброшу вначале на онлайн школы. Мне кажется, одна из больших проблем людей — мы не умеем учиться. Мы тупо не научились работать с информацией. Она льется из кучи мест — твиттеры, телеграм-каналы, youtube каналы, документация, проекты на гитхабе, стековерфлоу, доклады — мильёны их. 
А у нас одна проблема — мы хотим магическое место, которое открыл... и научился. Сразу. 

Такое нам, кстати, обещают хипстерские школы. hexlet, html-academy, geekbrains — это те, про которые я непосредственно слышал. (и я не знаю, какое количество есть еще)
Что они делают? В плане образования — ищут людей которые расскажут студентам и научат их. 
В плане маркетинга — обещают научить профессии, на которой вы будете мильёны и зарабатывать. И по моим ощущениям в маркетинг школы умеют куда как лучше.

Потому что:!
1) Если мы не умеем учиться, школа нас не научит. Нам нужен навык разграничения информации по полочкам и ее обработки. 

2) Я не буду показывать пальцем, но недавно наткнулся на прекрасную рекламу. "Вася Пупкин — ведущий преподаватель нашей школы. Вася живет в N, преподает в вузе (название предмета никак не коррелирующая с разработкой) и работает в вузе с командой программистов. Он вас научит разработке на питоне." Научит, да. Имена и город конечно же изменены, но суть передает прекрасно. Я в рекламе не увидел информации, по какой причине Вася Пупкин обладает востребованными мне знаниями. Когда вы идете на курсы, у вас нет никакой гарантии в навыках людей, которые вас обучают. 

Я могу сказать смело — я доверяю школам, за которыми стоит компания и/или конкретные люди из сообщества, которые отвечают своей репутацией. Моя бывшая компания — хх, школа разработки интерфейсов яндекса, redmadrobot + еще небольшое количество компаний, где "учат людей для себя". Это работает. Это работает потому что студенты:

1) Если не умеют учиться их отчисляют. Они не нужны компании. Компания хочет получить гарантированных кадров.

2) За обучением стоят конкретные разработчики конкретной компании. Это не супер-преподаватели. Но свое дело знают. И я бы предпочел учиться у человека, которому сложнее знания передать (но он хочет это сделать), чем у талантливого передатчика знаний без самих этих знаний. (кстати, здесь я дико благодарен вузу своему, где было очень много преподавателей — реальных разработчиков). 

Поэтому если видите такую школу — это работает. Если видите стажировку — это работает по тем же причинам. Стажировок, благо, тоже много — авито, мейл, яндекс. 

Теперь немного о том, почему школы за которыми нет компании, нет, не плохие, но я бы очень сильно подумал, прежде чем идти туда:
1) Если я не умею учиться, у меня неплохие шансы все равно закончить. Потому что я занес денег. 
2) Я не знаю, кто меня учит. Какой у людей бекграунд, навыки, то есть я в целом не понимаю, что я получу. Вот пример: иду на конференцию и вижу заголовок: k8s. Значит расскажут что-то про него. Но доклад про кубик может быть уровня — эта штука позволит вам сервисы менеджить. А может уровня как работает, как настраивается, как менеджить, какие-то edge кейсы. И это самая главная проблема таких школ.
3) Я не могу сказать, насколько знания, что я получу, помогут мне в карьере, выполнении целей. Вопрос актуальных и нужных знаний. 

Почему я вообще дал себе право судить о школах?
1) Я преподавал в школе разработчиков хх
2) Я собеседовал немало людей, которые закончили те самые "хипстерские" школы. И честно признаюсь, выпускники ШРИ всегда были на пару голов выше, чем выпускники хекслета или html-академии. Скажем так, ребята из ШРИ всегда работали головой. 

И да. Здесь я ни в коем случае не затрагиваю авторские курсы. Например, Илья Климов, который делает на мой взгляд, одни из самых сильных курсов. Я здесь говорю только про компании. 
Дальше поговорим о вузах и самообразовании.
Если вдруг пропустили: Modulz выпустили не самую обычную библиотеку компонентов. Она построена без использования каких-либо стилей.

То есть вы можете как добавить любые свои стили, чтобы все выглядело так, как вам нужно, либо использовать просто системный вид.

Выглядит очень круто, потому что я часто слышал от разработчиков, что эти uikit нам не подходят, потому что навязывают свой дизайн, а кастомизация с целью закрыть базовые стили оверинжениринг и не самое благодарное дело.

https://twitter.com/colmtuite/status/1339227861505466369?s=21

Бонусом, я потыкал компоненты, выглядит проект хорошо декомпозированным ;)
Не так давно в jsunderhood было обсуждение сложности useCallback’ов.

Вот смотрите: каждый проект считает своим долгом иметь какой-нибудь useToggle, который умеет переключать значение из true в false по вызову функции.
Что-то народе:

[value, toggle] = useToggle(initial);
...
toggle()

Вроде бы до безобразия просто?

Если интересно, подумайте, как бы вы сделали такую функцию?

{пауза на подумать}

Вот тут Gabe расписал разные варианты и логично добрался до редьюсера в конце. Посмотрите, это прям простое «интро в колбеки и редьюсеры в несколько твитов».

https://twitter.com/gabe_ragland/status/1339320009621872641?s=21
Канал не пал смертью храбрых.
Но в начале я присоединился к команде в фейсбуке, разбирался что к чему, затем долго думал, почему же я сам не получаю кайфа от ведения канала. У меня уже был предыдущий опыт, когда больше года назад я пытался делать также. Не зашло.
Так вот, секрет, как мне кажется, достаточно прост. Я не умею писать коротко и без иллюстраций. Мне всегда нужно где-то код привести, где-то скриншот вставить. Когда я пытался написать последний пост в канал, самое сложное было — понять какой кусок текста (половину) вырезать.
Поэтому я снова обратил свое внимание в сторону: что выбрать.
medium — удобный, но платный для пользователей
dev.to — неудобный, некомфортный
habr.com — "мелкие" мысли не напишешь
Хочу свой блог!

Коротко, что в итоге:
Теперь обзавелся блогом на своем сайте. Чуть позже расскажу, что да как в нем устроено. https://xnim.me/blog
Первый пост вчера уже добавил: вот пишем мы Math.max(...(new Array(1000000))); и все падает. Почему? Вот здесь есть разбор с исходниками v8 https://xnim.me/blog/math-max-call-stack-ru

Что дальше с каналом в тг? Я предполагаю, что канал будет местом для обсуждения статей из блога. В блоге статья и ссылка на пост в тг, где можно задать вопрос, обсудить. Как-то так.
Привет! Добавил (донастроил) RSS для своего блога: xnim.me/atom Если кто пользуется RSS читалкой, расскажите, заработало?

Оказывается я вообще крайне редко работал и вообще не использовал для себя RSS. Прямо мимо меня эта тема пролетела как то.
Лучше поздно, чем никогда! Я как-то проводил опрос про промисы и GC: https://twitter.com/nikmostovoy/status/1372577924478566406
Кажется, что промисы — это 100500 раз разобранная тема, но оказывается, это все еще вызывает кучу вопросов.
Сегодня поговорим про GC, как он дружит или не дружит с промисами:
https://xnim.me/blog/promises-and-gc Причем поговорим не в районе циферок и скринов DevTools, а проверим на практике.
По поводу промисов еще: получил вопрос, а как распознать статус промиса в рантайме? Понятно, что можем подписаться, еще что-то, а вот если нужно определить рандомный промис: resolved \ rejected \ pending? Здесь на самом деле очень помогает Promise.race: https://xnim.me/blog/promise-status
Всратые технологии: indexedDB очень мощная и гибкая штука (правда). С точки зрения внутренней архитектуры — это просто пушка. Умеет в индексацию, хранение документов, транзакционность, миграции, версионирование и так далее.

Однако работать с indexedDB в ванильном варианте — это то еще извращение. На открытие базы у вас уже минимум три колбека: на ошибку, на успех и на необходимость апдейта, который вызывается еще в случае отсутствия базы. Колбек на колбеке в колбеке. Это приводит к тому, что крайне сильно становится нужен wrapper.

Один из самых удобных wrapper'ов на текущий момент: Dexie https://github.com/dfahlander/Dexie.js Основан он на промисах, что удобно.

Но вот загвоздка: как только начинаешь копать в сторону работы indexedDB и особенно транзакций, выявляешь одну крайне пре-неприятную вещь: транзакции indexedDB живут внутри MacroTask.
То есть код:

const transaction = db.transaction(["cars"]);
setTimeout(function () {
const objectStore = transaction.objectStore("cars");
const request = objectStore.get("bmw 118i");
request.onerror = function(event) {
console.error('error', event);
};
request.onsuccess = function(event) {
alert("Plates for car bmw 118i is " + request.result.name);
};
}, 0);

Обречен на падение, потому что мы вышли из транзакции.

В то же время нативный промис:

const transaction = db.transaction(["cars"]);
Promise.resolve().then(function () {
const objectStore = transaction.objectStore("cars");
const request = objectStore.get("bmw 118i");
request.onerror = function(event) {
console.error('error', event);
};
request.onsuccess = function(event) {
alert("Plates for car bmw 118i is " + request.result.name);
};
});


Пройдет, потому что транзакция будет выполняться внутри микротаска, который технически будет относиться к скопу макротаска, так как промис зарезолвится в том же макротаске, что и создание транзакции.

И вот этот подход вселяет ошибочное чувство, что все запросы построенные на промисах будут работать. Вот здесь есть подробное обсуждение, почему это не совсем так: https://github.com/promises-aplus/promises-spec/issues/45

Как решить? Что ж, если покопаться в dexie, то это решается следующим способом:
Первый промис генерирует микротаску (в modern браузерах). Все последующие резолвы \ реджекты синхронные, что достаточно сильно бьет по восприятию работы кода, особенно когда начинаете дебажить сложные кейсы, где может быть задействовано несколько таблиц сразу.

Какая мораль? Даже если у вас есть популярное и хорошее опен-сорс решение, это никак не избавляет вас от необходимости достаточно подробно разбираться с кодом.
Notion выпустил beta версию своего API и немного (от слова совсем) изменил “обратную совместимость”. https://developers.notion.com/reference/intro Главная причина — авторизация теперь возвращает 401 ошибку (но и остальные RPC методы теперь возвращают пустые ответы). На неделе верну блог и опубликую англоязычный лонгрид про event loop, layout, paint и composition.
Окей, блог вернулся к жизни, и я таки завершил перевод своей статьи, опубликованной изначально на хабре про event loop.

На русском: https://habr.com/ru/company/hh/blog/517594/
English: https://xnim.me/blog/javascript-browser-event-loop-layout-paint-composite-call-stack

В переводе самое сложное — заставить себя писать. Потому что вот уже полет мысли закончился, все написано и дальше уже сухое переписывание. Поэтому перевод у меня идет в час по чайной ложке, вне зависимости от направления — с английского на русский или наоборот.
В статье про Event Loop я задавал несколько вопросов. Давайте разберем их здесь. На каждый вопрос будет отдельный небольшой пост.

1) Will console output "1"? Why?
function loop() {
Promise.resolve().then(loop);
}
setTimeout(() => {console.log(1)}, 0);

loop();


Ответ: 1 выведено не будет, страница зависнет. Каждый вызов loop кладет microtask в microtask queue. А это значит каждый раз, как loop функция заканчивается, мы достаем microtask. Поэтому ни до рендера, ни до новой задачи из TaskQueue мы не дойдем. Линк на теорию: https://xnim.me/blog/javascript-browser-event-loop-layout-paint-composite-call-stack#call-stack + сразу за ним микротаски
2) There is a site that has a link, which has cursor: pointer on :hover style. Also, the website has a button, which :hover style changes background-color from grey to blue. Now, let add a script to the console:
while (true);

The question is what will happen when we point the mouse over the link? Over the button? Why?

Ответ: Мы получаем бесконечный цикл, поэтому задачи из RenderQueue никогда выполнены не будут. Это означает, что мы вообще никогда не выполним ни один из этапов: Style\Paint\Layout\Composite, стили на :hover не применятся. Подробнее про это здесь: https://xnim.me/blog/javascript-browser-event-loop-layout-paint-composite-call-stack#what-is-taskqueue + схема, где style и paint можно увидеть, находятся в том же треде.
3) What will console output? Why?
Promise.resolve(1)
.then((x) => { console.log(x); return x + 1 })
.then((x) => {console.log(x);})

Promise.resolve(10)
.then((x) => { console.log(x); return x * 10})
.then((x) => {console.log(x);})


Ответ: если у вас нет овверрайда на промисы, то вывод будет вот таким:
1
10
2
100

Почему так: в основном таске, мы резолвим 2 промиса. На них сразу же навешиваем два then callback. Как только стек для таски завершается, эти колбеки вызываются в соответствие со своим порядком. Поэтому вначале будет выведено 1. Эта микротаска в свою очередь резолвит второй третий промис. Но так как в microtask queue уже стоит промис для вывода 10, то он будет исполнен только после 10. Аналогичная работа происходит и с выводом 100.

Теория: https://xnim.me/blog/javascript-browser-event-loop-layout-paint-composite-call-stack#call-stack + сразу за ней микротаски
4) How to animate a popup element height from 0 to auto? It's important to discuss the different methods using JS and\or CSS.

Если говорить про CSS решения, то можно использовать scaleY: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scaleY Но его нужно будет донастраивать, так как анимационный эффект будет не тот, который предполагается.
Если говорить про JS решения, то можно воспользоваться следующим подходом:

div1.style.height = 'auto' // Запланировали изменение высоты
const animateTo = div1.offsetHeight; // форсим layout, размеры будут пересчитаны, но пользователь изменений не увидит
div1.style.height = '0' // возвращаем первоначальное значение


После этого кода animateTo знает до какого размера анимировать элемент. Все что остается сделать, это иметь transition для анимации и использовать обычную css-анимацию
Есть такой зверь — SVG шрифты. Это когда каждая буква представляется в виде векторного SVG. Технически это очень удобно. Шрифт может легко масштабироваться, такой шрифт даже автоматизировать очень легко.

Есть такой зверь — emoji. Они не всегда бывают в формате svg. Иногда в формате PNG, иногда в webp. Редко lottie (json + svg).

И вот шрифты обычно содержат еще и эмодзи. И если у вас эмодзи в PNG формате, это означает, что в svg у вас будет содержаться data-image: png.

В итоге мы получаем: шрифт, который SVG Font, который содержит PNG картинки внутри себя.

Такой шрифт:
а) Плохо масштабируется — мы теряем преимущество svg шрифта
б) Большой по размеру — приходится иметь несколько шрифтов. Один для малого размера, другой побольше и так далее.
в) Не работает с canvas.

Немного про неработает с canvas:
canvas позволяет работать рисовать текст через fillText (или `strokeText`). Он отлично рисует обычные, svg шрифты. Но если у вас png inside svg, то вы получите на месте символа пустоту.

Вывод: думайте дважды.