Наткнулся на гитхабе на экспериментальную библиотеку, улучшающую читаемость скаловых стектрейсов
https://github.com/VirtusLab/stacktracebuddy
Стектрейсы у ошибок в скале перегружены нерелевантной информацией из байткода jvm, поэтому докапываться в них до источника проблемы — то ещё удовольствие. А эта библиотека вычищает всё лишнее и обогащает трейсы типами лямбд и именами джарников.
Делается это забавным образом: джавовый стектрейс содержит имя файла и номер строки кода. По этим данным ищется соответствующий TASTy файл, сгенерированный компилятором, и из него извлекается скала-специфичная информация.
К проду не готово, да и перфоманс не блещет (на каждый стектрейс читается TASTy), но концептуально красиво.
https://github.com/VirtusLab/stacktracebuddy
Стектрейсы у ошибок в скале перегружены нерелевантной информацией из байткода jvm, поэтому докапываться в них до источника проблемы — то ещё удовольствие. А эта библиотека вычищает всё лишнее и обогащает трейсы типами лямбд и именами джарников.
Делается это забавным образом: джавовый стектрейс содержит имя файла и номер строки кода. По этим данным ищется соответствующий TASTy файл, сгенерированный компилятором, и из него извлекается скала-специфичная информация.
К проду не готово, да и перфоманс не блещет (на каждый стектрейс читается TASTy), но концептуально красиво.
Forwarded from Scala Nishtyaki Channel
Рибята, это скала 3 релиз подкрался? https://github.com/lampepfl/dotty/releases/tag/3.0.0
GitHub
Release 3.0.0 · scala/scala3
Release blog post at https://www.scala-lang.org/blog/2021/05/14/scala3-is-here.html
Changelog from 3.0.0-RC3
Fix typo in file name #12181
Tasty: set experimental to zero #12438
Contributors
Thank...
Changelog from 3.0.0-RC3
Fix typo in file name #12181
Tasty: set experimental to zero #12438
Contributors
Thank...
Постов давно не было, потому что ушёл в чтение литературы по управлению. Дочитал супер-крутую книжку по менеджменту: Первые 90 дней (Майкл Уоткинс). Максимально содержательное чтиво, ни капли воды. Систематизированное повествование о том, что руководитель должен сделать в свои первые три месяца на новой должности. Хотя акцент сделан на адаптационном периоде, это самые качественно структурированные знания по руководству как таковому. Поэтому читать книгу есть смысл в любой карьерный момент.
Несмотря на то, что в книге описываются ситуации, свойственные уровню топ-менеджмента, начинающие тимлиды и программисты, размышляющие о переходе в управление, найдут для себя тонны ценной информации. Жалею, что прочитал её только сейчас, а не до того, как сам стал лидом. Фактически это инструкция по вступлению в должность, с которой можно избежать набивания собственных шишек.
Во время чтения собирал конспект, но однозначно рекомендую читать оригинал, потому что информация в нём и так подаётся в лаконичном виде.
Несмотря на то, что в книге описываются ситуации, свойственные уровню топ-менеджмента, начинающие тимлиды и программисты, размышляющие о переходе в управление, найдут для себя тонны ценной информации. Жалею, что прочитал её только сейчас, а не до того, как сам стал лидом. Фактически это инструкция по вступлению в должность, с которой можно избежать набивания собственных шишек.
Во время чтения собирал конспект, но однозначно рекомендую читать оригинал, потому что информация в нём и так подаётся в лаконичном виде.
В EPFL не только релизят третью скалу, но и продолжают шатать монадки. Вслед за заходами в async/await и effects as abilities появилась экспериментальная библиотека Monadic Reflection (от создателя не менее экспериментального scala-effect).
И это очередная попытка избавиться от необходимости писать
Библиотека работает только с Project Loom (если до сех пор не знаете о Loom, бегом читать / смотреть). Каждый шаг монадической композиции запускается на лумовом
Кажется, в EPFL понимают, что монады — это паттерн императивного программирования, и всячески пытаются срезать синтаксические излишки, чтобы избавиться от разницы между «обычным» императивным кодом и завёрнутым в монадки.
Выглядит интересно, и возможно такие эксперименты приведут индустрию в светлое будущее со ссылочной прозрачностью императивного кода без накладных расходов на синтаксис. Но на мой взгляд написание флэтмапов не сильно снижает продуктивность разработчика, поэтому непонятна выгода от их оптимизации. Те же abilities выглядят интереснее.
И это очередная попытка избавиться от необходимости писать
flatMap или for-comprehension при работе с монадками. То есть вместо forПредлагается написать
_ <- f()
_ <- g()
yield ()
f()А дальше оно само скомпозится.
g()
Библиотека работает только с Project Loom (если до сех пор не знаете о Loom, бегом читать / смотреть). Каждый шаг монадической композиции запускается на лумовом
continuation. Вот примерчик с ZIO.Кажется, в EPFL понимают, что монады — это паттерн императивного программирования, и всячески пытаются срезать синтаксические излишки, чтобы избавиться от разницы между «обычным» императивным кодом и завёрнутым в монадки.
Выглядит интересно, и возможно такие эксперименты приведут индустрию в светлое будущее со ссылочной прозрачностью императивного кода без накладных расходов на синтаксис. Но на мой взгляд написание флэтмапов не сильно снижает продуктивность разработчика, поэтому непонятна выгода от их оптимизации. Те же abilities выглядят интереснее.
Мелочь, а приятно: в третьей скале можно не придумывать имена для контекстных параметров.
Контекстные параметры очень часто нужны просто чтобы прокинуть их дальше или задать ограничение на тип, поэтому в их именовании нет смысла. Так что с анонимными параметрами и когнитивная нагрузка на придумывание имени пропадает, и пространство имён не засоряется заведомо не используемыми значениями.
Подробнее о контекстных абстракциях хорошо написано в документации.
def f(fut: Future[Int])(using ExecutionContext): Future[String] =вместо
fut.map(_.toString)
def f(fut: Future[Int])(implicit ec: ExecutionContext): Future[String] =из второй скалы.
fut.map(_.toString)
Контекстные параметры очень часто нужны просто чтобы прокинуть их дальше или задать ограничение на тип, поэтому в их именовании нет смысла. Так что с анонимными параметрами и когнитивная нагрузка на придумывание имени пропадает, и пространство имён не засоряется заведомо не используемыми значениями.
Подробнее о контекстных абстракциях хорошо написано в документации.
Написал небольшую библиотеку с интеграцией ZIO и MUnit
https://github.com/poslegm/munit-zio
Мне нравится MUnit за его простоту, минималистичность и наглядные сообщения об ошибках. Чего нельзя сказать о «нативном» для ZIO zio-test: это очень сложный фреймворк с кучей ассершенов, незадокументированных методов провайдинга зависимостей и аспектов.
На мой взгляд тесты должны быть простыми, поэтому и захотелось тестировать свои монадки на MUnit.
А ещё вся документация по munit-zio умещается в README, а полной документации по zio-test в принципе не существует.
https://github.com/poslegm/munit-zio
Мне нравится MUnit за его простоту, минималистичность и наглядные сообщения об ошибках. Чего нельзя сказать о «нативном» для ZIO zio-test: это очень сложный фреймворк с кучей ассершенов, незадокументированных методов провайдинга зависимостей и аспектов.
На мой взгляд тесты должны быть простыми, поэтому и захотелось тестировать свои монадки на MUnit.
А ещё вся документация по munit-zio умещается в README, а полной документации по zio-test в принципе не существует.
scalameta.org
MUnit · Scala testing library with actionable errors and extensible APIs
Forwarded from Big Flatmappa
В экосистеме Cats Effect есть утилита Hotswap, предназначенная для управления жизненным циклом заменяемых "на горячую" ресурсов через общий ресурсный скоуп.
К сожалению, она непригодна для конкурентного использования: внутренняя стейт-машина не защищена от конкуретных попыток свопа, а релиз заменяемого ресурса не отслеживает его использование другими файберами, что легко приводит к утечке.
Для trace4cats понадобилась подобная штука, и мы с Chris Jansen сделали конкуретную обёртку над
При этом:
- конкуретные свопы (
- своп не блокируется конкуретными чтениями во время аллокации нового ресурса: как только новый ресурс создан, он может быть прочитан из других файберов;
- конкуретные доступы к ресурсу не блокируют друг друга и практически никогда не блокируется свопом, но всё же есть небольшой шанс обратиться к ресурсу именно в момент перед перезаписью ссылки на него, но не успеть захватить блокировку до того, как это сделает финалайзер в свопе.
* здесь и далее имеется в виду семантическая блокировка
Запаблишили пока отдельной либой под Scala 2.12, 2.13 и 3, правда только для CE3 🤷🏻♂️ Может быть в будущем оно переедет в
Какие уроки я вынес для себя из этой задачки:
- сложно понять cancelation и корректно учесть в коде все ситауции с отменой;
- написать такой же хороший код для CE2 сложно: там аллокация ресурса в принципе неотменяема, поэтому нельзя использовать
- написать вообще хороший конкарренси код с первого раза невозможно: мы написали с пятого — и то с между 2-й и 3-й попытками прошло много времени, прежде чем мы обнаружили проблему.
Ещё из приятного: свой первый кросс-релиз под Scala 3 сделал за несколько минут.
К сожалению, она непригодна для конкурентного использования: внутренняя стейт-машина не защищена от конкуретных попыток свопа, а релиз заменяемого ресурса не отслеживает его использование другими файберами, что легко приводит к утечке.
Для trace4cats понадобилась подобная штука, и мы с Chris Jansen сделали конкуретную обёртку над
Hotswap, лишённую перечисленных недостатков.При этом:
- конкуретные свопы (
swap) блокируют* друг друга, защищая внутренний Hotswap;
- каждый доступ (access) к текущей версии ресурса контролируется отдельным ресурсным скоупом: если исполнение хотя бы одного файбера находится внутри такого скоупа, ресурс гарантированно не будет финализирован при свопе — своп заблокируется, пока ресурс не будет освобожден всеми пользователями;- своп не блокируется конкуретными чтениями во время аллокации нового ресурса: как только новый ресурс создан, он может быть прочитан из других файберов;
- конкуретные доступы к ресурсу не блокируют друг друга и практически никогда не блокируется свопом, но всё же есть небольшой шанс обратиться к ресурсу именно в момент перед перезаписью ссылки на него, но не успеть захватить блокировку до того, как это сделает финалайзер в свопе.
* здесь и далее имеется в виду семантическая блокировка
Запаблишили пока отдельной либой под Scala 2.12, 2.13 и 3, правда только для CE3 🤷🏻♂️ Может быть в будущем оно переедет в
cats.effect.std. Критика Hotswap отражена в этом issue.Какие уроки я вынес для себя из этой задачки:
- сложно понять cancelation и корректно учесть в коде все ситауции с отменой;
- написать такой же хороший код для CE2 сложно: там аллокация ресурса в принципе неотменяема, поэтому нельзя использовать
Resource для содания и композиции отменяемых скоупов, а в CE3 есть Poll (см. разницу между withPermit в CE2 и permit в CE3 на Semaphore);- написать вообще хороший конкарренси код с первого раза невозможно: мы написали с пятого — и то с между 2-й и 3-й попытками прошло много времени, прежде чем мы обнаружили проблему.
Ещё из приятного: свой первый кросс-релиз под Scala 3 сделал за несколько минут.
Big Flatmappa
В экосистеме Cats Effect есть утилита Hotswap, предназначенная для управления жизненным циклом заменяемых "на горячую" ресурсов через общий ресурсный скоуп. К сожалению, она непригодна для конкурентного использования: внутренняя стейт-машина не защищена от…
👆Новый канал про монадки, спешите подписаться!
Ковырялся на работе с тапиром, не понравилось. tapir — это популярный в Scala-мире DSL для описания HTTP эндпоинтов. DSL интерпретируется в “настоящие” эндпоинты на одном из четырёх доступных веб-серверов и автоматически генерирует спецификацию в OpenAPI. Собственно, ради автогенерации сваггера мы и затащили его в один REST-сервис. Руками OpenAPI описывать всё-таки нудно и ненадёжно, а gRPC не подходил по требованиям к сервису.
Основную боль причинила аутентификация: она дырявая и неудобная. Тапир сначала парсит метод и путь запроса, а только потом проверяет наличие Auth-заголовка. Значит злоумышленник может пореверс-инжинирить контракт, получая осмысленные 400 и 404 вместо 401. Если написать код аутентификации так, как предлагает документация, сервер ещё и тело запроса парсит 🤦♂️. Уязвимость с телом я обошёл костылём, а вот чтобы заткнуть дыру с парсингом пути, пришлось кинуть PR (надеюсь, примут). Правда код из документации всё равно останется дырявым by design, извольте писать костыли.
Следующая боль — маппинг ошибок. Тапир заставляет маппить эксепшены в HTTP-коды один к одному. При этом компиляторных гарантий полноты маппинга нет… Естественно, всё многообразие ошибок бизнес-логики 1-к-1 на HTTP-коды не замаппишь, поэтому приходится делать промежуточную ADT с сетевыми ошибками, а уже её маппить в коды.
Но и такой маппинг нельзя красиво встроить в код эндпоинтов, потому что в тапире нет абстракции для middleware! Поэтому всякие маппинги ошибок, логирование и тд приходится вкорячивать либо непосредственно в веб-сервер (если до него дойдёт всё, что хочется залогировать), либо костылить всратыми адхоками.
Спасибо, Господи, за gRPC и GraphQL.
Основную боль причинила аутентификация: она дырявая и неудобная. Тапир сначала парсит метод и путь запроса, а только потом проверяет наличие Auth-заголовка. Значит злоумышленник может пореверс-инжинирить контракт, получая осмысленные 400 и 404 вместо 401. Если написать код аутентификации так, как предлагает документация, сервер ещё и тело запроса парсит 🤦♂️. Уязвимость с телом я обошёл костылём, а вот чтобы заткнуть дыру с парсингом пути, пришлось кинуть PR (надеюсь, примут). Правда код из документации всё равно останется дырявым by design, извольте писать костыли.
Следующая боль — маппинг ошибок. Тапир заставляет маппить эксепшены в HTTP-коды один к одному. При этом компиляторных гарантий полноты маппинга нет… Естественно, всё многообразие ошибок бизнес-логики 1-к-1 на HTTP-коды не замаппишь, поэтому приходится делать промежуточную ADT с сетевыми ошибками, а уже её маппить в коды.
Но и такой маппинг нельзя красиво встроить в код эндпоинтов, потому что в тапире нет абстракции для middleware! Поэтому всякие маппинги ошибок, логирование и тд приходится вкорячивать либо непосредственно в веб-сервер (если до него дойдёт всё, что хочется залогировать), либо костылить всратыми адхоками.
Спасибо, Господи, за gRPC и GraphQL.
Задача (де)сериализации структур в json решается тремя способами:
1. Проанализировать поля в рантайме с помощью рефлексии;
2. "Заранее" статически проанализировать структуры и нагенерировать для них кодеки;
3. Переложить все поля класса в json и обратно руками :)
В Scala по первому пути идёт, например, старая библиотека json4s. Но рантайм-рефлексия работает в несколько раз медленнее заранее сгенерированного кода, а сериализация частенько становится узким местом высоконагруженных приложений. Поэтому сообщество сместилось в сторону второго подхода, который реализует библиотека circe.
Паттерн у генерации всяческих сериализаторов на Scala примерно одинаковый: объявляется тайпкласс с дефолтными инстансами для примитивов (String, Int, Boolean, etc...) и пользовательскими инстансами для своих типов. Для кейс-классов макросом (или встроенной деривацией в Scala 3) выводятся составные инстансы, в которых поля структуры сопоставляются полю в json и конвертируются кодеком для типа поля.
Результирующий код в рантайме ведёт себя так же быстро как перекладывание руками, но при этом кодек не нужно писать и поддерживать самостоятельно.
А вспомнил я об этом, потому что наткнулся на библиотеку ffjson, которая решает те же проблемы в голанге. Стандартный пакет использует рантайм-рефлексию, поэтому ffjson его обгоняет. Только вместо макросов там кодеки просто кодогенерируются перед сборкой проекта. Языки разные, а проблемы у всех одинаковые :)
1. Проанализировать поля в рантайме с помощью рефлексии;
2. "Заранее" статически проанализировать структуры и нагенерировать для них кодеки;
3. Переложить все поля класса в json и обратно руками :)
В Scala по первому пути идёт, например, старая библиотека json4s. Но рантайм-рефлексия работает в несколько раз медленнее заранее сгенерированного кода, а сериализация частенько становится узким местом высоконагруженных приложений. Поэтому сообщество сместилось в сторону второго подхода, который реализует библиотека circe.
Паттерн у генерации всяческих сериализаторов на Scala примерно одинаковый: объявляется тайпкласс с дефолтными инстансами для примитивов (String, Int, Boolean, etc...) и пользовательскими инстансами для своих типов. Для кейс-классов макросом (или встроенной деривацией в Scala 3) выводятся составные инстансы, в которых поля структуры сопоставляются полю в json и конвертируются кодеком для типа поля.
trait Encoder[T] {
def encode(obj: T): Json
}
implicit val stringEncoder: Encoder[String] =
(str: String) => Json.fromString(str)
@JsonCodec case class Sample(stringValue: String)Результирующий код в рантайме ведёт себя так же быстро как перекладывание руками, но при этом кодек не нужно писать и поддерживать самостоятельно.
А вспомнил я об этом, потому что наткнулся на библиотеку ffjson, которая решает те же проблемы в голанге. Стандартный пакет использует рантайм-рефлексию, поэтому ffjson его обгоняет. Только вместо макросов там кодеки просто кодогенерируются перед сборкой проекта. Языки разные, а проблемы у всех одинаковые :)
Поигрался с match types в Scala 3. Сильно хотел использовать их для определения зависимости возвращаемого типа функции от типа аргумента, но не прокатило. Не понравилось, что матчинг при использовании типа происходит в рантайме, поэтому можно словить исключение
Полный пример в Scastie. Для переменной
Второе следствие матчинга в рантайме — потеря ленивости аргументов:
Полный пример в Scastie.
Пока не понимаю, является ли матчинг в рантайме следствием фундаментальных ограничений языка. Но вообще хотелось бы иметь возможность без костылей сделать зависимую типизацию для своей функции, просто разматчив тип аргумента.
Появление summonFrom и transparent inline позволяет накостылить нечто подобное чуть менее вербозно, чем в Scala 2, но всё равно не интуитивно.
Пример на Scala 2: https://github.com/zio/zio/issues/5241
Он же на Scala 3: https://scastie.scala-lang.org/EwfBu7rcTwi6UQ11VYMwEQ
Несмотря на то, что эта штука работает, выглядит она не как нативная языковая
конструкция, а как насилие над компилятором.
MatchError:type Invert[T] = T match
case String => Int
case Int => String
def invert[T](t: T): Invert[T] =
t match
case s: String => s.length
case i: Int => i.toString
val test = invert(false) // упадёт в рантайме
Полный пример в Scastie. Для переменной
test компилятор выводит тип Invert[Boolean], но не проверяет, есть ли такая ветка в определении типа. В итоге код компилируется, но падает при запуске.Второе следствие матчинга в рантайме — потеря ленивости аргументов:
type Eval[T] = T match
case Any => "do nothing"
def eval[T](t: => T): Eval[T] =
t match
case _: Any => "do nothing"
val a = eval {
println("oooops")
42
}
Полный пример в Scastie.
Пока не понимаю, является ли матчинг в рантайме следствием фундаментальных ограничений языка. Но вообще хотелось бы иметь возможность без костылей сделать зависимую типизацию для своей функции, просто разматчив тип аргумента.
Появление summonFrom и transparent inline позволяет накостылить нечто подобное чуть менее вербозно, чем в Scala 2, но всё равно не интуитивно.
Пример на Scala 2: https://github.com/zio/zio/issues/5241
Он же на Scala 3: https://scastie.scala-lang.org/EwfBu7rcTwi6UQ11VYMwEQ
Несмотря на то, что эта штука работает, выглядит она не как нативная языковая
конструкция, а как насилие над компилятором.
Lil Functor
Поигрался с match types в Scala 3. Сильно хотел использовать их для определения зависимости возвращаемого типа функции от типа аргумента, но не прокатило. Не понравилось, что матчинг при использовании типа происходит в рантайме, поэтому можно словить исключение…
Добрый человек в комментах подсказал, что первая проблема решается флагом
-Ycheck-all-patmat. Очень странно, что он не включен по дефолту.Напоминаю, что Яндекс.Вертикали нанимают скалистов!
Мы делаем три площадки объявлений: auto.ru, Я.Недвижимость и Я.Объявления. Подробный рассказ о RSU, техническом стеке и стульях Herman Miller можно прочитать в вакансии: https://telegra.ph/Vakansiya-behkend-razrabotchika-na-Scala-03-04
Со своей колокольни могу добавить, что вам особенно нужно в Вертикали, если:
– вы планируете переход из разработки в управление. В этом случае у вас будет синергия с постоянной потребностью лидов разработки в Вертикалях;
– вы вэлью-челик с интересом к продукту и сильной технической базой. Вам будет комфортно и не скучно работать в продуктовых командах;
– вы хотите перейти из джавы в скалу. У нас есть опыт адаптации джавистов, а размер компании обеспечит плавный переход;
– вы работаете в стартапе и хотите попробовать бигтех на вкус. Вертикали достаточно небольшой юнит по меркам Яндекса, поэтому шока от перехода в корпорацию почти не будет. А вот все плюшки — будут.
Резюме и вопросы присылайте в лс -> @poslegm
И самое главное: нельзя. игнорировать. тотал.
Мы делаем три площадки объявлений: auto.ru, Я.Недвижимость и Я.Объявления. Подробный рассказ о RSU, техническом стеке и стульях Herman Miller можно прочитать в вакансии: https://telegra.ph/Vakansiya-behkend-razrabotchika-na-Scala-03-04
Со своей колокольни могу добавить, что вам особенно нужно в Вертикали, если:
– вы планируете переход из разработки в управление. В этом случае у вас будет синергия с постоянной потребностью лидов разработки в Вертикалях;
– вы вэлью-челик с интересом к продукту и сильной технической базой. Вам будет комфортно и не скучно работать в продуктовых командах;
– вы хотите перейти из джавы в скалу. У нас есть опыт адаптации джавистов, а размер компании обеспечит плавный переход;
– вы работаете в стартапе и хотите попробовать бигтех на вкус. Вертикали достаточно небольшой юнит по меркам Яндекса, поэтому шока от перехода в корпорацию почти не будет. А вот все плюшки — будут.
Резюме и вопросы присылайте в лс -> @poslegm
И самое главное: нельзя. игнорировать. тотал.
Нашёл библиотечку OCDQuery с генерацией запросов на doobie по пользовательским моделям данных. Сама библиотека выглядит заброшенной, а вот в документации лежит сокровище — понятное описание проблематики и реализации паттерна Higher Kinded Data для моделей сущностей из БД.
https://scalalandio.github.io/ocdquery/#Initialidea
Проблема: часть колонок заполняются БД по заданным правилам (автоинкремент id, например). Соответственно, они присутствуют в модели, которая из базы читается, но бесполезны в той, которая в базу пишется. Ещё при накатывании миграций нужны не значения полей, а названия соответствующих колонок.
Можно решать это отдельными моделями на каждый вариант использования, можно накостылить
Описываем кейс-класс, поля которого лежат в контейнерах, тип которых задаётся при создании. Под каждый способ использования модели задаётся комбинация контейнеров.
Количество тайп-параметров и их комбинаций можно делать любое в зависимости от сценариев использования данных. Главное не получить комбинаторный взрыв :)
https://scalalandio.github.io/ocdquery/#Initialidea
Проблема: часть колонок заполняются БД по заданным правилам (автоинкремент id, например). Соответственно, они присутствуют в модели, которая из базы читается, но бесполезны в той, которая в базу пишется. Ещё при накатывании миграций нужны не значения полей, а названия соответствующих колонок.
Можно решать это отдельными моделями на каждый вариант использования, можно накостылить
null/Option на все колонки. А можно применить HKD.Описываем кейс-класс, поля которого лежат в контейнерах, тип которых задаётся при создании. Под каждый способ использования модели задаётся комбинация контейнеров.
case class ColumnName(name: String)
type Id[A] = A // когда поле обязательно присутствует
type UnitF[A] = Unit // когда поле будет создано базой
type ColumnNameF[A] = ColumnName // для миграций
// F для пользовательских полей
// С для полей, управляемых базой
case class User[F[_], C[_]](id: C[String], name: F[String])
type UserSelect = User[Id, Id] // все поля будут присутствовать в модели
type UserInsert = User[Id, UnitF] // поля, управляемые базой, будут заполнены Unit
type UserColumns = User[ColumnNameF, ColumnNameF] // вместо всех полей будут экземпляры ColumnNames
Количество тайп-параметров и их комбинаций можно делать любое в зависимости от сценариев использования данных. Главное не получить комбинаторный взрыв :)
Не сразу заметно, но в документации третьей скалы работает аналог Hoogle. Hoogle — это поисковый движок по библиотекам на Haskell, умеющий искать по сигнатуре функции. В документации Scala 3 тоже можно нажать на лупу и ввести, например,
Поиск сделан на библиотеке Inquire. Как подключить её в свой скаладок, не понятно. Ещё в Hoogle проиндексированы все хаскельные библиотеки, а Inquire умеет искать только по текущей.
Пока выглядит скорее как игрушка, но вот если бы в IDEA или Metals появилось аналогичное решение с поиском по сигнатурам в проекте и его зависимостях, было бы прямо круто.
Option[A] => A => Boolean: поиск найдёт функцию contains. Правда, далеко не на первом месте.Поиск сделан на библиотеке Inquire. Как подключить её в свой скаладок, не понятно. Ещё в Hoogle проиндексированы все хаскельные библиотеки, а Inquire умеет искать только по текущей.
Пока выглядит скорее как игрушка, но вот если бы в IDEA или Metals появилось аналогичное решение с поиском по сигнатурам в проекте и его зависимостях, было бы прямо круто.
От чтения тайпскриптовых ФП-библиотек (раз, два) складывается впечатление, что они проходят тот же этап, что и скалисты несколько лет назад, когда тащили всё подряд из хаскеля. Только в тайпскрипте это выглядит как будто бы ещё хуже: один только заменитель do-нотации чего стоит. В исходниках ещё много вещей, которые интересны своей изобретательностью в обходе ограничений компилятора, но болезнены в использовании.
Похоже, что "переводы" хаскеля — это проклятие всех языков с развитой системой типов, а идиоматичный инструментарий для ФП появляется только спустя годы экспериментов.
Система типов в TS при этом передовая для промышленного языка: условные типы, типы-литералы даже с поддержкой шаблонов, flow typing, пересечения и объединения типов. Часть этих фич только появилась в Scala 3, а в тайпскрипте существует уже несколько лет. Возможно, тайплевельные истории там не летят из-за интеропа с JS, который гораздо более неприятный, чем интероп с джавой в Scala-мире.
Похоже, что "переводы" хаскеля — это проклятие всех языков с развитой системой типов, а идиоматичный инструментарий для ФП появляется только спустя годы экспериментов.
Система типов в TS при этом передовая для промышленного языка: условные типы, типы-литералы даже с поддержкой шаблонов, flow typing, пересечения и объединения типов. Часть этих фич только появилась в Scala 3, а в тайпскрипте существует уже несколько лет. Возможно, тайплевельные истории там не летят из-за интеропа с JS, который гораздо более неприятный, чем интероп с джавой в Scala-мире.
Есть один супер-интересный канал с разбором пейперов по распределённым системам, на котором несправедливо мало подписчиков.
Всем советую подписаться, там о больших и сложных вещах понятным языком рассказывают. Сегодня вот вышел пост о FoundationDB.
https://t.me/shark_in_it
Всем советую подписаться, там о больших и сложных вещах понятным языком рассказывают. Сегодня вот вышел пост о FoundationDB.
https://t.me/shark_in_it
Telegram
Акула (в) IT
FoundationDB: A Distributed Unbundled Transactional Key Value Store
#shark_whitepaper
Пока я пытаюсь осилить ARIES, немного ненапряжного и очень свежего case-study от июня 2021 года. Работа про распределенное KV хранилище FoundationDB. Всех авторов перечислять…
#shark_whitepaper
Пока я пытаюсь осилить ARIES, немного ненапряжного и очень свежего case-study от июня 2021 года. Работа про распределенное KV хранилище FoundationDB. Всех авторов перечислять…
Удобнейший плагин для релизов артефактов в Maven Central sbt-ci-release переехал в организацию sbt на гитхабе и похоже стал официально рекомендованным способом автоматизации релизов.
Это здорово, потому что релизить что-то в Maven Central — долгий и болезненный процесс, а с этим плагином всё как-то само происходит.
Это здорово, потому что релизить что-то в Maven Central — долгий и болезненный процесс, а с этим плагином всё как-то само происходит.
Канал перевалил за 1000 подписчиков, очень радостное для меня число! Пока вы не успели отписаться, сделаю стандартный телеграм-пост с каналами об ИТ, которые я читаю.
* @oleg_log, @oleg_fov — Олег пишет об индустрии. Удивляюсь его продуктивности и читаю, чтобы держать руку на пульсе;
* @bigflatmappa — канал контрибутора ФП-библиотек с историями о том, что он туда контрибутит. Стоит подписаться, чтобы проникнуться духом 10х программирования;
* @yourcybergrandpa — дед ворчит на облака;
* @architect_says — дед ворчит на Agile;
* @nikitonsky_pub — Никита Прокопов ворчит на всё вокруг;
* @nosingularity — о базах данных и инструментарии для них;
* @dereference_pointer_there — личный блог без чётко очерченной тематики (но частенько про Rust);
* @pmdaily — о продуктовой разработке и взаимоотношениях программиста с бизнесом;
* @scala_channel_ru — важные новости и анонсы из мира Scala;
* @daily_ponv — в основном ссылки на сложные пейперы;
* @shark_in_it — резюме пейперов о распределённых системах и базах данных;
* @scalabin — Антон давно ничего не писал, но если вдруг напишет — точно будет интересно;
* @consensus_io — о распределённых системах.
И конечно же чаты самого дружелюбного в мире сообщества, в котором высококвалифицированные специалисты помогают всем желающим стать 10x скалистом:
@scala_ru, @scala_learn, @scala_jobs, @ru_zio, @akka_ru
* @oleg_log, @oleg_fov — Олег пишет об индустрии. Удивляюсь его продуктивности и читаю, чтобы держать руку на пульсе;
* @bigflatmappa — канал контрибутора ФП-библиотек с историями о том, что он туда контрибутит. Стоит подписаться, чтобы проникнуться духом 10х программирования;
* @yourcybergrandpa — дед ворчит на облака;
* @architect_says — дед ворчит на Agile;
* @nikitonsky_pub — Никита Прокопов ворчит на всё вокруг;
* @nosingularity — о базах данных и инструментарии для них;
* @dereference_pointer_there — личный блог без чётко очерченной тематики (но частенько про Rust);
* @pmdaily — о продуктовой разработке и взаимоотношениях программиста с бизнесом;
* @scala_channel_ru — важные новости и анонсы из мира Scala;
* @daily_ponv — в основном ссылки на сложные пейперы;
* @shark_in_it — резюме пейперов о распределённых системах и базах данных;
* @scalabin — Антон давно ничего не писал, но если вдруг напишет — точно будет интересно;
* @consensus_io — о распределённых системах.
И конечно же чаты самого дружелюбного в мире сообщества, в котором высококвалифицированные специалисты помогают всем желающим стать 10x скалистом:
@scala_ru, @scala_learn, @scala_jobs, @ru_zio, @akka_ru
Посмотрел на Ruby Russia кейноут создателя языка. Там он всерёз говорит об оптимизации языка под микробенчмарки, потому что программисты слишком серьёзно к ним относятся, и выбирают языки, которые обгоняют Ruby. То есть буквально не из-за того, что ускорение рантайма принесёт какую-то ценность, а ради увеличения привлекательности языка. Дальше рассказывал про целый роадмап повышения перфоманса Ruby: многоуровневый JIT, гранты контрибуторам за микрооптимизации. И всё это под соусом того, что «медлительность» вредит маркетингу.
И вот не понимаю: программисты действительно столько внимания уделяют синтетическим бенчмаркам? Почему?
Конечно, есть критичные к перфомансу области разработки, но они уже заняты специфичными языками: Rust, C++. На Ruby пишутся в основном веб-бэкенды, а в них, чтобы упереться в производительность *языка*, надо особо постараться. Если в сервисе что-то тормозит, то почти всегда накосячил программист, а не рантайм. На своей практике припоминаю только два случая, когда тормоза на высоких нагрузках можно было с натяжкой списать на проблемы платформы. Оба связаны с (де-)сериализацией, что характерно :). Но и они решились не переписыванием со скалы на раст, а просто заменой библиотеки и небольшими оптимизациями кода.
А что до синтетических бенчмарков: в самом популярном сравнении HTTP серверов akka-http стабильно болтается около 190-го места. При этом в проде работает нормально и кушать не просит. Если что-то и тормозит, то в коде приложения, а не фреймворка. Современное состояние индустрии таково, что фреймворк со дна бенчмарков может держать внушительную нагрузку! И это не говоря о дешёвом железе.
Поэтому в моих глазах топ причин плохого перфоманса выглядит так:
1. баг в коде;
2. ошибка конфигурации;
3. ошибка дизайна системы;
4. ... программист обосрался где-то ещё ...
5. медленный рантайм языка.
Или в руби всё настолько плохо с производительностью, что даже скала по сравнению с ней летает? Или программистам комфортно списывать свои оплошности на «медленный язык»?
И вот не понимаю: программисты действительно столько внимания уделяют синтетическим бенчмаркам? Почему?
Конечно, есть критичные к перфомансу области разработки, но они уже заняты специфичными языками: Rust, C++. На Ruby пишутся в основном веб-бэкенды, а в них, чтобы упереться в производительность *языка*, надо особо постараться. Если в сервисе что-то тормозит, то почти всегда накосячил программист, а не рантайм. На своей практике припоминаю только два случая, когда тормоза на высоких нагрузках можно было с натяжкой списать на проблемы платформы. Оба связаны с (де-)сериализацией, что характерно :). Но и они решились не переписыванием со скалы на раст, а просто заменой библиотеки и небольшими оптимизациями кода.
А что до синтетических бенчмарков: в самом популярном сравнении HTTP серверов akka-http стабильно болтается около 190-го места. При этом в проде работает нормально и кушать не просит. Если что-то и тормозит, то в коде приложения, а не фреймворка. Современное состояние индустрии таково, что фреймворк со дна бенчмарков может держать внушительную нагрузку! И это не говоря о дешёвом железе.
Поэтому в моих глазах топ причин плохого перфоманса выглядит так:
1. баг в коде;
2. ошибка конфигурации;
3. ошибка дизайна системы;
4. ... программист обосрался где-то ещё ...
5. медленный рантайм языка.
Или в руби всё настолько плохо с производительностью, что даже скала по сравнению с ней летает? Или программистам комфортно списывать свои оплошности на «медленный язык»?