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

Если посмотреть на тему null safety с другой стороны - то это лишь один из аспектов более широкого принципа. Я бы сформулировал его как: "Знай свои данные".

Что же нужно знать:
1) кодировку текстовых данных - всегда явно ее указывать, не ждать, что всегда будет UTF-8
2) часовой пояс\locale - опять же не надеяться на то, что CI pipeline, тестовые и ПРОМ стенды работают в одном часовом поясе. А даже если это так - что на всех правильно настроен часовой пояс) И что никто не запусти код в другом часовом поясе. И никто не пришлет время из другого часового пояса
3) файловую систему, в частности разделители в пути к файлу. Для них есть специальные константы в Java Core, ОС в которой происходит запуск также можно определить
4) все проверки на injection - sql injection и аналоги
5) указание конкретных проверяемых исключений вместо Exception. Это не совсем данные, но часто исключения вызываются некорректными данными
6) unit тесты на граничные значения
7) ну и наконец null safety - может ли по бизнес-процессу значение принимать null или нет

Принцип можно расширить до инфраструктуры и добавить к примеру версии используемых библиотек и плагинов. Если версии не фиксировать - могут подтянутся новые в неожиданный момент с неожиданным поведением)

P.S. Если что-то забыл - дополняйте в комментах

#data #principles
September 8, 2023
Всем привет!

Постов долгое время не было, причина типичная - много работы. Вообще не помню времени, когда ее было мало((( И были ли вообще такие времена?)

Хотел бы поднять сегодня такую важную тему как взаимодействие разработчиков и сопровождения.
Для начала одна общеизвестная информация - разработчики и сопровождение исходя из своих задач обречены на противостояние.
Задача разработчиков - менять приложение, задача сопровождения - обеспечивать его работоспособность. А как известно: работает - не трогай) Любое изменение потенциальный источник проблем.
Отсюда часто следует одна крайность - сопровождение максимально критично относится к любым изменениям, разработка "виновна" по умолчанию, требуется строгое соблюдение регламентов, любая нестандартная просьба разработки встречается "в штыки".
Почему это плохо?
Сейчас основная методология разработки - это Agile в разных вариациях. Один из ключевых моментов в Agile - это команда, командная ответственность, гибкие решения в команде. А сопровождение в описываемом кейсе выступает внешним "врагом" - блокирует инициативы команды, замедляет скорость выпуска новых версий. А высокая частота выхода в ПРОМ - еще одна важная часть Agile.
С таким кейсом я, увы, сталкивался и наблюдал его губительный для команды эффект. Часто свои требования сопровождение объясняет требованиями надежности. Хорошее ли это объяснение - зависит от деталей. Если объяснение звучит как-то так - это снизит надежность, т.к. ... и идет описание причин - то да, хорошее.
Если слово надежность произносится, а никаких деталей не приводится - это признак того, что сопровождение боится изменений и не хочет развиваться.
Есть и другая крайность - сопровождение "согласно на все") Не выставляет никаких требований, принимает любые дистрибутивы. Кейс более редкий. Чем это плохо - разработчики опять же исходя из своих основных задач редко думают о том, как их код будет сопровождаться. Обычно на разработку времени хватает впритык.
Какой выход из данной ситуации?
Выставлять требования со стороны сопровождения.
Требования зависят от компании, отрасли, приложения, числа пользователей и много чего.
Но базовые требования могут быть такими:
1) список метрик, позволяющих отслеживать работоспособность
2) требования к логам - где и в каком объеме. Сюда же я бы добавил требования к фильтрации логов, с важным дополнением - возможность фильтрации зависит как от разработчиков бизнес-приложения, так и от разработчиков системы просмотра логов
3) требования к трассировке (tracing) - особенно важно если мы имеем дело с микросервисами
4) наличие инструкции для сопровождения в случае, если установка релиза требует ручных действий
5) наличие сценария отката на предыдущую версию. Это может быть выключение feature toggle или номер версии для отката. Самое важное - сама возможность отката. Это тоже требование, его нужно или соблюдать, или если это невозможно, например, в случае необратимых изменений в БД - составлять план действий на случай неудачной раскатки
6) фиксирование таймаутов внешних вызовов: я уже писал что бесконечные таймауты - одна из основных причин падения приложения
7) требования по UI для ручного разбора ошибок, если все предыдущие требования не помогли)

Почему я говорю "могут быть такие требования" - я все же изначально разработчик, поэтому имею некие предустановки и не вижу полной картины. Если есть возражения и дополнения - возражайте и дополняйте)

#dev #ops
September 16, 2023
September 19, 2023
Всем привет!

Может ли API с широким функционалом стать проблемой? Имея несколько реализаций от разных производителей ПО, являясь эталонной реализацией паттернов интеграции https://www.enterpriseintegrationpatterns.com/ при этом быть хуже конкретного продукта с ограниченым набором функционала?
Как можно догадаться из вопроса - ответ: да. Я про JMS vs Kafka.

JMS - это API из состава Java EE (сейчас Jakarta EE). Есть несколько реализаций: практически у каждого сервера приложений есть свой JMS - IBM, Oracle, JBoss, SAP, есть и Open source решения - ActiveMQ, Artemis MQ и другие.
Что есть в JMS? Стандарт широкий: есть очереди (точка-точка, ака P2P) и топики (подписка, ака PubSub), опциональная персистентность и транзационность, возможность настраиваемой маршрутизации и конвертации сообщений. И с security все хорошо.

У Kafka же только топики, нет продвинутой маршрутизации, трансформации, персистентность постоянная, транзакционности нету, гарантии однократной вычитки должен обеспечивать клиент. Да и вендор один. Но справедливости ради vendor lock нет, т.к продукт open source, за деньги только поддержка.

При этом Kafka успешно отвоевывает долю рынка. В чем же дело?

Секрет Kafka в том, что она выпустила достаточно простой, очень быстрый open source продукт, достаточный для большого числа клиентов. Этим нивелируется преимущество JMS в возможности выбора реализации. Причем Kafka быстрая с включённой по умолчанию персистентностью, а значит и высокой надёжностью. По скорости однозначно бьет все реализации JMS. Про то, как удалось добиться такого результата, я писал тут https://t.me/javaKotlinDevOps/91

В чем проблемы JMS:
попытка объять необъятное в API = переусложнение,
много вендорской специфики, которая может помешать смену реализации,
слишком большая роль брокера - все возможности по маршрутизации и трансформации не бесплатны по производительности, и кроме того ведут к тому, что обычная очередь превращается в Enterprise Service Bus, а у этой концепции есть свои минусы.

Я не хочу сказать, что JMS можно выкидывать, а лишь пишу почему Kafka удалось ее так сильно потеснить. Если вам нужно взаимодействие точка-точка и нет больших объёмов данных - JMS вполне подойдёт.

#kafka #jms #comparison
September 23, 2023
Всем привет!

Я уже писал о важности рефакторинга.
Но как оценить, что рефакторинг достиг своих целей?
Можно экспертно. Но не всегда этот вариант годится для обоснования времени на рефакторинг у бизнеса.
Можно ли как-то подтвердить эффект цифрами?
Самый простой вариант - если проблема в производительности. Тогда изменяем TPS - transaction per second - до и после и демонстрируем эффект.
А если проблема в сложности кода как это чаще всего бывает?
Тогда на помощь могут прийти следующие метрики:
- цикломатическая сложность кода и другие похожие метрики https://www.tiobe.com/knowledge/article/demystifying-code-complexity/ После рефакторинга сложность должна снизиться, при этом в процессе может временно повышаться. А стандартные метрики хороши тем, что уже есть утилиты для их подсчёта. Например, Checkstyle https://checkstyle.org/checks/metrics/cyclomaticcomplexity.html или Sonarqube https://habr.com/ru/articles/565652/ Также благодаря тому, что эти метрики широко известны в узких кругах разработчиков )) их проще объяснить бизнесу. Или пусть изучают формулу, или верят на слово разработчикам)
- если сложность кода по каким-то причинам не подходит - можно рассмотреть среднее число строк в классе или методе. После рефакторинга это число также должно снижаться,
- в некоторых случаях может даже подойти абсолютное число строк кода. Если приложение «раздуто», то результатом рефакторинга станет уменьшение размера кодовой базы.
- число TODO в коде. Каждая TODO - потенциальный техдолг.
- число длинных комментариев в коде. Если код самодокументирующийся - с говорящими названиями методов и классов - то длинный комментарий можно рассматривать как аналог TODO
- скорость вникания в код сервиса для новых разработчиков. Изменить достаточно трудоёмко, но метрика хорошая
- число ошибок ПРОМ, связанных с изменяемым кодом. Если их много - значит с кодом что-то не так
- постоянно увеличивающееся или стабильно большое время разработки новых фичей. Например, по сравнению с временем в начале жизненного цикла сервиса. Сравнивать с другими командами и сервисам часто не корректно.

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

#java refactoring #metrics
September 25, 2023
Всем привет!

Продолжая тему рефакторинга. Основное предусловие для начала рефакторинга - это наличие хорошего тестового покрытия. Т.к. мы не меняем бизнес функционал, а улучшаем код либо для повышения производительности, либо для его упрощения. Но при этом нужно гарантировать, что бизнес функционал не сломался, т.е. не появились регрессионные баги. Ведь рефакторинг, в отличие от новой фичи, может затронуть все приложение. Соответственно, баги могут появиться в любом месте, и без тестового покрытия - это большие риски.
Можно рассмотреть похожий кейс. У нас есть монолит, мы хотим распилить его на микросервисы. Это тоже своего рода рефакторинг, только на уровне архитектурном уровне. И тоже аналогичное условие для его начала - наличие достаточного набора тестов. В данном случае повышается важность интеграционных тестов.
Важный момент: в процессе подготовки к разбиению монолита или серьёзному рефакторингу может возникнуть вопрос-предложение - а давайте все выкинем и напишем заново. Так вот - одним из базовых критериев для ответа на этот вопрос также является покрытие тестами. Очевидно, не единственным, но важным. Другие критерии - объем техдолга, соответствие текущей архитектуры и целевой.
Еще кейс - разработчик «боится» рефакторить код, т.к. он слишком сложный или затрагивает слишком много зависимостей. С тестами решиться на рефакторинг намного проще.

Вывод простой - пишите тесты, это страховка при рефакторинге)

#refactoring #unittests #microservices
September 26, 2023
Всем привет!

Я упоминал в посте про JMS vs Kafka про ESB - Enterprise Service Bus. Она же Корпоративная Сервисная Шина.
Какие плюсы и минусы данного решения?

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

Минусы такие:
1) т.к. ESB - это отдельная система, то ее разрабатывает как правило отдельная команда, которая быстро становится узким местом. Особенно при внедрении микросервисной архитектуры и резком увеличении числа интеграций
2) ESB как правило вносит дополнительные задержки, что особенно критично при синхронном взаимодействии
3) как правило ESB предлагают коммерческие компании, что приводит к vendor lock. Слезть с такого решения будет сложно
4) неочевидная штука - с одной стороны команда ESB унифицирует все API. Но с другой - API становятся перегруженными. Там будут какие-то стандартизированные для всех поля, общие базовые типы, которые во многих случаях будут избыточными
5) также ESB из-за стандартизации затрудняет развитие API. Т.к. унификация, а кроме того больше команд участвует в согласовании - три вместо двух

Вывод: на данном этапе развития ПО идея ESB выглядит избыточной.

Но что же с плюсами, как добиться того же результата с API точка-точка и микросервисной архитектурой?
1) унификация вещь полезная, главное чтобы она не была избыточной. Архитектор может выставить требования по API, DevOps - встроить их проверку в pipeline.
2) единая точка контроля - в случае облачной среды такой точкой может быть Istio или k8s. Либо ставить proxy на границах сред.
3) для переиспользования можно использовать каталог API. Да и не всегда переиспользование полезно, см. выше про избыточное API. Также отдельное API для каждого потребителя позволяет лучше контролировать доступ к данным

#api #esb
September 29, 2023
October 2, 2023
Всем привет!

Сегодня хотел бы поднять такую тему - что должно быть в проекте сервиса (в исходниках)?
Кроме собственно кода и файлов с настройками.

1) readme.md
Наличие: обязательно.
Содержимое: описание проекта, его идентификатор (для DevOps pipeline или в вашем реестре сервисов), описание вариантов сборки (отладка, запуск модульных и интеграционных тестов, чистовая сборка), структура каталогов, возможно важные особенности сборки

2) .gitignore
Наличие: обязательно

3) test.http
Наличие: крайне желательно
Содержимое: список URL для отладки на localhost в формате, который понимает IntelliJ IDEA

4) IDEA run configuration
Наличие: крайне желательно
Да, конфигурации тоже можно сохранять. Особенно полезны для больших проектов, допускающих отладку отдельных частей для скорости.

5) скрипты и настройки CI
Наличие: крайне желательно
Часто скрипты меняются вместе с кодом, лучше держать их вместе

6) todo.md
Наличие: желательно
Содержимое: техдолг с точки зрения разработчиков сервиса. Я специально делаю акцент на происхождение, т.к. еще есть внешний техдолг от архитекторов, сопровождения, ИБ, его обычно заводят в JIRA. Почему бы и внутренний техдолг не завести в JIRA? Можно, но есть два риска: если работа идет не по Scrum - задача потеряется в недрах системы, если работа идет по Scrum - слишком рьяный Scrum мастер в рамках гигиены JIRA может настоять на удалении задачи как непонятной\неактуальной. Храня же техдолг вместе с кодом мы можем свободно уточнять формулировки, разбивать на более мелкие задачи для последующего переноса в JIRA с взятием в ближайший спринт.

7) Maven или Gradle wrapper
Наличие: желательно, чтобы не зависеть от наличия утилиты в среде сборки

8) профили checkstyle и ему подобных утилит статического анализа кода
Наличие: возможно, если требуется подстройка для вашего сервиса

9) статическая часть папки .idea
Наличие: возможно по договоренности с командой

10) settings.xml для Maven
Наличие: возможно если они меняются от проекта к проекту

11) документация, естественно через автогенерацию
Наличие: возможно, особенно для библиотек

P.S. Еще может возникнуть вопрос про схемы API - их лучше держать отдельно, чтобы физически разделить интерфейс и реализацию.

#sources
October 3, 2023
Всем привет!

Хорошая подробная статья про кодировки в Java и что изменилось в Java 18 https://habr.com/ru/companies/jugru/articles/709952/
Еще порадовало, что кто-то заморочился и сделал вот такой навигатор: https://habr.com/ru/articles/147843/ )))

А вывод следующий: в существующих Java сервисах надо явно указывать кодировку, как я и говорил ранее: https://t.me/javaKotlinDevOps/193 В новых написанных на Java 18+ в большинстве случаев можно положится на кодировку по умолчанию - UTF-8. Если конечно вы не храните данные в другой кодировке) Или не работаете с Windows и ее консолью и файловой системой. Или кто-то в вашей команде
не проводит отладку на Windows.

#java #encoding
October 5, 2023
Всем привет!

Я уже писал о проблеме интероперабельности Kotlin-Java касающейся null safety - https://t.me/javaKotlinDevOps/190
Есть и еще одна, коллега столкнулся с ней недавно.
В Kotlin четко разделяет изменяемые и неизменяемые коллекции на уровне типов, по умолчанию предлагая делать их неизменяемыми.
В Java наоборот - по умолчанию все коллекции изменяемые, хотя неизменяемые создать тоже можно, например, Collections.unmodifiableXXX, но это не единственный способ.
Итого: предположу, что в Kotlin условно 90% коллекций немодифицируемые, в Java - наоборот 90% модифицируемые.

Что же будет при передаче коллекции из Kotlin в Java?
Да, хорошая практика независимо от языка - не менять передаваемые в метод параметры. Но эта практика не стимулируется к использованию Java.
Да, иммутабельность можно проверить, но делается это довольно криво и я подозреваю делается редко: https://ru.stackoverflow.com/questions/608545/collections-unmodifiable-как-определить
Отсюда получаем, что с большой вероятностью возможна ошибка UnsupportedOperationException на вставке в эти коллекции в Java.

#java #kotlin
October 7, 2023
Всем привет!

Проверяемые исключения - еще одна вещь, которой отличаются Java и Kotlin.
В Kotlin их нет, и вот тут описано почему https://kotlinlang.ru/docs/reference/exceptions.html
Там же есть ссылка на диалог таких известных людей как Bruce Eckel и Anders Hejlsberg на эту тему https://www.artima.com/articles/the-trouble-with-checked-exceptions
Вот тут есть его русский перевод https://habr.com/ru/articles/221723/

В целом соглашусь с основным аргументом авторов: с ростом кодовой базы - а тут важно помнить, что кроме кода сервиса мы еще используем кучу библиотек включая вездесущий Spring Framework - проверяемых исключений становится слишком много. А их выборочная обработка в бизнес приложении, которое активно использует внешние библиотеки, часто не нужна. Т.е. есть цепочка вызова из к примеру 10 сервисов, а обработка исключений - в одном из них, максимум в двух. В остальных случаях их приходится пробрасывать. Отсюда приходим к throws Exception. А это явный антипаттерн.
Следовательно, в большинстве случаев вред от проверяемых исключений перевешивает пользу. Хотя идея - если рассматривать ее именно как идею - красивая: объявляем в API не только типы входящих и исходящих параметров, но и потенциально возможные ошибки. Вот только удобной реализации пока никто не придумал)))

#java #kotlin #exceptions #checked_exceptions
October 9, 2023
Объявляете ли вы проверяемые исключения в Java в своем коде?
Anonymous Poll
36%
Да
64%
Нет
October 11, 2023
Что делаете с проверяемыми исключениями из Java Core и внешних библиотек?
Anonymous Poll
38%
Честно пробрасываю все
54%
Сразу же ловлю и обрабатываю
23%
throws Exception скрипя зубами)
October 11, 2023
Всем привет!

Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий. Но есть нюанс. Схема OpenAPI - внешний артефакт. Он лежит либо в git репозитории или API Studio от Swagger. Код по нему генерируется в каталоге сборки. Забыть обновится при выходе новой версии сложнее как раз из-за чёткого понимания того, что API - внешнее. Хотя конечно же можно )
Другое дело Java API. Это про сути ещё одна из десятков библиотек, подключенных к проекту. Версию библиотеки мы фиксируем как это принято при управлении зависимостями. Забыть о том, что это внешнее API, гораздо легче.
Я сейчас говорю не только про кейс, описанный в статье. Ещё есть вариант обмена данными через распределенный кэш, путём сериализации Java POJO объектов, встречал его на практике. А самый яркий антипаттерн при похожем подходе - обмен данными через БД. В этом случае как правило обмениваются скриптами БД, а не классами. Но идея похожа - зачем нам лишняя сущность в виде схемы, лишние преобразования, когда уже есть код. Или уже есть таблица в БД. Конечно, интеграция через БД стала антипаттерном в том числе и потому, что БД - это не только схема, но ещё и транзакции, блокировки, триггеры. Но главную причину я озвучил выше - каждая команда будет считать базу своей внутренней, забывая, что это API. Проблема психологическая, не техническая.
Итого: подход интересный, имеет права на жизнь (я про обмен jar-никами, не про интеграцию через БД), но требует дисциплины. Или автоматизации на этапе CI, позволяющей не надеятся на человеческий фактор.

P.S. Как говорится, не OpenAPI единым - есть ещё Protobuf, GraphQL, xsd наконец. Но самый распространённый - OpenAPI, поэтому везде упоминается он.

#api #OpenAPI #integration
October 13, 2023
Всем привет!

Я уже писал про один особенный класс в Java - enum - https://t.me/javaKotlinDevOps/14

Вот ещё один - массив.
1) да, массив - тоже класс, хранится в куче, наследуется от Object.
2) Главная особенность этого объекта - его класс не определен заранее, JVM создаёт его динамически. Соответственно, его исходники нельзя посмотреть и от него нельзя наследоваться. Имя у него строится по принципу [X, где X - кодирует тип элементов массива, скобка - это скобка) Например, [I для массива int.
3) размер массива как известно фиксируется при создании и его можно получить вызвав array.length. Но интересно, что это не поле класса, значение хранится в заголовке объекта
4) исходя из сказанного выше массив - это особый класс, плохо вписывающийся в систему классов Java. Для него даже пришлось ввести 2 специальные инструкции байткода - для создания и получения длины
5) массив используется под капотом у ArrayList. Если массив статичен, то ArrayList - динамически растёт по мере его заполнения. Ну и является «нормальным» классом)
6) элементы массива расположены последовательно друг за другом в heap, что сильно ускоряет поиск\вставку по номеру элемента
7) массивы ковариантны и поэтому не типобезопасны. Пример кода, который скомпилируется, но упадет в runtime:
Integer[] a1 = new Integer[10];
Object[] a2 = a1;
a2[0] = "Привет ArrayStoreException"
ArrayList является generic и поэтому инвариантен - аналогичный код не скомпилируется:
List<Integer> a1 = new ArrayList()
List<Object> a2 = a1;
8) массивы могут содержать как примитивы, так и объекты, что выгодно отличает их от коллекций. Поэтому основное применение массива, которое я вижу, работа с большим количеством примитивных типов - это будет эффективно с точки зрения памяти и отсутствия операций boxing/unboxing. Зачем нужны массивы объектов - для использования в ArrayList, других применений не могу придумать)

P.S. На написание поста меня подтолкнула эта статья - https://habr.com/ru/articles/753638/, но она для совсем джунов-джунов, решил расширить и повысить концентрацию полезной информации)))

#java #arrays
October 17, 2023
Всем привет!

Среди первых постов этого канала был пост про k8s - для чего он нужен https://t.me/javaKotlinDevOps/6
Но я забыл рассказать про Service Mesh - что же она добавляет к k8s. Если вы не понимаете, что за Service Mesh такой - самой известной реализацией является Istio https://istio.io/latest/docs/ На его примере хочу рассказать про Service Mesh.

Начал искать материалы и сразу наткнулся на серию отличных статей:
https://habr.com/ru/companies/flant/articles/438426/
https://habr.com/ru/companies/flant/articles/569612/
https://habr.com/ru/companies/oleg-bunin/articles/726958/
Рекомендую их почитать, там есть и про устройство Istio на сетевом уровне, и про решаемые им задачи, и про вносимые данной технологией риски.

Для тех, кому лень читать поработаю продвинутой версией Yandex GPT.
Основные "плюшки" Istio:
1) возможность аутентификации и авторизации запросов как по адресам, url-ам, так и с помощью OAuth
2) продвинутые возможности балансировки - например, привязка клиента к конкретному серверу или геопривязка: перенаправление только на экземпляры сервиса, находящиеся в том же гео-кластере
3) реализация паттерна Circuit Breaker, повторов и настройка таймаутов для запросов
4) продвинутые возможности маршрутизации: по URL и http заголовкам
5) реализация канареечного развертывания и зеркалирования траффика
6) TLS Termination и Origination - снятие и добавление TLS шифрования на входе\выходе из namespace, что позволяет полностью переложить работу с сертификатами с разработки на сопровождение

Вывод следующий: Service Mesh - новый уровень абстракции поверх обычного облака (k8s). Да, он добавляет сложность, особенно в части сопровождения. Вносит небольшие задержки, которые в определенных случаях могут быть критичны. Требует ресурсов, что также может быть важно. Но если его "плюшки" вам полезны - оно того стоит)

#istio #k8s #service_mesh #cloud
October 20, 2023