Шось про айтішку – Telegram
Шось про айтішку
1.46K subscribers
447 photos
162 videos
2 files
599 links
Фронтенд, ШІ, 3D друк, FPV, історії з життя та роботи
Download Telegram
В ClojureScript есть type inference, хотя язык динамический, который используется для генерирования externs, вместо того чтобы писать их руками, и для генерирования оптимального кода.

Тип можно определить вручную, с помощью type hints, которые добавляют значение в поле :tag в метаданных этого значения

(def ^number x 1)

Благодаря type inference часто явный type hint не нужен. Компилятор сам распознает и добавит тип значения.

Помимо тегов значений есть теги возвращаемых значений из функции

(defn ^js/Promise http-get [url]
(js/Promise. ...))

Для (.then (http-get url) on-ok) компилятор использует информацию о возвращаемоем типе чтобы сгенерировать extern Promise.prototype.then, который позже будет использован в Closure Compiler для генерирования корректного интероп кода в процессе оптимизации.

Типы возвращаемых значений тоже могут быть автоматически распознаны компилятором. В примере ниже функции f будет присвоен тип string.

(defn f [] "123")

Благодаря тому, что возвращаемые типы пробрасываются через функции, например имея в кодовой базе одну функцию которая возвращает Promise, автоматический externs inference покроет все использования этой функции и компилятор сгенерирует корректный интероп код.

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

Например известно, что (str 1 2) вернёт string, но тип (apply str [1 2]) уже неизвестен. apply здесь — функция высшего порядка, которая вызовет str и тогда уже вернёт строку.

Поэтому я начал работать над патчем для return type inference в функциях высшего порядка. По факту это абстрактное выполнение кода на этапе компиляции, когда компилятор повторяет как конкретная функция отрабатывает в рантайме.

Например зная, что str всегда возвращает строку, можно утверждать, что (apply str xs) тоже вернёт строку.

Интереснее становиться, когда у multiarity функций методы имеют разные типы возвращаемых значений.

(defn f
([a b] (+ a b))
([a b c] (str a b c))

В примере выше f имеет тип #{number string}, но зная количество аргументов на этапе компиляции, можно определить конкретный тип.

Например для (apply f a b c xs) можно утверждать, что возвращаемый тип будет string, но никак не number.

Эту информацию можно использовать чтобы определить несовпадение количества аргументов с арностью методов. Для (apply f a b c d xs) можно точно сказать, что f не имеет метода с арностью 4 или больше.

Type hints можно использовать, чтобы помочь компилятору сгенерировать оптимальный код. В целом разница будет заметна только для hot path кода.

Например в проверках на правдивость механизм приведения типов в ClojureScript отличается от JS. Поэтому тестовое выражение будет обернуто в вызов функции, которая приведет тип согласно этому механизму.

(when x true)

if (cljs.core._truth(x)) {
true
}

Или например аргументы в str будут обернуты в вызов функции которая приводит значение к строке

(str a b "s")

[str(b), str(a), "s"].join("")

Если в первом случае x действительно Boolean и во втором случае a и b строки, то об этом можно сообщить компилятору с помощью type hints и сгенерированный код будет более оптимальным.

(when ^boolean x true)

if (x) {
true
}

(str ^string a ^string b "s")

[a, b, "s"].join("")
Более интересные оптимизации, так называемые intrinsics, используют type inference для переписывания кода в более оптимальный для конкретного типа данных.

Например для выражения (count x), где известно, что x имеет тип string или array, компилятор сгенирирует x.length, вместо рантайм вызова протокола ICounted. Или для выражения (:x rec), где rec это Record, компилятор сгенирирует rec.x, вместо доступа к полю через вызов протокола.

Но такие оптимизация не всегда дают прирост в производительности.

Например, на первый взгляд (apply str a b xs) будет медленнее, чем аналогичная конструкция (clojure.string/join (cons a (cons b xs))), потому что apply соберёт аргументы редьюсом, а потом str соберёт строку в цикле. В то время, как str/join соберёт строку в одном цикле. Выходит, что первый вариант в 2-3 раза медленнее.

Однако, прогнав скомпилированный код мы увидим, что вариант с apply наоборот, в 2-3 раза быстрее str/join. Причина в том, что функция str/join достаточно коротка, чтобы компилятор заинлайнил ее в месте вызова (что говорит о том, что такой код будет ещё быстрее), но из-за отличий правил скоупинга в ClojureScript от JS заинлайненый код будет обернут в самовызывающуюся функцию. И тогда выходит, что на каждый вызов такого выражения будет создана новая функция, что и бьёт по производительности.
Начал серию скринкастов о разработке нативного UI под десктоп на ClojureScript, React, Node и Qt. Стек технологий достаточно необычный, поэтому должно быть интересно. Тема затрагивает нативные аддоны для Node.js, кастомный reconciler для React и разработку UI на cljs. https://www.youtube.com/user/roman01la
Итак, новости спустя почти два года:

В конце 2019го мы запустили бету, в конце 2020го запустились для всех и недавно отпраздновали первый год после релиза.

Где-то перед релизом поняли, что нужно вкладывать больше времени в производительность приложения, по итогам решили создать отдельную инфраструктурную команду. Я переключился на роль «менеджер/все ещё нужно писать код». Сейчас ищу больше инженеров в Team Performance, в основном занимаемся производительностью фронтенда. Пишите в личку если вам интересно этим заняться, расскажу подробнее. Про перфоманс позже напишу ещё сюда, за год накопилась информация которой хочется поделиться.
О перфомансе во фронтенде

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

Пользовательские ивенты отслеживаются через RUM (Real User Monitoring) в DataDog. В основном это перфоманс метрики различных действий, которые производят пользователи. Например: открытие презентации, переключение слайдов, перетаскивание блоков или печатание текста в редакторе. Каждая из метрик имеет набор трешхолдов в формате Good, Needs improvement и Poor. Отслеживая эти метрики мы понимаем для кого и когда приложение тормозит. Бывает на графике сразу видно, как после очередного релиза линия ползет вверх, значит в релиз попала регрессия. В идеале для этого нужны синтетические перф тесты, которые бы блокировали PRы, так же, как остальные виды тестов, но практика показывает, что в браузерном окружении разброс результатов достаточно большой, т.е. на конкретном пулл-реквесте практически невозможно определить отклонение, если это конечно не очевидная регрессия, но такое бывает редко.

Большинство перф метрик замеряют время от пользовательского действия (нажатия клавишей мыши или клавиатуры) до момента, когда желаемый результат отобразился на экране. Под это описание попадают практически все действия пользователя: навигация, создание или удаление чего либо, открытие/закрытие окон и т.д.

Такие метрики стартуют запись времени с помощью performance.mark() внутри обработчика события и останавливают вызывая performance.measure() в useLayoutEffect хуке в реакте, в компоненте который должен появится на экране. Именно этот хук вызывает колбек после того, как браузер отрисовал изменение на экране.

Временные промежутки записанные с помощью mark/measure отображаются в Performance панели в Chrome DevTools. Это сильно упрощает дебаг конкретного действия, т.к. эти фреймы отображаются вместе с JS стек трейсом.

В DataDog метрики выглядят вот так
Я не добавлял комментарии в этот канал, так что если есть вопросы, пишите в личку. Отвечу туда же или постом в канал 👍
Сегодня узнал, что в Performance панели в Chrome DevTools можно замерить время декодирования и отрисовки изображений. Что это такое? Скажем после того, как изображение загружено браузером из сети в память, массив данных нужно распарсить, сделать декомпрессию (большинство растровых форматов сжимают изображения для уменьшения размера файла) и отрисовать данные, на CPU или GPU.

Каждый новый формат имеет преимущества над более старым. Допустим размер файла в WEBP обычно меньше, чем JPEG, но не всегда. AVIF еще меньше WEBP, но опять же не всегда, и создает больше визуальных артефактов т.к. алгоритм сжатия построен поверх кодека для сжатия видео, где артефакты менее заметны глазу. Собственно из-за этих отличий в алгоритмах декодирвания и заключается разница во времени обработки изображения браузером.

Прогнав JPEG, WEBP и AVIF разных размеров и настроек качества я увидел, что быстрее всего декодируется JPEG, AVIF примерно в 2 раза медленее, а WEBP где-то между ними, иногда ближе к AVIF. Еще одна особенность WEBP (или того, как это делает Chrome) в том, что изображение высокого разрешения (по крайней мере 3x5k) декодируется и отрисовывается прогрессивно, сверху вниз, как прогрессивный JPEG.

Когда это может быть важным? Когда важно показывать изображение без задержки. Например в Pitch при переключении слайдов мы заметили задержку в отрисовке уже предзагруженных изображений. Обошли это путем рендеринга изображений для ближайших слайдов в скрытых DOM элементах.
Вітаю. Через чотири місяці після початку війни я та мій друг трохи зібрали свої кабіни і вирішили запустити подкаст на ютубі та тг канал під нього. Приєдуйтесь, там ми будемо робити айтішний контент та збирати донати на ЗСУ. Сподіваюсь наш контент допоможе вам відволіктись від всього піздеца хоча б на півгодини кожного тижня.
https://news.1rj.ru/str/droptarget
https://www.youtube.com/channel/UCtdUJ9f7v43dQaciP42P40Q
Channel name was changed to «Шось про айтішку»
Channel photo updated
Літо пройшло, падвідьом ітогі.

Війна продовжується, таке відчуття що всі чекають ядєрку. Не зважаючи на це, я трохи змінив контекст і переїхав (все ще в Києві).

На роботі лейофнули 30% персоналу. Мені у цьому плані пощастило, чи через те, що я в Україні, чи через те, що я там написав стільки говнокоду, що мене скорочувати невигідно)

У вільний час почав колупати React Native. Останній раз щось робив на ньому років 6 назад. Після вебу це прикольна платформа, бо є повний контроль, і js і нативна частина. Потроху вивчаю c++, якось напишу нашо мені це.

А зараз чекаю поки з каналу відвалиться вся руснява падпісота, бо бачу шо сиплються на постах українською)
Тут доречі на тлі продажу Figma за дохєра бабла, невеличка компанія Penpot https://penpot.app/ підняла 8 лямів інвестицій та отримала приток користувачів https://techcrunch.com/2022/09/27/penpot-inks-8m-as-signups-for-its-open-source-spin-on-figma-jump-5600-after-adobes-20b-acquisition-move/

Команда Penpot вже давно будує опенсорсний дизайн тул, доречі сам тул написаний на ClojureScript. Хлопці дали багато кльових бібліотек в опенсорс https://github.com/funcool а ми колись переклали їх посібник по cljs українською https://lambdabooks.github.io/clojurenoscript-unraveled/
​​Дивлячись фото та відео мосту, згадав, що не так давно пробував симуляцію вибухів у EmberGen https://jangafx.com/software/embergen/

Це софтина для realt-time симуляції фізики газоподібних речовин (дим або вогонь). Чуваки розробили паралельний алгоритм симуляції, який виконується на GPU. На моїй RTX 3060 симуляція оцього вибуху дає 25-30 FPS, що набагато швидше ніж в Blender, бо Mantaflow все рахує на CPU і це може зайняти усі вихідні. От настільки GPU може взувати CPU якщо можливо адаптувати алгоритм під паралелізацію.

Симуляція потім експортується у формат VDB (Volume Database) як послідовність кадрів з вокселями і закидуються у Blender де можна вже поєднати її зі сценою, підправити візуал і відрендерити.

Я подумав, що було б кльово відрендирити VDB у бразері через WebGL, але нажаль це буде супер повільно, тому що знов ж таки — воно все проходить через CPU, а WebGL сам по собі вже повільніший через браузерну прослойку. Але ось є альтернатива — NanoVDB (https://developer.nvidia.com/nanovdb), це якраз варіант рендеру VDB на GPU. Розробники бібліотеки начебто працюють над підтримкою WebGL, тому колись воно буде.
Цікаво хто як готується до зими в Україні? Я поки шо тримаюсь думки, що Київ та центр зазнає проблем з постачанням газу та електроенергііі в останню чергу, хоча все може бути.
Бачив хтось купує акумулятори за 25-50к, сонячні батареї, балони з газом, та буржуйки.
Ми собі вирішили поки не рипатись, якщо буде погано поїхати в приватний будинок з дровами та колодязем, але це вже на крайняк.
З цікавого, десь весною замовлял Starlink, днями нарешті відправили, чекаю доставку. Але теж думаю що пограюсь і віддам в ЗСУ.
Інколи буває, що хочеться трохи пописати код, але робити якийсь фронтенд чи ганяти жисочики зовсім не цікаво, бо цього і на роботі вистачає.

Я для цього останнім часом почав лайтове входження в геймдев. Виявилось дуже фаново знов повчити фізику і закодити фізичні моделі, якусь ракету в космосі чи підвіску автомобіля.

В таких справах для мене головне — не втрачати елемент задоволення від процесу і завжди мати проміжний результат. Бо сидіти годинами мучати якусь бібліотеку чи боротися з апішкою відбиває бажання продовжувати. Це доречі головний фактор в навчанні.

Звичайно я спробував Unity та Unreal Engine, і Godot. Але поки що зупинився на самому простому — робити щось маленьке і просте, і майже все руками, тому роблю щось в вебі на pixi.js якщо це 2D або Three.js для 3D.
👍5
Відключення світла все більше впливають на роботу команди. В мене поки що не було, можливо пощастило з локацією. Тільки от зараз немає води.

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

Я поки не думав як до цього адаптуватись, особливо коли відключення відбуваються не по графіку. Поки шо плюс-мінус проблема — це статус людини. Якщо б було по графіку, в Slack можна автоматично встановлювати статус на шось типу «офлайн бо русня гандони».

В генераторах не бачу сенсу, бо часто відключають і мобільні вишки, тому зв’язку також нема. Якщо тільки ваш сетап проєкту не дозволяє працювати повністю офлайн.
2
Я згадав, що в мене є YouTube канал, на якому я вже рік-два не постив. Тому вирішив його трохи оживити. Найближчим часом там виходитиме серія відосів по моделюванню в Blender та простенькому геймдеву. Думаю буде фаново, підписуйтесь.

👉 https://youtu.be/_sCz7vGmn7A
👍8