Два года назад в Хельсинки взяли мидлом, зп была выше вами озвученной для архитекторов и тимлидов, и это продуктовая компания.
Если попасть в консалтинг, будет еще интереснее в этом плане.
А если в какой-нибудь SuperCell, что не у каждого выйдет, конечно, то можно будет купаться в теплом шоколаде, т.к. со всеми премиальными там может выйти за 150-200 в год (до вычета)
Так а как тут поможет монолит или микруха, если БД под завязку?
Стейтлесс приложения обновляются один за другим без особых проблем. С тяжелыми базами будут проблемы вне зависимости от архитектуры системы.
На _нормальный_ девопс вороха микрух времени уйдет не меньше, чем на разработку. Для небольших команд это может быть критично, т.к. вместо имплементации фич они будут дрочиться, почему же у них на EC2 инстанс не качается докер имадж из приватного ECR. А выделять на это приходится человека, который код пишет.
У меня есть опыт работы и в небольшой команде, и в крупной компании. Есть возможность сравнить плюс и минусы подходов на практике, без теоретического «ну оно там чото скейлится, чтоб обрабатывать мои 100 запросов в час».
Основная суть микросервисов — это масштабирование на бизнес-уровне.
Пусть в компании X определена общая политика — все микросервисы должны предоставлять REST API. Вот книжка с good practice, следуйте.
Теперь каждая команда обозначает API через какой-нибудь swagger/graphql/whatever и имплементирует уже как хочет. Полная независимость разработки между командами, никаких баундов. Технологии и языки вольна выбирать команда, ответственность за продукт end to end, бизнес-домен как зона ответственности команды и продукта.
Единственное правило — не ломать API. А дальше уже скейлите, заливайте огрехи баблом и т.п. Когда у вас на фронте все рендерится по несколько сотен мс, не пофиг ли, что там на бэкэнде теперь оверхед на запросы между сервисами?
Теперь повторите такой же трюк с монолитом на масштабах больше 1к разработчиков. Чтоб гибко и независимо. Вот почему это работает для таких гигантов как Netflix или Spotify
Для команд по 5-6 человек на всю компанию вы на нормальный девопс убьете не меньше ресурсов, чем на, собственно, разработку микрух. Это из собственного опыта.
Хотя сейчас kubernetes + AWS сервисы и облегают задачу с service discovery, failover и т.п., но мороки все равно хватает.
Автоматический вывод тайп-классов — это фактически вывод тайп-класса для некого типа `T` на основе уже имеющейся информации. Например, если у вас описаны тайп-классы для примитивов, можно вывести через LabelledGeneric для кейс-классов. А через копродукты еще и для трейтов.
Как вы будете использовать тайп-класс для типа — это уже ваше дело. Можно для бинарного сложения, а можно напрямую ТК дергать для своих целей.
Возьмем, как пример, библиотеку circe для работы с JSON. Есть множество энкодеров/декодеров для примитивов из коробки. На основе этих энкодеров в circe есть дженерик для автоматического вывода энкодеров для любых классов (если есть необходимый). Т.е. в вашем кейсе достаточно было один раз описать свои энкодеры для необходимых примитивов и дальше использовать их сколько душе угодно. И никакого абуза макросов.
Евгений говорил, что холивар на тему, когда использовать type level программирование, а когда — макросы, может длиться очень долго. Но основная мысль — макросы нужны там, где у нас реальный кодоген и мы пишем сложные деревья. По-крайне мере, в большинстве крупных проектов они так и работают.
Для L-уровня имхо лучше использовать type level подход просто по той причине, что это сопровождать будет проще.
Все там читаемо.
И на 100% процентов уверен, что на _ЛЮБОМ_ языке, который человеку не знаком, можно найти такой пример, что у субъекта прикипит и он начнет исходить слюнями. От асма до name-yourself.
Макросы в скале в текущей реализации — это экспоуз компилятор наружу, за что их не особо любят (это же, о боже, надо понимать, что такое Expr и Tree!).
Позже появились квазицитаты, стало попроще. Сейчас пилят scala-meta, там все радужно и с пони.
Но меня всегда умиляло, как вылезают такие уникумы, и на абстрактных примерах использования макросов или type level программирования составляют суждение о языке как таковом. Это все равно что о крестах судить через призму шаблонов. Пфф
Хм, интересно, как себя поведет shapeless + aux паттерн, да и вообще всё type-level программирование.
Хотя, если запилят частичное применение типов, то ничего страшного не случится.
for {
a <- futureA
b <- futureB
c <- futureC
} yield {
...
}
Компилятор сам разложит на map/flatMap (можно даже с if подключить filter). Это для начального уровня.
Зайдя чуть дальше в ФП — там Future всё еще монада (ну ладно, тут я лукавлю, она монада, если забыть про эксепшены внутри, иначе left identity не выполняется, но не суть). А значит, можно подрубить монад-трансформеры и работать с Future[Option[A]] словно у вас праздник на улице. В коде ниже мы получаем доступ сразу до значения типа А внутри двух монад:
for {
a <- futureOptA.optionT //a: A
b <- futureOptB.optionT //b: B
c <- futureOptC.optionT //c: C
} yield {
...
}
К слову, это довольно частый кейс при работе с асинхронными базами/драйверами. Вы ждете запись в будущем, которая может и не существовать в базе.
Любопытства ради, хотелось бы увидеть решение на джаве. Слышал, там Option тоже завезли.
Два года назад в Хельсинки взяли мидлом, зп была выше вами озвученной для архитекторов и тимлидов, и это продуктовая компания.
Если попасть в консалтинг, будет еще интереснее в этом плане.
А если в какой-нибудь SuperCell, что не у каждого выйдет, конечно, то можно будет купаться в теплом шоколаде, т.к. со всеми премиальными там может выйти за 150-200 в год (до вычета)
Стейтлесс приложения обновляются один за другим без особых проблем. С тяжелыми базами будут проблемы вне зависимости от архитектуры системы.
На _нормальный_ девопс вороха микрух времени уйдет не меньше, чем на разработку. Для небольших команд это может быть критично, т.к. вместо имплементации фич они будут дрочиться, почему же у них на EC2 инстанс не качается докер имадж из приватного ECR. А выделять на это приходится человека, который код пишет.
У меня есть опыт работы и в небольшой команде, и в крупной компании. Есть возможность сравнить плюс и минусы подходов на практике, без теоретического «ну оно там чото скейлится, чтоб обрабатывать мои 100 запросов в час».
Основная суть микросервисов — это масштабирование на бизнес-уровне.
Пусть в компании X определена общая политика — все микросервисы должны предоставлять REST API. Вот книжка с good practice, следуйте.
Теперь каждая команда обозначает API через какой-нибудь swagger/graphql/whatever и имплементирует уже как хочет. Полная независимость разработки между командами, никаких баундов. Технологии и языки вольна выбирать команда, ответственность за продукт end to end, бизнес-домен как зона ответственности команды и продукта.
Единственное правило — не ломать API. А дальше уже скейлите, заливайте огрехи баблом и т.п. Когда у вас на фронте все рендерится по несколько сотен мс, не пофиг ли, что там на бэкэнде теперь оверхед на запросы между сервисами?
Теперь повторите такой же трюк с монолитом на масштабах больше 1к разработчиков. Чтоб гибко и независимо. Вот почему это работает для таких гигантов как Netflix или Spotify
Для команд по 5-6 человек на всю компанию вы на нормальный девопс убьете не меньше ресурсов, чем на, собственно, разработку микрух. Это из собственного опыта.
Хотя сейчас kubernetes + AWS сервисы и облегают задачу с service discovery, failover и т.п., но мороки все равно хватает.
Автоматический вывод тайп-классов — это фактически вывод тайп-класса для некого типа `T` на основе уже имеющейся информации. Например, если у вас описаны тайп-классы для примитивов, можно вывести через LabelledGeneric для кейс-классов. А через копродукты еще и для трейтов.
Как вы будете использовать тайп-класс для типа — это уже ваше дело. Можно для бинарного сложения, а можно напрямую ТК дергать для своих целей.
Возьмем, как пример, библиотеку circe для работы с JSON. Есть множество энкодеров/декодеров для примитивов из коробки. На основе этих энкодеров в circe есть дженерик для автоматического вывода энкодеров для любых классов (если есть необходимый). Т.е. в вашем кейсе достаточно было один раз описать свои энкодеры для необходимых примитивов и дальше использовать их сколько душе угодно. И никакого абуза макросов.
Евгений говорил, что холивар на тему, когда использовать type level программирование, а когда — макросы, может длиться очень долго. Но основная мысль — макросы нужны там, где у нас реальный кодоген и мы пишем сложные деревья. По-крайне мере, в большинстве крупных проектов они так и работают.
Для L-уровня имхо лучше использовать type level подход просто по той причине, что это сопровождать будет проще.
Все там читаемо.
И на 100% процентов уверен, что на _ЛЮБОМ_ языке, который человеку не знаком, можно найти такой пример, что у субъекта прикипит и он начнет исходить слюнями. От асма до name-yourself.
Макросы в скале в текущей реализации — это экспоуз компилятор наружу, за что их не особо любят (это же, о боже, надо понимать, что такое Expr и Tree!).
Позже появились квазицитаты, стало попроще. Сейчас пилят scala-meta, там все радужно и с пони.
Но меня всегда умиляло, как вылезают такие уникумы, и на абстрактных примерах использования макросов или type level программирования составляют суждение о языке как таковом. Это все равно что о крестах судить через призму шаблонов. Пфф
Там еще были бы и рекорды из коробки
Хотя, если запилят частичное применение типов, то ничего страшного не случится.
Компилятор сам разложит на map/flatMap (можно даже с if подключить filter). Это для начального уровня.
Зайдя чуть дальше в ФП — там Future всё еще монада (ну ладно, тут я лукавлю, она монада, если забыть про эксепшены внутри, иначе left identity не выполняется, но не суть). А значит, можно подрубить монад-трансформеры и работать с Future[Option[A]] словно у вас праздник на улице. В коде ниже мы получаем доступ сразу до значения типа А внутри двух монад:
К слову, это довольно частый кейс при работе с асинхронными базами/драйверами. Вы ждете запись в будущем, которая может и не существовать в базе.
Любопытства ради, хотелось бы увидеть решение на джаве. Слышал, там Option тоже завезли.
На другой — 6.
Не вижу корреляции.