melikhov.dev – Telegram
melikhov.dev
4.63K subscribers
110 photos
2 videos
2 files
203 links
Фронтенд, фронт-бек и около. Всё, что в голову пришло. Иногда котики.
Download Telegram
Приключения DI в мире функционального программирования

Когда-то давным-давно (в 2011 году), Марк Симан написал отличную книгу «Внедрение зависимостей в .NET». Всё, что нужно знать про DI в ООП там есть. Маст рид. А несколько лет спустя Марк ударился в функциональное программирование и написал достаточно резонансную серию небольших статей "From dependency injection to dependency rejection" (а также поездил с докладом).

Сегодня у нас будет TL;DR по этой серии.

Итак, Марк начинает с демонстрации «классического» ООП внедрения зависимостей через конструктор объекта. Классика. Все мы делали это. А дальше Марк задаётся вопросом: а как быть в с ФП? Конструктора у нас нет, а значит все параметры нужно передавать на вход функции. Это неудобно, наш API становится чудовищным.

Первое, что приходит в голову, это частичное применение. Напишем функцию с 4 параметрами, первые 3 из которых это зависимости (код на F#):


let tryAccept capacity readReservations createReservation reservation =
let reservedSeats =
readReservations reservation.Date |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then createReservation { reservation with IsAccepted = true } |> Some
else None



«Приклеим» зависимости


let tryAcceptComposition =
let read = DB.readReservations connectionString
let create = DB.createReservation connectionString
tryAccept 10 read create


На выходе имеем функцию tryAcceptComposition в которую уже внедрены зависимости и остался один входной параметр reservation.

Дальше Марк делает классный трюк, и превращает код из F# в C# средствами .NET (через его промежуточное представление IL). И код на C# выглядит как обычный объект с внедрением в конструкторе!

Решена ли задача? Можно ли сказать, что частичное применение решает задачу внедрения зависимостей в ФП? Марк предлагает решить спор используя Haskell. F# язык хороший, но он позволяет много больше, чем «настоящие» ФП языки. И что же у нас происходит в Хаскеле? Если мы объявим tryAccept чистой функций, то код не скомпилируется. Потому что зависимости несут сайд-эффекты (походы в базу данных).

Т.е. частичное применение решает вопрос внедрения зависимостей, но оно делает код нефункциональным. Чтобы функции остались чистыми, мы должны отказаться от внедрения зависимостей. И тут Марк переходит к последнему шагу. Он переписывает tryAccept так, чтобы на входе были только «чистые» значения:


let tryAccept capacity reservations reservation =
let reservedSeats = reservations |> List.sumBy (fun x -> x.Quantity)
if reservedSeats + reservation.Quantity <= capacity
then { reservation with IsAccepted = true } |> Some
else None


Эта функция не требует внедрения зависимостей, в ней нет сайд-эффетов. Сайд-эффекты поднимаются на уровень функции-композиции, в ней происходит вся «грязь»


let flip f x y = f y x

let tryAcceptComposition reservation =
reservation.Date
|> DB.readReservations connectionString
|> flip (tryAccept 10) reservation
|> Option.map (DB.createReservation connectionString)


В итоге Марк постулирует, что функциональное программирование должно отказаться от понятия внедрения зависимостей. Чистые функции не могут вызывать нечистые функции. Мы должны оставить наше ядро чистым и поднять всё нечистое до уровня границы с внешним миром (и снова привет тебе, архитектура портов и адаптеров).
👍35🤔123🤮2
Так, мне нужен ваш опыт

Подскажите хорошие примеры качественной работы с текстами и переводами в опенсорс-проектах? Вот чтобы не просто
md
и
json
файлы абы как коммитили, а был построенный процесс, как во взрослых коммерческих проектах.

Под процессом я понимаю примерно следующее:

- Изменение или добавление ключей в ветке блокирует пулл-реквест;
- Приходят переводчик и техпис, забирают тексты в свою систему;
- По готовности текстов они выгружаются обратно и коммитятся автоматикой в ветку PR;
- Блок снимается, PR заезжает в main.

Это значит, что где-то нужно поднять платформу локализации (тот же Weblate), как-то удобно следить за текстами, понимать статус задачи на вычитку/перевод. Хочу посмотреть, как это устроено в других проектах.
16👍2
Как мы ничему не научились на примере жизни и смерти Yarn

Статья от Джареда Вилкарта про Bun в моём любимом жанре «дедовское брюзжание». Как многие опытные программисты знают — выбирать надо скучные технологии. И сидя на берегу дождаться, пока мимо проплывут останки недавно хайповой штуки.

И вот Джаред проводит параллели между Yarn и Bun:

— продают «скорость»,
— раскалывают экосистему,
— не про обратную совместимость,
— в стабильной 1.0 версии не поддерживают Windows.

Yarn на старте был быстрее npm. Но npm догнал его по скорости, а создателям Yarn пришлось объяснять, что вообще-то они были не про перформанс, а про фичи. Сложно конкурировать с владельцем npm-серверов.

В итоге, все фичи yarn внедрены в npm и npm ещё и быстрее (тут Джаред почему-то забывает про Plug'n'Play, который пусть не сразу, но появился в Yarn, но так и не был реализован в npm). Да, есть нюансы, кому-то они важны, но для большинства людей подходит npm.

Вот и Bun — он не делает ничего, что нельзя было бы достичь в Node.js не ломая обратную совместимость. Так что в какой-то момент Node.js скорее всего получит паритет по скорости. И маркетинговая шумиха про скорость сойдёт на нет.

Ок, Yarn пришёл, пошумел и умер. В процессе подстегнул npm. В чём проблема? В том, что пока Yarn шумел и продавал функции, которые на самом деле в большей степени были нужны только Facebook, команде npm пришлось гнаться за ним и добавлять схожие фичи, чтобы экосистема не раскололась сильно. При этом были изменены приоритеты, фактически Facebook косвенно повлиял на порядок внедрения фичей в npm.

А дальше Yarn проник в Readme. Куча проектов стала ориентироваться на Yarn и писать инструкции, как развернуть их с помощью Yarn. Смущая новичков и тратя время синьоров на объяснения, почему в наш конкретный проект так ставить зависимости не нужно.

Вместо того, чтобы контрибьютить в npm Facebook потратил силы на создание собственной его копии. И ради чего?

Но bun гораздо опасней

Bun предлагает скорость и опасные фичи:

1. Макросы — ваша сборка теперь гвоздями прибита к Bun
2. bun.x API. Собственные «более быстрые» API. Ваш код будет «отравлен» ими. Придётся ставить зависимости — полифиллы. Ура, ещё одна зависимость.
3. Встроенную поддержку мета-языков. Тут подробнее.

Мета-языки временны. Их задача сделать программирование удобней, пока основной язык не дотягивает. Как только возможностей основного языка достаточно, мы отстреливаем мета-язык. Как выкинули CoffeeScript, как многие отказываются от Sass, потому что CSS сам по себе уже достаточно неплох. Но вот в Bun теперь встроен ужасный JSX и TypeScript.

А TS уже прошёл свой пик. Графики показывают первые признаки разворота сообщества с сторону более лёгких альтернатив, таких как eslint-plugin-jsdocs, а на горизонте маячит добавление статической типизации на комментариях в ES202X. В какой-то момент TS может сказать, что его работа закончена. Sass тут отличный пример — из популярнейшего дефолтного инструмента для всех он уходит в сторону узкоспециализированного продвинутого инструмента для профи.

А если бы Bun вышел в 2019 году на пике популярности Sass, то Sass был бы встроен в него. И что бы они делали в момент смены API? Вы уже не можете написать npm install <версия Sass>. Не нужно прибивать мета-языки к рантайму.

Bun приносит абстракции для кучи технологий, но он не абстрагируется от этих технологий. Он не берёт что-то сложное и делает это проще и универсальней — нет, он засовывает это в себя как есть. И всегда будет отставать от оригиналов (нужно следить за изменениями API и добавлять код в свою реализацию). При этом абстракции эти находятся в критически важных местах: установка зависимостей, тесты и сборка.

Дальше Джаред пишет про Windows. Сборка под неё экспериментальная и обещают позже дать стабильную. И Джаред сомневается, что столь небольшая команда сможет одновременно догонять фичи для Windows и пилить новые в Linux/OSX. А не пилить фичи нельзя. И как-то придётся выравнивать версии. Возможно через год у нас будет v1.8 для Linux и v1.0 для Win.
👍75🤡6👎42🤔2💯2😁1
А мир во фронтенд-разработке меняется достаточно быстро. Как скоро мы увидим конкурента Vite? Как скоро уйдём с ESBuild? Внедрит ли Bun новые абстракции и будет ли поддерживать старые? Или просто удалит их?

А если мы нашли проблема в JS Runtime — можем ли мы обновить рантайм, не потеряв инструменты, на версии которых мы завязались? О нет. Кажется нужно всё переписывать.

Что будет, например, когда запустят JavaScript Shadow Realms? Vitest уже ждёт их, готов использовать. Вот только Bun будет ждать, пока Shadow Realms прорастут в WebKit. Что будет в этот промежуток с совместимостью с Vitest? (Джаред забывает, что первая реализация Shadow Realms внедрена как раз в WebKit. Но пример достаточно корректный, так как позже имплементация была убрана за флаг, потому оставим тут).

Слишком много инструментов в одном. И, при этом, в обойме нет инструмента управляющего версиями этих кусочков.

• Если бы Bun вышел в 2012 году, в него был бы встроен Grunt.
• Если бы Bun вышел в 2014 году, в него был бы встроен Gulp.
• Если бы Bun вышел в 2016 году, в него был бы встроен Webpack.
• Если бы Bun вышел в 2018 году, в него был бы встроен Rollup.
• Если бы Bun вышел в 2020 году, в него был бы встроен ESBuild.
• Если бы Bun вышел в 2026 году, в него был бы встроен ...

Это не значит, что Bun отстой. Bun хорош. Но седые и строгие деды уже чуют запах будущих проблем. Прогноз Джареда, что Bun будет с нами лет 5, прежде чем все про него забудут. Ну а все проекты, которые Bun встроил в себя и ускорил — наверстают упущенное за год.
👍509🔥8🤔4🌚2
Смотрите, что подвезли в Телеграм Beta

```javanoscript
console.log('Hello world');
```
🔥198👍267🤯1
История про баг в Safari

Недавно решил поправить browserslist в проекте и оторвал правило Chrome >= 72 как явно для нас устаревшее. После релиза получаю всплеск жалоб от пользователей Safari 15 (их много!). Бегу проверять, вижу ошибку (самое смешное, что ошибка не проявляется при включенных девтулз), откатываюсь. Дальше мучительный поиск проблемы.

Прописываю Chrome >= 74 — бага есть. Chrome >= 73 — баги нет. Ясно, дело в полях классов. Начиная с Chrome 74 у нас есть полная поддержка публичных и статических полей классов, полифилл больше не нужен. Но в Safari 15 тоже полная поддержка! Can I Use врать не будет же. Где же баг и почему его не лечит правило Safari >= 15?

Долго ищу как запустить Safari 15. Проблемное место нахожу достаточно быстро — это описанные через static propTypes, в которые прилетает внешнее значение/ссылка. Вот это место

Ищу дальше. Да, в Safari 15 есть такой баг! https://bugs.webkit.org/show_bug.cgi?id=236843 Поля классов в нём поддерживаются, но иногда не работают.

Остаётся понять последнее, почему preset-env не помогает? Ищем дальше. А вот оно как, в Babel заведена ишью уже больше года как. В комментах и @valya_reads_issue отметился. Как же лечить? Вот, например, так, как сделали в Графане. Прописать @babel/plugin-transform-class-properties в плагины.

Мораль тут такая, что спецификации спецификациями, но тестировать надо на реальных браузерах.
😨32👍136😱5🤣4😢3
Почитайте тоже https://news.1rj.ru/str/valya_reads_issue/329

TL;DR «Начиная с 7.22.6 в @babel/compat-data указано, что class properties поддерживаются в iOS 14.5, а до этого было указано что в iOS 15, т.е. с Safari 15 сдаунгрейдили поддержку до Safari 14.1. Напомню, без багов эта фича работает начиная с Safari/iOS 16. »
👍6😨31
После раскрытия кода Даталенс весь ноябрь проходит в каком-то бесконечном девреле. В декабре финальное, расскажу на YaTalks докладик и, надеюсь, эту тему пока поставить на паузу. Хотя бы до января, снежок же выпал, склоны запустились, найти бы свободный выходной.

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

Не лезь туда, оно тебя сожрёт! Но тебе даже понравится.
👍274😁3🔥1
Про билд-секреты в докере

Давно хотел написать. Вот есть задача закинуть секреты в docker build. Это не рантайм-секреты, это секреты необходимые только на этапе билда. В итоговом образе они светиться не должны (как и любые секреты).

Как тут правильно поступить? --build-arg (ARG в Dockerfile) не подходит для передачи секретов, запомните это. Достаточно docker history --no-trunc <img> и вот они, секреты, как на ладони. Значит, какие у нас варианты:

1 Вытягивать секреты из секретницы в самом билде — не всегда возможно;
2 Multi-stage билд — может существенно замедлить сборку;
3 Закинуть секреты через встроенный механизм докера!

Как оно работает. Создаём файл с секретами. Например, .secrets. Обычный текстовый файл, куда мы закинем секреты строчка за строчкой.


cat <<EOT > .secrets
SUPER_SECRET_1=$SUPER_SECRET_1
SUPER_SECRET_2=$SUPER_SECRET_2
EOT


Включаем BuildKit через env DOCKER_BUILDKIT=1. Если у ваc Docker >= 23.0 то BuildKit включен по умолчанию.

Скармливаем файл с секретами:


DOCKER_BUILDKIT=1 docker build --secret id=secrets,src=.secrets .


В Dockerfile монтируем секреты в RUN и загоняем их в env


RUN --mount=type=secret,required=true,id=secret,target=./.secrets \
export $(cat .secrets) > /dev/null && \
npm run build


Можно не только через файл, но и через ENV но это мне кажется наименее удобным.
🔥82👍19
Satechi делает много классных вещей, но вот именно эти два кабеля меня в дороге выручают постоянно: длинный type-c с переходником на HDMI и супер-короткий type-c на lightning
👍51
Forwarded from Веб-стандарты (Vadim Makeev)
Приходите в субботу 16 декабря в 12:00 (UTC+3) на стрим подсмотреть как мы записываем 400-й эпизод Веб-стандартов вживую и обсуждаем новости фронтенда за неделю. Обычный эпизод, ничего такого 🤓

https://youtube.com/live/-QyzkZ0sHRA
👍33🔥13🥱1🍾1
Я как-то уже писал, что полностью перешёл на разработку на удалённой linux-машине. В VSCode работает прекрасно, позволяет бесшовно жить на два ноута (офисный 16" и домашний/дорожный 14"). Но вот ещё что важно, мои ноутбуки на M1. А это, помимо всех плюсов, и минусы:

- относительно тормозной Докер (ещё и платный, в случае Docker Desktop/OrbStack)
- проблемы с нативными биндингами node.js

Второй момент проявляется так. Запускаем приложение и ловим какой-нибудь dyld[42703]: missing symbol called. Дальше два варианта: забить и переустановить все зависимости с --target_arch=x64 или найти виновника, и понять, что делать дальше: поднимать версию, выкидывать и менять на другую реализацию, форкать, поднимать транзитивные через override и т.д. Не самое приятное развлечение.

Из хорошего то, что таких случаев всё меньше и меньше, да и Rosetta 2 получилась удивительно хорошей. Но всё же тонкие клиенты — это кайф. Пока не сядешь в поезд.
👍44🔥7😁6🤔1
Пока ещё пишу итоги (ну ждёте же?). Прервался на запись просто огромного новогоднего выпуска Веб-стандартов. С видео. Как вы любите.

Как Вадим будет это всё монтировать — даже не знаю. Пошлите ему лучиков поддержки.
🔥89🎄17💩1095🦄1
Итоги 2023

Жизнь и около

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

Почти не пропускал подкаст. 35 эпизодов по 2 часа + ~1.5 часа подготовки. 122,5 часа получается. Нехило. Хорошо, что монтирует Вадим.

Примерно 140 часов провёл в дороге. Обычно работал. Перевёл домашний 14” ноутбук в режим рабочего. В дороге-то самое оно.

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

Много плавал, регулярный бассейн для спасения спины. Купил сап, штука ленивая, но приятная. В гидрашке даже в сентябре хорошо.

На сноуборде катался до середины марта и открыл сезон с первых чисел декабря. В конце прошлого сезона обновил доску (прошлой уже лет 15 минимум было. Ох ты ж). Сменил крепы Flow на классику, сначала чуть не плакал, но сейчас уже привык.

Программирование

Вернулся в ШРИ, сделал лекцию по node.js. Одной лекции явно недостаточно, весь материал не запихнуть, добивал внезапным мастер-классом, но всё равно. Надо что-то сделать тут.

По работе — много ковырял node.js, девопсил. Мало трогал UI, в основном чинил баги. Всё как люблю. Плакал от багов gRPC. Настраивал Webpack, выравнивал зависимости. Будни фронтендера.

Полностью поменял воркфлоу. Слез с Idea/WebStorm и полюбил VSCode. vim конечно никуда не делся, когда надо поковырять файлики. Вообще, уменя ощущение, что сейчас мы видим начало конца традиционных больших IDE, вместо них снова приходят текстовые редакторы, но дополненные LSP, LLM-моделями и плагинами.

Перешёл на разработку на удалённой машине (отчасти следствие перехода на arm-процессоры, работать локально на маке стало больней). Разрабатывать прямо в linux со всеми сетевыми доступами — счастье. Перестал носить с собой ноут каждый день.

Разочарование года — декораторы в TypeScript. Ждали, ждали, они вышли и что? Будем ждать нативных.

Боль года — ESM. Очень больно. Ну вы и сами знаете.
57👍16
Техника и гаджеты

Традиционно раз в три года обновил телефон. Дождался падения цен на iPhone 15 (не про) и взял. Ожидаемо ничего нового, но type-c, хорошая камера и dynamic island дают радость новизны. Type-c вообще провоцирует на эксперименты «а если я в тебя вот это воткну, то что получится?». Докупил кошелёк — подставку от Moft. Удобно! Лучший недорогой гаджет в этом году.

Андроид обновлять не стал. Pixel 5A в целом справляется с задачей поглядеть на приложения, а как основную OS для жизни я Андроид рассматривать всё ещё не могу. Хотя уже близко.

Основной клавиатурой в этом году стала NuPhy Air 75. Так как работаю в основном в офисе, то взял на красных. Сойдёт. Хотя отсутствие на ней F5-F6 без Fn — огромный недостаток.

Самая бесполезная покупка года — iPad mini. Продал. Обычный iPad Pro 11 так же пылится в шкафу. Не буду говорить, что планшеты это тупиковая ветвь развития, многим они заходят. Мне пока никак.

RØDECaster Duo. Это король. Запись подкастов уже не будет прежней.

Shure SM7B — перешёл на классику. Окончательно понял, что проблема не в микрофонах, а в моём голосе. Но всё равно приятно. Такой у меня и у Майкла Джексона (был).

В рюкзаках перешёл на роллтопы. Раньше посматривал на них с сомнением (где же мои 50 кармашков), но понял, что кроме ноутбука ношу только продукты. Зато если нужно, то влазит и куртка и вообще всё влазит. Взял для города Lefrik Roll и для поездок Pinqponq Block Medium.

Интернет

Интернет для меня схлопнулся до Телеграма, Гитхаба и инди-блогов. Спасибо каналам в Телеге, что вернули ощущение тёплой ламповости того, олдскульного веба. Хотя это конечно не веб, надо это понимать 🙂 Зато в Телеге не так стыдно не уметь писать.

Книги
Читал катастрофически мало. Ну очередной Пелевин, конечно, как без него. «Бронепароходы» Иванова не дочитаны (хотя очень хочется дочитать). Очередной занудный графоманский Стивенсон («Падение, или Додж в Аду») не дочитан. «Однажды в Голливуде» Тарантино — не дочитана. Что-то с этим надо делать.

Фильмы
Запомнил только «Всё, везде и сразу».

Ну вот вроде и всё. Прощай 2023, скучать не буду.
84👍31🍾12
Притча про монорепы

Приходит молодой программист к седому опытному гуру и жалуется: «О умнейший из фронтендеров, у меня такая тяжелая жизнь, у меня 10 проектов, все связаны зависимостями, постоянно всё разъезжается везде... кошмар...»
Седой и строгий отвечает: «Собери все проекты в монорепу»
Программист: «Какую монорепу? Зачем? Как я ее в гитхаб положу!!!???»
Опытный: «Сделай монорепу»

Программист подумал-подумал, прикинул плюсы и минусы, пошел и сделал монорепу.
Через неделю приходит к опытному, тот его спрашивает «Ну, как жизнь»? Программист заламывает руки, кричит : «Еще хуже стало, эта монорепа чёртова, тулинг ужасный, все PR и ишью вперемешку, все тесты ломаются на каждый чих, всё тормозит... ужас!»
Умный почесал бороду и говорит: «Удали монорепу»
Программист страшно удивляется: «Что??? Зачем же я ее делал???"»
Опытный продолжает напирать: «Удали монорепу»
Программист подумал, подумал, пошел и удалил монорепу.

Через неделю возвращается программист к высокогрейдовому гуру и чуть не плачет от счастья: «Боже, друг, как же мне хорошо...»
😁156🥴12👍4🍓32🤓21🤡1
А я напомню, что таких долгоживущих веток делать конечно же не надо. Хорошая ветка живёт день-два и уезжает в main (ну или в версию, если у вас одновременно несколько веток живёт).

И не забываем ребейзить и сквошить.

https://news.1rj.ru/str/mefody_dev/119
💯28👎3🤔2🤝2😁1
Хорошее замечание, что при таком подходе можно перегрузить QA. Ответ тут в том, что QA не должны быть узким местом. Разбираем монолиты на библиотеки и микросервисы, покрываем всё автотестами, подключаем ручное QA только в критичных местах, либо на релизную ветку.

Цель CI в том, чтобы код постоянно вливался и шарился между всеми. Чем раньше мы упрёмся в проблему, тем менее она болезненна. К сожалению, это не особо совместимо с ручным QA, либо придётся приставить по одному QA к каждому разработчику. И что должен этот QA делать с неготовой задачей, закрытой флагом от прода? Только проводить регрессы и смоуки. А с этим автоматика отлично справляется.
👍27