(java || kotlin) && devOps
369 subscribers
6 photos
1 video
6 files
306 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Всем привет!

Продолжение про сагу.

Когда мы говорим про транзакции, сначала всплывает аббревиатура ACID. Транзакции должны обеспечивать принципы ACID. Посмотрим что тут у нас с сагой.
A - атомарность: или все выполняется, или все откатывается. Собственно атормарность есть в определении паттерна, см. выше. Единственное отличие - у нас нет волшебного rollback на всю распределённую транзакцию, бизнес логику отката придётся писать руками.
C - консистентность данных. Сага обеспечивает т.наз. eventually consistentcy - конечную согласованность. Т.е. данные будут согласованы только после окончания распределённой транзакции. В течение транзакции данные в разных микросервисах могут расходится. Транзакция в БД может обеспечить строгую согласованность изменяемых данных с нужным уровнем изоляции. Поэтому переходим к
I - изоляции изменений внутри транзакции от других операций. Сага не обеспечивает ее совсем, что с этим можно сделать описано в статье про это патерн от Microsoft по ссылке выше. Важный момент - в отличие от транзакции в БД, которая как правило длится миллисекунды, распределённая транзакция - это секунды, может даже десятки секунд. Несогласованность данных в течение этого времени из-за отсутствия изоляции нужно иметь в виду. В дополнение к описанным в статье по ссылке способом скажу ещё один - завершать транзакцию как можно быстрее и игнорировать несогласованность данных) Пример: клиент вряд ли будет жаловаться в службу поддержки, если после отмены заказа деньги и бонусы вернутся на счёт в течение минуты. И скорее всего будет - если это не будет сделано через час.
D - надёжность хранения данных, к саге отношения напрямую не имеет, обеспечивается используемыми хранилищами.

Т.к. в итоге мы получили ACD, причем неполноценный, то для распределенных транзакций придумали новую аббревиатуру - Basically Available, Soft-state, Eventually consistent - https://ru.m.wikipedia.org/wiki/Теорема_CAP#BASE-архитектура

Ещё один интересный момент про сагу: определение последовательности шагов - локальных транзакций. Единственно верной схемы нет, но есть рекомендации. Первая - fail fast. Т.е. если есть локальная транзакция, которая упадёт с большей вероятностью - ее нужно ставить вначале. Пример: резерв билета или товара. Вторая - если какая-то локальная транзакция проводит к критичной для клиента несогласованность данных - ее нужно выполнять как можно позже. Что делать, если эти рекомендации противоречат друг другу - зависит от сценария, но в целом я бы выбрал уменьшение времени неконсистентности.

Еще интересный момент касается саги в виде оркестрации. Т.к. ее главный плюс - сделать простой и понятной бизнес логику саги, то самая очевидная ее реализация вот такая:

class OrderSaga {
SagaResult execute() {
// шаг 1
// шаг 2
// ...
}
}

Назовём этот подход Transaction Script, есть такой Паттерн организации бизнес логики.
Просто - да. Но если процесс сложный, каждый шаг тоже, то мы ухудшим читаемость кода, получим замечание SonarQube про длину метода да и нарушим S из SOLID, принцип единой ответственности. Что делать? Использовать event driven подход:
class OrderSaga {
PrepareEvent start(...) {..}
ReserveEvent makeReservation(...) {...}
// ...
}
При необходимости обработку событий можно разнести в разные классы. Чтобы было понимание как работает процесс нужно написать пару модульных тестов - позитивный и негативные сценарии, ведь тесты в идеале - лучшая документация к коду. Ещё один плюс - в событийной стиле легко сделать весь процесс неблокирующим, например, через адаптер отправляя и принимая все события в Kafka. Да, есть ещё БД, запись в БД в эту парадигме - это такое же событие. В этом случае стоит посмотреть в сторону R2DBC https://www.baeldung.com/r2dbc Для REST endpoint и client есть Spring WebFlux.
К слову, Transaction script тоже может обеспечить неблокирующее выполнение, но только в языках программирования с async await: c#, python, rust https://learn.microsoft.com/ru-ru/dotnet/csharp/language-reference/operators/await

To be continued...

#patterns #saga #microservices #acid #arch_compromises
Всем привет!

Этим постом завершается серия по паттерну Сага.

В предыдущем посте забыл упомянуть 3-й и 4-й способ реализации Саги.

Третий - если вы используете BPMN движок, например, Camunda, то он отлично подходит для оркестратора Саги. Более того, использовать BPMN как оркестратор - лучшая идея, чем использовать его как среду для low-code разработки. Ну не верю я в low-code, не сталкивался с работающими кейсами) Главные плюсы BPMN в данном - случае готовая state machine и визуализация Саги. К слову сама Camunda поставила этот use case на первое место в списке https://camunda.com/solutions/microservices-orchestration/ что как бы намекает. На всякий случай: Camunda - это самый распространенный BPMN движок, собственно движок - opensource, платить нужно только за UI консоль.

Аналогично - если вы уже используете Apache Camel - он тоже умеет в сагу, https://camel.apache.org/components/4.4.x/eips/saga-eip.html

Тут встает вопрос - стоит ли внедрять данные инструменты только ради Саги? Базовый ответ нет, идеальный кейс: если какой-то из этих компонент уже у вас используется - логично реализовать оркестрацию с его помощью. Я бы внедрял, если бы были какие-то еще плюсы от использования, кроме собственно реализации паттерна.

Еще важный момент при реализации оркестратора - stateless или statefull? Да, любая бизнес операция имеет как минимум ID и состояние, которые нужно хранить. Но необязательно это делать в классе Саги. Особенно используя event driven подход, можно просто передавать все не необходимые данные в событиях\командах. Напомню, при этом сохранение состояния операции в БД - это тоже событие. Плюс такого подхода - не нужно думать о букве D из ACID, т.е. персистентности, для данных, хранимых в оркестраторе. А где персистентность, там и кэширование, т.к. обращение к БД - дорого. И восстановление данных из БД при сбоях. Поэтому если вы все же решили хранить состояние операции в коде - я бы рекомендовал не изобретать велосипед, а воспользоваться готовым фреймворком. Два из них я уже упомянул выше, но они достаточно "тяжелые". Вот еще несколько, заточенных собственно под паттерн Сага и под DDD, который в общем-то тесно связан с сагой. Ведь если мы делим систему на ограниченный контексты, Bounded Context, то их данные лежат в разных БД, а следовательно возникает распределенная транзакция...

1) Axios https://docs.axoniq.io/reference-guide/v/3.1/part-ii-domain-logic/sagas
2) Eventuate Tram Saga https://eventuate.io/docs/manual/eventuate-tram/latest/getting-started-eventuate-tram-sagas.html
3) Seata https://www.seata.io/docs/user/mode/saga


Фреймворк помогает нам с:
а) персистентностью
б) кэшированием
в) созданием экземпляра саги для конкретной бизнес-операции
г) удобной работой с параметрами операции

При этом он не отменяет написания кода оркестрации и компенсирующих действий.

На этом пожалуй все.
Хотя нет. Остается вопрос - как же лучше реализовать Сагу? Ответ - лучше сделать свой ограниченный контекст = микросервис таким, чтобы Сага была не нужна)
А если серьезно.
1) постарайтесь использовать только локальные транзакции
2) если это не возможно, и у вас 2-4 шага - используйте хореографию
3) если шагов от 4+ и сервис создаётся с нуля - используйте оркестратор, для начала самописный, stateless event driven
4) у вас уже используется Camunda или Camel - делайте оркестратор на их основе
5) если вас нужен state - используйте фреймворки из последнего списка, например, Axios
6) если нужна сага и state machine - Camunda или Seata

#saga #microservices #ddd #patterns
Всем привет!

Есть такая фраза - все новое - это хорошо забытое старое. Еще есть тезис, что все развивается по спирали.
К чему это я?)

Если вы имеете отношение к миру Java - вы наверняка слышали про virtual threads. https://openjdk.org/jeps/425
Для начала немного теории. В ОС есть процессы - это запущенная программа или фоновый процесс. У каждого процесса может быть несколько потоков, которыми также управляет ОС. Поток занимает ресурсы - как минимум память, а при выполнении - еще и процессорное время. Поток может блокироваться - ожидать какого-то события для продолжения операции. Больше того - не ошибусь, если скажу, что в большинстве сервисов время блокировки >=50% общего времени выполнения потока.
При блокировке расходуется только память и емкость пула потоков, из которого этот поток был взят (процессорное время - нет). Особенно опасна блокировка тогда, когда она массовая - тогда пул быстро заканчивается, и все новые запросы к приложению отбиваются. Еще более опасна, если поток не из пула, например, он обслуживает UI или это основной поток выполнения программы - метод main, т.к. тогда блокируется приложение целиком.

Виртуальные потоки призваны снизить остроту этой проблемы. Как именно?
Виртуальный поток - это как бы обычный поток, вот пример его создания:

Thread thread = Thread.ofVirtual().start(() -> System.out.println("Hello"));

того же класса Thread https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Thread.html
Но если обычный поток мапится один к одному на поток ОС, то виртуальные управляются JVM и работают в рамках одного системного потока, т.наз. carrier потока. Выглядит это так: https://belief-driven-design.com/images/2023/2023-10-05-java-21-virtual-threads-scheduler.webp
К чему приводит такой подход?
1) виртуальные потоки более "дешевые" в плане памяти, т.к. управление идет на уровне JVM
2) при блокировке виртуального потока поток ОС не блокируется, может выполнять полезную работу, например, обрабатывать запросы новых пользователей
3) можно использовать обычные блокирующие конструкции языка, без CompletableFuture и Reactive кода, которые проще создавать и что наверное более важно - проще отлаживать.

Но вернусь к новому и старому)

В Java 1.1 появились Green Threads https://en.wikipedia.org/wiki/Green_thread
Что это за зверь такой? А примерно тоже самое - создаем несколько потоков на уровне JVM, все они средствами JVM мапятся на один поток ОС. Зачем? Был 1997 год, памяти было мало, создавать потоки было очень дорого. Потом память подешевела, проблема казалось бы ушла. В Java 1.3 green threads убрали.
Потом памяти стало еще больше, но число клиентских запросов и сложность кода выросли еще сильнее, чем память. И в 2021 году к идее вернулись.

P.S. Потоки, управляемые виртуальной машиной - стандартная штука для языков, у которых эта виртуальная машина есть. У них есть общее название - fibers. Пример - goroutines в Go.

#threads #concurrency #java #go
Всем привет!

Одна из моих любимых тем, вторая после читаемости кода, это скажем так "разработка - искусство компромиссов".
Редко встречаются ситуации, когда какой-то паттерн или принцип можно применять по формальным критериям всегда и везде. Более того, часто паттерны и принципы противоречат друг другу. Рассмотрим пример.

Есть такой паттерн, по моему опыту проведения интервью самый известный после синлетона - фабрика. А точнее абстрактная фабрика, именно такой паттерн описан в классике - Design Patterns: Elements of Reusable Object-Oriented Software. Суть его в том, что функция создания новых объектов выносится в отдельный класс. Создаваемые объекты являются наследниками какого-то базового класса или интерфейса. Классов фабрик может быть несколько, при этом каждая фабрика создает все (!) необходимые для проведения некой операции совместимые (!) между собой объекты. Вот более подробное описание с примером https://habr.com/ru/articles/465835/

Т.е. на первый взгляд паттерн работает четко в соответствии с принципом единственной ответственности (Single Responsibility) - создание отделено от доменного объекта, более того, для разных потребителей процесс создания объектов разнесен по разным фабрикам - ToyotaFactory и FordFactory из статьи выше.

А теперь изменим пример из статьи - будем создавать не разные типы кузовов автомобилей, а детали автомобиля. А деталей в авто подозреваю несколько тысяч... И список их более изменчивый, чем список типов кузовов. Т.е. по сути объединив в одном классе создание нескольких объектов мы уже заложили мину замедленного действия. Где находится грань между работой по Single Responsibility и его нарушением?

Базовый ответ был в первом абзаце - все зависит от бизнес-процесса. Но попробуем добавить конкретики.
Для начала можно вспомнить про лайфхак - можно оставить в фабрике один метод и передавать ему на вход Enum с типом создаваемого объекта.
class Factory {
SomeItem createSomeItem();
OtherItem createOtherItem();
}

vs

class Factory {
Item createItem(ItemType type);
}
Он немного упрощает добавление новых классов, т.к. не надо менять API фабрики, но в итоге приводит к тому же результату. Но дает нам подсказку: когда в Enum становится слишком много элементов - значит с фабрикой надо что-то делать.
Еще вариант - посмотреть, что скажет SonarQube. Он предлагает ограничиться 35 методами и 750 строками кода для одного класса. Как по мне - это много, я бы начинал делить фабрику на части раньше, при появлении 10-15 методов или по мере появления логических сущностей, позволяющих взять группу связанных методов из большой фабрики и вынести их в отдельную фабрику.

#patterns #solid #dev_compromises
Всем привет!

Немного не по теме блога, но выглядит впечатляюще - демо возможностей ChatGPT-4o https://www.youtube.com/live/DQacCB9tDaw?t=542s Который мультимодальный, понимает голос и анализирует видео с камеры смартфона в реальном времени, плюс может переводить текст на ходу.
В плане разработки - интересен пример с анализом куска кода на предмет того, что он делает, это прям отдельное направление. Не как картинка, код взят из буфера обмена, но это детали. Интересно, какого размера кусок кода он сможет проанализировать за раз?

P.S. Судя по отдельному спасибо NVidia в конце ролика - железо для этого дела нужно мощное.

P.P.S. ChatGPT-4o доступен бесплатно с ограничениями по числу сообщений в сутки с официального сайта при наличии Google аккаунта и VPN.

#ml #chatgpt
Всем привет!

Как LLM модели могут помочь разработчику? Накидаю варианты, которые видел и\или пробовал.

1) Самое очевидное - генерация больших кусков типового кода. Например, реализация алгоритма быстрой сортировки на языке Kotlin. Это пример вымышленный - не надо так делать на самом деле, наверняка уже есть подходящая библиотека. Еще пример - код инициализации RestTemplate без реактивщины с настройкой mTLS, таймаутов и обработкой ошибок. Существующие модели уже неплохо справляются с этим, но я вижу направление для развития - в больших компаниях со своими фреймворками\платформами доработка модели с использование DAG - локальной векторной БД с данными по используемому в компании ПО.

2) анализ существующего кода - что делает этот метод, этот класс, модуль, сервис. У большинства моделей пока здесь проблемы из-за ограничения по размеру подаваемого контекста, но ChatGPT-4o похоже эту проблему решает. Что не убирает требования к хорошей читаемости кода, конечно же))))

3) AutoCompetion кода в IDE. На этой поляне работают GitHub Copylot, IntelliJ и Sber GigaCode. Работают скажем так с переменным успехом. Здесь два рода проблем. Во-первых, контекст должен собираться автоматически плагином для IDE, а это нелегко - понять чего хочет разработчик. Да, есть имя класса, метода, переменных, уже написанный код, открытые в IDE файлы, печатаемый в данный момент код - но важно все эти ингредиенты правильно приготовить) Но даже если их приготовить - часть знаний все равно останется в голове разработчика. О второй проблеме уже писал - т.к. в данном кейсе код содержит больше генерируемого на лету, чем вытащенного из глубин модели, то велика вероятность мелких ошибок синтаксиса, см. https://t.me/javaKotlinDevOps/279 Задача сложная, но перспективная, т.к. набор встроенных AutoCompletion ограничен "фантазией" и размерами команды разработки IDE и, а главное - слабо учитывает контекст

4) генерация тестов - тоже уже есть, тоже с переменным успехом, но кажется, что эта задача проще, т.к. контекст - метод для тестирования - четко задан. Область расширения - генерация интеграционных или приемочных тестов с указанным фреймворком.

5) генерация комментариев для commit и Pull Request - уже писал про это https://t.me/javaKotlinDevOps/252

6) краткий пересказ статей и книг - много пробовал, пока слабовато, т.к. контекст - что мне интересно в тексте - сложно извлечь из головы. Но опять же есть надежда на ChatGPT-4o и его последователей. И рекомендую по возможности не просто пользоваться кнопкой "пересказать", а задавать контекст явно. Перспективно, т.к. объем информации, необходимый для изучения разработчиком чтобы "быть в тренде" - очень высок. Но важное замечание - важные вещи я бы читал сам, чтобы не упустить детали.

7) автоматический анализ ошибок. В частности стектрейсов, но не ограничиваясь ими. Почему важно - по моим наблюдениям гораздо больше времени тратится на отладку ошибок, чем на собственно разработку. Кажется, что по stackoverflow модели уже неплохо работают, но как и с генерацией кода важно дообучение на ошибках, специфичных для конкретной компании. Еще одна область для развития - автоматический анализ логов, автоматическое создание инцидентов, выстраивание их в иерархию, автоматическое создание багов в трекере. И ещё одна - встраивание инструмента в IDE, переход на стройку с ошибкой из stack trace (уже есть в IDEA) и предложения по исправлению

Что я забыл в плане разработки?

#llm #ml
Всем привет!

Разработка ПО - очень динамичная сфера. Мэйнфреймы, ассемблер, CSV, RDBMS, C, Delphi, Java, REST, MQ, git, DevOps, Docker, k8s, Kafka, noSQL, microservices, reactive programming, DataLake, GitOps, ChatGPT...
Но есть вещи, которые не меняются. 1967 год, сформулирован закон Конвея - Любая организация, которая разрабатывает систему (в широком смысле), вынуждена создавать проекты, структуры которых являются копией структуры связей организации.
Причем если верить wiki, а в данном случае IMHO это можно делать, закон даже был доказан, видимо на исследовании реальных компаний.
Так вот, читаю сейчас одну интересную книгу про внедрение DDD - Domain Driven Development, 2022 года выпуска. В главе про внедрение вижу такой совет - начать с того, что определить бизнесовые поддомены в компании, на основании которых будут строится ограниченные контексты - одна из ключевых сущностей DDD. Как их проще всего определить? Рекомендуется посмотреть на структуру организации. Закон Конвея в DDD)

P.S. Интересно и то, что в 1967 году разработка как отрасль уже достигла уровня, позволяющего формулировать определенные принципы.

#ddd #dev_law #book_review
Всем привет!

Попробую немного развить тему с законом Конвея из предыдущего поста.
Я достаточно много раз за свою карьеру в разработке сталкивался с упоминанием данного закона. Уже не вспомню где конкретно, но у меня осталось стойкое впечатление, что отношение к нему было как к неизбежности, с которой нужно бороться. Способы борьбы можно вспомнить такие:
1) корпоративные архитекторы, выравнивающие архитектурные шаблоны
2) внутренние платформы, обязательные к использованию внутри компании и реализующие единообразно нефункциональные требования
3) техрадар как способ ограничить технологический стек
4) единые практики найма и онбординга
5) корпоративная модель данных - как антипод принципа DDD, когда существует некая общая для организации единственно верная доменная модель
...

Так вот - что мне нравится в парадигме DDD, что она говорит - не надо бороться, надо принять как данность, расслабиться и получать удовольствие от своего ограниченного контекста) Ремарка – речь про применение закона в проектировании ПО.

#ddd #dev_law
Всем привет!

Agile сейчас стал мейнстримом. Большинство из моих знакомых работают в Agile командах, почти все соискатели на собеседованиях либо работают по Agile, либо как минимум знают, что это такое.
И Agile, в частности SCRUM, как самая распространенная его реализация - это очень крутая и полезная методология.
Хороша она как следует из названия гибкостью - т.е. развитие продукта можно корректировать каждые две недели, а не раз в квартал или полгода. С учетом скорости изменений в современном мире - это killer feature.

Но как говорится есть нюанс.
У SCRUM (Agile) есть фундаментальный косяк. Изначально методология разрабатывалась под процессы одной команды. 7-10 человек. Так сказать сферическая команда в вакууме.
Команда тесно взаимодействует с бизнес-заказчиком, целиком отвечает за продукт, вовлечена в процесс и итеративно выдает результат. Предлагаю рассмотреть ответственность команды за продукт.
Когда команда одна - да, она за него 100% отвечает. А если команда - часть большой компании? Где продукт выводится в рамках какого-то большого мобильного приложения или сайта, т.е. канала. Канал, а точнее подразделение, за него отвечающее, предъявляет ряд требований к продуктам. У компании есть своя платформа, обязательная к применению. Плюс ряд таких же обязательных требований по архитектуре, надежности и кибербезопасности, выполнение которых контролируется. Единые требования по дизайну и текстовкам. В конце концов в компании множество источников данных, т.к. активно используются микросервисы. И при этом запрещено дублирование бизнес-критичного функционала, т.е. за доработками нужно идти к смежникам. Замечу, что в последнем требовании нет ничего плохого, та же DDD (надеюсь я пока не надоел вам с ней) требует того же.

Итог такой - команда не отвечает за продукт на 100%, т.к. у нее куча смежников, выставляющих свои требования. А значит ломаются многие базовые Agile принципы, например, выпускать релизы, доставляющие реальную бизнес-ценность, каждый спринт становится проблематично.
А что SCRUM - в своей исходной версии он этот вопрос никак не регламентирует.
Как в анекдоте - к пуговицам претензии есть?)
Да, есть другие фреймворки для масштабирования Agile - Scrum of Scrum, SAFe, LESS... Вот небольшое их сравнение https://vc.ru/hr/100292-freimvorki-masshtabirovaniya-agile-na-kompaniyu Еще есть Sbergile https://habr.com/ru/companies/sberbank/articles/547036/. Последний подсказывает нам, что в теории другие большие компании также могут заводить свои фреймворки. Отсюда главный минус такого подхода - получаем зоопарк фреймворков, которые в целом похожи - https://habr.com/ru/articles/726302/ - но естественно имеют и отличия.

Итого: главный минус SCRUM - он изначально создавался под условно "стартапы" из одной команды. При этом ИТ рынок формируют компании с тысячами и даже десятками тысяч разработчиков: Google, Microsoft, Amazon, Yandex, VK, Сбер.

#agile #scrum
Всем привет!

В продолжение темы Agile.

Как решение данной проблемы можно было бы предложить даже в большом enterprise работать как множество независимых Agile команд.
В теории это возможно если:
1) в организации мало требований и стандартов, команды имеют высокую степень автономности
2) существующие проверки автоматизированы, степень автоматизации стремится к 100%
3) процедура приемо-сдаточных испытаний автоматизирована или отсутствует
4) команды разрабатывают функционал End To End - от фронта до БД
5) сопровождение ПРОМ находится в команде, как вариант - разработчики отвечают за сопровождение
6) допускается, хотя бы временно, дублирование реализации, если команда, разрабатывающая целевой функционал, не готова доработаться вовремя

И наверное самое главное - организация изначально работала по Agile и, скажем так, в ее ДНК есть цель сохранить такой порядок вещей. На эту цель работает архитектура и все платформенные команды.

Для больших компаний, переходящих от водопада к Agile приходится придумывать что-то свое или искать подходящий фреймворк. Фреймворков много, какой лучше подходит - не понятно....

#agile
Всем привет!

При проектировании системы применяя микросервисный подход всегда появляется главный вопрос - как делить?
Сделаешь слишком крупно - получишь маленький монолит. Это как правило всем понятно, т.к. от монолита мы пытаемся уйти создавая микросервисы.
Но есть и другая крайность - слишком мелкое деление. Уже немного писал об этом https://t.me/javaKotlinDevOps/57
Сейчас же хочу проиллюстрировать эту крайность примером.
Предположим у нас есть некая система, представляющая клиентам CRUD REST API. Create, Read, Update, Delete методы. И еще List, который сильно отличается от Read поэтому должен быть выделен отдельно - pagination, сортировка, кэширование...
Можно применить назовем его "наивный" подход к микросервисам и сделать 5 микросервисов по числу методов API. Точнее даже "миллисервисов")
Что получим?
Вспоминаем, что у каждого микросервиса должна быть своя БД.
Это значит что от микросервисов Create и Delete зависят все остальные, т.к. им нужно будет обновить свою копию данных. Это может быть event driven подход с Kafka, CQRS или что-то другое, но в любом случае это зависимость.
От микросервиса Update зависят Read и List.
А если структура данных меняется?
И это зависимости "из коробки" на сферическом CRUD в вакууме. В реальном кейсе по мере развития системы число зависимостей будет больше. Что получилось? Получился распределённый "ком грязи". Такой же "ком грязи", как в старом неподдерживаемом монолите, от которого мы уходили, только хуже. Там хоть БД одна была и интеграций сильно меньше.
Можно попробовать вынести все взаимодействие с БД в отдельный микросервис Storage, но тогда мы нарушаем Single Responsibility - за ту же операцию Create отвечает и микросервис Create, и микросервис Storage. И Create скорее всего станет слишком простым для отдельного микросервиса.
Пример специально взят простой, в реальности выбор может быть сложнее. Зато на этом примере хорошо видны недостатки "миллисервисов".

P.S. За идею примера спасибо все из той же книжке по DDD, расскажу о ней в ближайшее время.

#microservices #rest #arch_compromises
Всем привет!

Наткнулся на интересную статью про различные типы разработчиков https://habr.com/ru/articles/135865/
Тут не про уровень - джун, миддл, сеньор, - а про разные названия должностей и что за этим стоит. Кодер, хакер, разработчик, инженер, архитектор...
В целом классификация норм, но хотел бы подсветить пару моментов. Да, статью рекомендую хотя бы краем глаза прочитать)

Архитектор вполне может быть и часто живет в своей башне из слоновой кости, где он бесполезен. Но есть как минимум два кейса, где польза есть:
1) корпоративный архитектор в большой компании, знающий где лежат те или иные данные и какие микросервисы можно переиспользовать, чтобы избежать дублирования
2) архитектор = инженер-исследователь. Изучает новую технологию, делает прототип, демонстрирует его всем заинтересованным лицам, рассказывает где и как технология будет полезна

Разница между разработчиком и инженером. На первый взгляд особой разницы не видно. Очевидно, что диплом не делает инженера лучшим спецом, чем разработчик. Но рассмотрим ПО для критической инфраструктуры: авиаперевозки, космос, атомные станции, медицина.
ПО нужно сертифицировать. А раз так, то и сертификация разработчика, который это ПО пишет, выглядит логичной. Как минимум есть подтверждение, что он сдавал экзамен по чему-то важному, что требуется в данной отрасли. Но речь именно про специализированные экзамены, а не про программирование на Java или не дай бог Pascal)

Но первая мысль, которая мне пришла в голову после прочтения - главное, чтобы ChatGPT не сделал из разработчика кодера)))

#development
Вроде простая картинка про работу git, но думаю будет полезно. Ключевые моменты - наличие локального репозитория и staging area #git
Forwarded from Metanit
Вкратце как работает Git
Всем привет!

Нашел отличное видео по исключениям в Java https://www.youtube.com/watch?v=UIbbNsta2UE

Краткий конспект, не влияющий на рекомендацию посмотреть видео:
1) затраты на выбрасывание исключений конечно же есть, но если исключение в вашем сервисе равно ошибке, то проблем с производительностью не будет. Т.к. ошибки как правило не выбрасываются сотнями и тысячами в секунду
2) если ваши исключение выбрасывается в строго определенном месте кода - можно убрать из него stack trace, это неплохо так увеличит производительность. На самом деле если просто не обращаться к stack trace, то она уже увеличится, но для надежности лучше вообще не прикреплять stack trace к исключению. Или использовать StackWalking API https://www.baeldung.com/java-9-stackwalking-api
3) самый спорный и опасный совет для того же кейса - исключение, выбрасываемое в одном месте - закэшировать исключение, так его выброс будет еще быстрее. Но по сути это старый добрый go to. Использовать с осторожностью!)
4) исключение должно содержать весь контекст ошибки, в идеале с предложениями по ее исправлению. Чтобы структурировать информацию об ошибке есть библиотека https://github.com/melix/jdoctor Активность в репозитории слабенькая, но сама идея мне нравится.
5) как известно, есть исключения, которые не стоит ловить - например, OutOfMemory и StackOverflow. Но если очень надо, то OutOfMemory все же можно) Главное - заранее создать все необходимые для сохранения информации о проблеме объекты, ведь после появления OutOfMemory памяти уже не будет.

А еще из интересного - после просмотра видео станет понятно, как работает SneakyThrows в Lombok

#java #exceptions
Всем привет!

TDD конечно крутая штука в плане правильного проектирования сервиса. Правильное проектирование - имеется в виду получить публичное Java API, удобное для использования, если не с первого раза, то с меньшим количеством итераций. О плюсах TDD уже говорил тут https://t.me/javaKotlinDevOps/32 И не только я)

Но кажется есть элемент, который можно к этой технике добавить.
Перед тем, как начинать писать первый тест для еще несуществующего класса - выписать как можно больше тестовых кейсов. Не для одного метода или даже класса, а для фичи, которую надо реализовать в текущей итерации. В виде готового набора тестов это сделать сложно, т.к. кода еще нет, поэтому как комментарии.
Что там может быть:
1) входные данные -> выходные данные
2) обработка возможных исключений
3) повторный запуск: идемпотентность, докат или ошибка
4) параллельный запуск
5) поведение при различных значениях настроек
6) поведение при различных настройках кодировки, языка, часового пояса, файловой системы
7) эффекты из-за отсутствия транзакционности (там где ее нет)
...
И возможно выписывание этих кейсов приведет к изменению дизайна системы. Или к пониманию, что метод\класс\модуль имеет слишком сложную логику. Или в нем много побочных эффектов. Или что есть дублирование логики между классами, которая решается либо их объединением, либо вынесением ее в третий класс. Возможно, стоит изменить границы транзакции.

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

#tdd #system_design
Всем привет!

Недавно посмотрел достаточно интересное видео про управление техдолгом https://youtu.be/pvZDcytPU3w
Почему именно техдолг - это мои "вьетнамские флешбэки", лет 8 назад я пришел на свое текущее место работы как раз с этой задачей.

По содержимому видео - оно не про управление техдолгом в широком смысле этого слова. Там нет архитектурного техдолга, технологического. Оно про техдолг, возникающий при реализации конкретной фичи конкретным разработчиком. Тот, что можно определить по наличию TODO в коде.

Но видео мне понравилось и могу его порекомендовать. И вот почему.
Речь идет о извечной проблеме разработчика - "сделать все красиво". А точнее идеально. А это идеально может потребовать недели, месяца, ... А у нас Agile, спринты в 2 недели, ежедневные дейли, бизнес ждет свою фичу.

Что предлагается делать:
1) не надеяться, что декомпозиция бизнес задачи на планировании будет идеальной
2) если при реализации выясняется, что фичу невозможно сделать в запланированные сроки, а их можно прикинуть исходя из длины спринта, числа задач и их оценки - нужно сделать часть фичи, допускающую продвижение дальше всей команды. Опять же - декомпозировать правильно сложно, но итеративно это получается лучше. Главное, повторюсь - минимум кода, позволяющего продвинуться дальше команде.
3) расставить по коду подробные TODO, рассказать команде что сделано, а что нет и почему, и влить доработку AS IS. Т.об. мы гарантировано получаем большую прозрачность. А если повезет, а точнее, если удалось правильно определить, что блокирует команду сейчас - еще и лучший Lead Time.
4) далее некий робот сканирует код, находит там TODO и делает из них таски в вашем таск-трекере
5) таски будут оценены на очередном планировании и взяты в работу, возможно другим разработчиком

Самое интересное - для одной и той же исходной задачи процесс может повторяться. И, наверное, если это происходит в 5-10 раз - стоит детальнее взглянуть на задачу. Похоже она сильно повлияла на архитектуру приложения.

У подхода есть и минусы:
1) TODO может быть сильно много, и они захламят бэклог. Нужен механизм приоритезации, в видео про это есть. Если копать дальше - не всякое TODO должно попадать в бэклог. Какие-то TODO - это хотелки, которые вначале стоит обсудить с командой
2) техдолг может висеть в бэклоге месяцами, нужен механизм контроля за его исполнением
3) подход нужно объяснить бизнесу. Что это не несделанная задача - а дополнительно декомпозированная. Но, кажется, прозрачность бизнес оценит. А если удастся уложиться в сроки - тем более.

Итого: идея пытаться сделать фичу за минимально возможное время с максимальным "выхлопом", заводя на все остальные задачи подробные TODO, мне кажется верной.

P.S. Отдельное спасибо автору за исторический экскурс - откуда взялось слово техдолг. Почему долг? Кто кому должен?) Спойлер - это аналогия с миром финансов

#техдолг
Всем привет!

Продолжаю серию полезных видео - https://youtu.be/j-i3NQiKbcc
Тут по полочкам расписывает как работает логирование в Java.

Краткий конспект по архитектуре логирования:
1) адаптер - предоставляет API, которое вызывается из кода. На данный момент их 3 - SL4J, JCL (Apache Common Logging) и JBoss Logging. Самый распространенный и рекомендуемый - SLF4J
2) bridge - нужен, когда какая-то библиотека использует не тот адаптер, что мы хотим. По сути адаптер на адаптер, который эмулирует API, вызываемое из кода, и пробрасывает вызовы в нужный адаптер, как правило slf4j. Понятно, что когда у нас есть адаптер на адаптер, есть риск бесконечной рекурсии. Про это надо помнить)
3) движок логгера - компонента, которая пишет логи. Примеры: log4j, log4j2, logback, JUL\JDK (встроенный в JDK)
4) appender - компонент, определяющий физическое место, куда пишутся логи: консоль, диск, БД, MQ... Вот полный список для log4j2 https://logging.apache.org/log4j/2.x/manual/appenders.html
5) фильтры и конверторы - позволяют отфильтровать или преобразовать сообщения на клиенте

Плюс 3 хороших совета из видео:
1) соблюдать гигиену classpath - чистить его от лишних библиотек
2) логи в теории могут стать основой мониторинга, когда мы отбрасываем специальным образом размеченную запись в лог, которая после обработки лога становится событием мониторинга
3) не добавлять как зависимость в свои библиотеки движок логгера. Пусть его выберет потребитель, а не разбирается с вашими транзитивными зависимостями

И 2 полезные утилиты - миграторы на logback и slf4j с альтернативных библиотек логирования.

Из минусов вижу пожалуй один - там идет рассказ о связке slf4j и logback. Если во время создания видео logback сильно обогнал log4j, то сейчас с log4j2 ситуация меняется. Неплохо бы добавить сравнение с log4j2.

#java #logging
Всем привет!

Какие компиляторы есть в Java? Сколько их вообще?
Простой ответ - один, называется javac. Им мы компилируем исходники в байт-код, который потом исполняет JVM.
Исполняет и что важно оптимизирует.
Вообще говоря, основные оптимизации происходят именно runtime, а javac является довольно простым.
Идея в том, что собирается статистика использования кода во время выполнения, часто используемый код компилируется в "нативный" - ассемблер для конкретного процессора, а неиспользуемый - удаляется. Таким образом получаем плюс еще один компилятор - JIT, он же Just in Time. Только на самом деле, исторически, компиляторов два - один быстрый, но оптимизирующий не оптимально))), второй - наоборот, медленный и хорошо оптимизирующий. C1 и C2, сейчас они используются в паре, подробнее можно почитать тут https://for-each.dev/lessons/b/-jvm-tiered-compilation

А можно без байт-кода? Да, есть AOT - Ahead of Time компилятор, называется native-image, поставляется в GraalVM https://www.graalvm.org/latest/reference-manual/native-image/
Он сразу компилирует в требуемый "нативный" код.
А если поддержки требуемой процессорной архитектуры нет? Был момент доминирования x86, но сейчас растет популярность ARM архитектур, а там, я так понимаю, тот еще зоопарк.
А для этого уже существует промежуточный язык и набор компиляторов LLVM https://llvm.org/. Что-то типа Java байт-кода, только не привязанный к Java. GraalVM его тоже поддерживает https://www.graalvm.org/latest/reference-manual/native-image/LLVMBackend/
А можно его использовать как runtime компилятор? Почему нет, в Azul JDK решили отказаться от C1\C2 и сделать свой компилятор с блекджеком и LLVM - https://www.azul.com/products/components/falcon-jit-compiler/ Да, ошибся немного, блекджека там, увы, нет)

А еще есть компиляторы Kotlin, Scala, Groovy, Jython, JRuby... И Kotlin native, также использующий LLVM https://kotlinlang.org/docs/native-overview.html В общем я сбился со счета)

#java #jvm #jdk #native_image #compilers