Deadline
Прочитал «Deadline» Тома Демарко. Хорошая книжка по руководству проектами, читается за два вечера. Уровень графомании приемлемый, буллщитометр критических отметок не достигал. Начинающим менеджерам смело рекомендую.
Выписал несколько ключевых мыслей, вроде бы и очевидных, но разобранных на понятных ситуациях проектной работы.
Управление проектом — это управление людьми, работающими над проектом.
Работа руководителя делается не в час Х, а до него. Во время интенсивной работы над проектом команда уже должна знать, что делать, и идти по налаженным процессам. Задача руководителя — подготовить команду и процессы.
Работа руководителя состоит из принятия массы иррациональных решений. Но интуицию стоит формализовывать и моделировать там, где возможно.
Не существует краткосрочных мер увеличения производительности команды. Производительность — результат долгосрочных усилий.
Для управление проектом надо управлять рисками. Необходимо вести учёт возможных рисков, и как можно раньше ловить момент, когда риск становится проблемой.
Слаженная команда — такой же результат проекта, как и созданный продукт. Такую команду надо беречь как зеницу ока, избегать разделения людей.
Коллективной принятие решений эффективно. Собрать вокруг себя близких по духу профессионалов — залог успешного принятия решений.
Проектирование — самый важный этап разработки. Сконцентрировав усилия команды на этапе проектирования, можно существенно упростить процесс реализации задач и снизить количество ошибок. Но большими командами проектировать тяжело.
Не стоит недооценивать людей-катализаторов. Есть люди, одним своим присутствием поднимающие командный дух, снимающие напряжение, решающие внутренние конфликты. Таких людей надо ценить, тем более, что и работают они зачастую хорошо.
Прочитал «Deadline» Тома Демарко. Хорошая книжка по руководству проектами, читается за два вечера. Уровень графомании приемлемый, буллщитометр критических отметок не достигал. Начинающим менеджерам смело рекомендую.
Выписал несколько ключевых мыслей, вроде бы и очевидных, но разобранных на понятных ситуациях проектной работы.
Управление проектом — это управление людьми, работающими над проектом.
Работа руководителя делается не в час Х, а до него. Во время интенсивной работы над проектом команда уже должна знать, что делать, и идти по налаженным процессам. Задача руководителя — подготовить команду и процессы.
Работа руководителя состоит из принятия массы иррациональных решений. Но интуицию стоит формализовывать и моделировать там, где возможно.
Не существует краткосрочных мер увеличения производительности команды. Производительность — результат долгосрочных усилий.
Для управление проектом надо управлять рисками. Необходимо вести учёт возможных рисков, и как можно раньше ловить момент, когда риск становится проблемой.
Слаженная команда — такой же результат проекта, как и созданный продукт. Такую команду надо беречь как зеницу ока, избегать разделения людей.
Коллективной принятие решений эффективно. Собрать вокруг себя близких по духу профессионалов — залог успешного принятия решений.
Проектирование — самый важный этап разработки. Сконцентрировав усилия команды на этапе проектирования, можно существенно упростить процесс реализации задач и снизить количество ошибок. Но большими командами проектировать тяжело.
Не стоит недооценивать людей-катализаторов. Есть люди, одним своим присутствием поднимающие командный дух, снимающие напряжение, решающие внутренние конфликты. Таких людей надо ценить, тем более, что и работают они зачастую хорошо.
Видео на три с половиной часа, в котором автор замечательного канала DevInsideYou объясняет скалу от установки настройки тулинга до ADT и имплиситов. Отличная альтернатива документации с официального сайта для людей, переходящих с других языков.
https://www.youtube.com/watch?v=-xRfJcwhy7A
https://www.youtube.com/watch?v=-xRfJcwhy7A
YouTube
#Scala Crash Course by a Scala Veteran (with some JavaScript flavor)
Learn Scala in one video from a 10+ years Scala veteran.
Watch my videos before everyone else!
https://www.youtube.com/channel/UCSBUwLT9zXhUalKfJrc2q2A/join
Stack Overflow Developer Survey 2020:
https://insights.stackoverflow.com/survey/2020#technology…
Watch my videos before everyone else!
https://www.youtube.com/channel/UCSBUwLT9zXhUalKfJrc2q2A/join
Stack Overflow Developer Survey 2020:
https://insights.stackoverflow.com/survey/2020#technology…
Наткнулся на гитхабе на экспериментальную библиотеку, улучшающую читаемость скаловых стектрейсов
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 сделал за несколько минут.
Lil Functor
В экосистеме 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://www.tg-me.com/shark_in_it
Всем советую подписаться, там о больших и сложных вещах понятным языком рассказывают. Сегодня вот вышел пост о FoundationDB.
https://www.tg-me.com/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. Всех авторов перечислять…