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

Я уже писал про один особенный класс в 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
Всем привет!

Среди первых постов этого канала был пост про 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
Всем привет!

К вопросу о кратком пересказе текста. Как вы наверное знаете, недавно такую фичу выкатил Яндекс - назвал ее YandexGPT.

Вот пример краткого пересказа двух статей из предыдущего поста.

Istio в разрезе: что умеет и не умеет самый популярный Service Mesh (обзор и видео доклада) / Хабр
• Istio - это система управления Service Mesh, которая позволяет реализовать разные паттерны по управлению TCP-трафиком в проекте.
• Istio предоставляет набор интерфейсов для настройки и управления компонентами Service Mesh.
• Istio может влиять на надежность приложения, но требует правильной настройки и использования.
• Istio также влияет на latency, безопасность и масштабирование.
• В Istio можно использовать протокол Delta xDS для сокращения нагрузки на Control Plane и сеть.
• Ожидается, что Ambient Mesh, новая функция Istio, упростит обновления и снизит нагрузку на Control Plane.
https://300.ya.ru/PxCuGmdO

Что ждать от внедрения Istio? (обзор и видео доклада) / Хабр
• Istio - частный случай «сервисной сетки» (Service Mesh), понятия, о котором наверняка все слышали.
• Istio влияет на трафик, возможности для его мониторинга, безопасность mTLS.
• Istio имеет свой декларативный язык для управления сетью.
• Istio интегрируется с сторонними инструментами для мониторинга, например, с дашбордом Kiali.
• Istio предоставляет возможности для внедрения трассировки на основе Jaeger.
• Безопасность mTLS в Istio считается безопасной.
• Вопросы к Istio: влияние на приложение, кластер, observability, безопасность mTLS.
https://300.ya.ru/4cNaxU0s

Что хочется отметить:
1) ИИ не умеет структурировать тезисы, идет сверху вниз
2) ИИ не умеет выбирать ключевые фичи и делать акценты
3) "Безопасность ... считается безопасной"

P.S. Что касается п.3 - а может ИИ уже научился шутить и нам стоит начинать бояться?)

#ai #yandexgpt #yandex
Всем привет!

Прочитал книгу Лемер "Масштабируемый рефакторинг". В целом понравилась, с важным дисклеймером.
С одной стороны основные мысли в книге вполне себе "капитанские". С другой - о них очень легко забыть)))

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

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

2) рефакторинг нужно делать для кода в вашей области ответственности. Если за код отвечает другая - не надо его трогать без согласования

3) нужно понять - не является ли код deprecated или неиспользуемым. Часто код забывают удалять, все его использование ограничивается модульными тестами

4) нужно изучить - почему код стал таким. Зачем?
а) возможно выяснится, что "это не баг, а фича"
б) когда станет понятно, на почему возникли те или иные компромиссы в коде - это изменит отношение к коду. Все же приятнее улучшать сложный legacy код, а не "переписывать этот го..код"

5) нужно ответить себе на вопрос - почему код нужно рефакторить именно сейчас. А возможные ответы на этот вопрос приводят к необходимости метрик для бизнеса, о которых я уже писал https://t.me/javaKotlinDevOps/197

6) важно собрать команду с двумя типами участников: full time разработчики и эксперты. Для этого нужно договориться с руководителями о их полном или частичном подключении к задаче рефакторинга. Искать стоит людей, либо заинтересованных в результате рефакторинга, либо тех, кому надоела рутина и хочется, что-то поменять

7) нужен канал или страничка, где регулярно будут публиковаться прогресс рефакторинга. В случае, если прогресс будет - это может мотивировать на подключение к рефакторингу новых участников. Прогресс нужно сопоставлять с планом, при необходимости вносить корректировки. Также нужен митап или чат, где заинтересованные лица смогут задать вопросы.

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

9) после окончания рефакторинга важно проконтролировать, что все потребители знают об изменениях и либо уже используют их, либо запланировали обновление. Речь может идти о переходе на новое API, новый фреймворк, новый DevOps, новую версию библиотеки. Для ускорения процесса перехода нужны:
а) рассылка
б) демонстрация
в) инструкция
г) чат, куда можно задать вопросы
д) возможно регулярный митап для ответов на сложные вопросы

#books #refactoring #book_review
Всем привет!

Сегодня хочу поднять вопрос анемичной доменной модели. Давно холиварные вопросы не поднимал)

Одним из первых это понятие ввел Мартин Фаулер, см. https://martinfowler.com/bliki/AnemicDomainModel.html
Анемичной модели противопоставляется т.наз. "богатая" или, как я бы ее назвал, полноценная доменная модель.
В чем разница?
В анемичной доменной модели объекты по сути аналогичны DTO, их можно реализовать в виде Java records или Kotlin value object.
В полноценной - в объектах кроме данных есть бизнес-логика.
Вот аргументы сторонников полноценной модели:
https://www.baeldung.com/java-anemic-vs-rich-domain-objects
https://www.youtube.com/watch?v=lfdAwl3-X_c - особенно рекомендую, Егор как всегда подходит к теме "с огоньком")
Вот - сторонников анемичной модели: https://habr.com/ru/articles/346016/

Я в этом споре все же склоняюсь к полноценной модели.
Т.к. доменный объект - это не DTO, он должен содержать нечто большее. А именно - бизнес-логику. А вынося логику в отдельные сервисы легко так сильно ее размазать по коду, что это приведет к дублированию и ухудшению читаемости.
Более того: если модель становится анемичной - это может быть признаком, что модель не нужна, сервис является простым и можно вполне себе работать с DTO.
Особенно актуальна "богатая" доменная модель, если вы пытаетесь следовать практике DDD - Domain Driven Design. Собственно, ее автор, Эрик Эванс, сторонник этого подхода.
Да и есть смотреть определение класса в ООП - это не просто хранилище данных. Объект - это отражение сущности из реального мира. А в реальном мире объекты - кот, автомобиль, заказ - являются не только набором характеристик, но и могут что-то делать)

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

Идея в том, что не надо боятся добавлять методы в объекты доменной модели. Более того, при проектировании стоит изначально думать о том, какими будут эти объекты.

Что касается нарушения принципов S и I из SOLID.
Не надо относится к этим принципам догматично. Если так делать - то у нас в итоге будет куча DTO с парой полей, куча интерфейсов с одним методом и взрыв мозга у людей, которые попытаются вникнуть в этом код с нуля) Важен баланс.

#anemic-vs-rich-domain-objects #holy_war #solid #oop
Всем привет!

Сегодня пятница, поговорим немного о магии.
Что я считаю одним из самых плохих качеств разработчика - веру в магию.
Симптомы магического мышления: фразы типа "ну вроде починил", "ну вроде работает". Или хаотичный перебор настроек в надежде, что все заработает. Или нежелание что-то менять в коде, из-за боязни поломать.
У любой проблемы при разработке ПО есть причины. Иногда они очевидны, иногда нужно потратить дни или недели, чтобы понять - почему оно так работает.
Бывает так, что не хватает времени, чтобы разобраться в причинах. Бывает так, что корни проблемы лежат в области, где не хватает компетенции - СУБД, внешняя система, pipeline. Это нужно понимать и признавать. Решение - искать специалиста или просить больше времени на разбор. Четыре лайфхака по самостоятельному разбору проблем:
1) посмотреть исходный код проблемного компонента, даже если он не ваш
2) погуглить)))
3) внимательнее читать логи. Часто вижу, что первая подозрительная запись в логах останавливает поиск. А если промотать еще десяток строк - лежит нормальное описание ошибки.
4) разбить проблему на части, т.к. часто самые загадочные случаи - это следствие череды ошибок.

Ну и прекрасная иллюстрация того, что любая магия имеет объяснение - вот эта статья: https://habr.com/ru/articles/759344/

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

Те, кто читал книжку Чистый код Мартина думаю помнят, что переменные должны иметь говорящие имена для повышения читаемости кода. Да и не только там эта мысль проходит. Я двумя руками за, писал уже об этом на канале.
Теперь внимание, вопрос - а можно ли тогда использовать переменные типа i или j в циклах? Откуда вообще взялись i и j, почему не a, b?

https://stackoverflow.com/questions/4137785/why-are-variables-i-and-j-used-for-counters

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

Что включает в себя понятие объекта?
1) объект может иметь данные
2) данные объекта можно менять
3) объект может иметь поведение - методы
4) от класса объекта можно наследоваться
5) объектов одного класса может быть несколько
6) каждый объект уникален - находится в heap по своему адресу. Т.е. имеет identity

Можно ли отобрать у объекта что-то из вышеперечисленного в Java?

1) final class - запрещаем наследование
2) sealed class - если полный запрет нам не подходит, то ограничиваем наследование https://habr.com/ru/companies/otus/articles/720044/
3) final поля - запрещаем менять данные класса после создания объекта - иммутабельность
4) records - запрещаем методы и изменение полей https://habr.com/ru/articles/487308/ Основое применение - DTO, где есть только данные и их нежелательно менять.
5) lambda - можно рассматривать как объект-функцию без данных, хотя технически это не так - JVM под капотом транслирует ее в статический метод https://javadungeon.wordpress.com/2017/08/02/java-8-lambdas-under-the-hood/
6) object в Kotlin - синлетона на уровне языка в Java нет, но такую конструкцию сделали в Kotlin
7) value class - еще не реализованная в Java концепция, которая по сути добавляет в язык что-то среднее между примитивным типом и объектом. Т.е. у нас будет объект, но в плане занимаемой памяти он будет почти также эффективен, как и примитив. Что важно: т.к. это объект - его можно будет использовать в generics. Ура-ура!. Детали: https://www.baeldung.com/java-valhalla-project Но ничего не бывает бесплатно - у такого объекта не будет identity, т.е. два объекта с одинаковыми полями считаются одинаковыми. Также, как это сейчас происходит с примитивными типами. Да, для объектов это уже сейчас можно реализовать на уровне кода. А тут идея сделать тоже самое на уровне JVM. Т.е. JVM может (обязана?) оставить один экземпляр для всех одинаковых объектов. Причем так, как это сделано сейчас со строками - вариант не очень, т.к. остается "дыра" с конструктором, который по определению всегда создает новый объект. Т.е. для value class нельзя использовать публичный конструктор, нужен какой-то фабричный метод - как элемент языка. Примеры, когда это полезно: те же классы-обвертки для чисел или географические объекты.

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

Минутка самообразования. В России есть две крупнейших конференции по Java разработке - JPoint и Joker. Они платные, с одним бесплатным днем, доступным после регистрации. Но главное - через какое-то время все доклады конференции, которые были записаны, становятся открытыми. Уже доступны доклады с JPoint 2023 - https://www.youtube.com/playlist?list=PLVe-2wcL84b9iHBMgj3Mjgr7Lg-FER8jP
Докладов целых 60 штук, тематика очень разнообразная, в отличие от прошлых лет. Я для себя нашел как минимум с десяток интересных.
Enjoy)

#conferences #jpoint
Всем привет!

К двум моим статьям про k8s (https://t.me/javaKotlinDevOps/6) и Istio (https://t.me/javaKotlinDevOps/210) прямо напрашивается третья - про Openshift.

Тут может возникнуть вопрос - а что это вообще такое и почему напрашивается?)
Ответ: это "допиленный напильником" k8s от компании Redhat для enterprise.
Поэтому если вы работаете в enterprise, особенно кровавом, то тема актуальная)

Второй вопрос, который может возникнуть - какой такой западный enterprise в России сейчас?
Ответ: есть opensource версия https://habr.com/ru/companies/redhatrussia/articles/511800/

Итак, что же добавляет Openshift к k8s.

1) Istio - включен в дистрибутив

2) встроенный Docker Registry

Небольшое уведомление. Основной пласт возможностей, которые предоставляет Openshift, реализован за счет кастомных ресурсов - CRD - и оператора, который их обрабатывает.
https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
https://habr.com/ru/companies/slurm/articles/556860/
Идем дальше.

3) настройки безопасности: ролевая модель https://docs.openshift.com/container-platform/4.8/rest_api/role_apis/role-apis-index.html, авторизация https://docs.openshift.com/container-platform/4.8/rest_api/authorization_apis/authorization-apis-index.html , OAuth https://docs.openshift.com/container-platform/4.8/rest_api/oauth_apis/oauth-apis-index.html

4) механизм шаблонов (ресурс типа Template) - позволяет в одном файле задать несколько ресурсов с параметрами. Значения параметров можно как задать в самом шаблоне (значения по умолчанию), так и передать в момент применения Template
https://docs.openshift.com/container-platform/4.8/rest_api/template_apis/template-apis-index.html

5) Имея механизм шаблонов, ролевую модель и настройку лимитов из k8s можно упростить создание новых namespace: для этого вводится проект - аналог namespace в Openshift. https://docs.openshift.com/container-platform/4.8/rest_api/project_apis/project-apis-index.html

6) самое интересное - концепция build-related ресурсов. Идея в том, что при изменении исходников или появлении нового образа в Docker происходит автоматическая сборка и установка новой версии приложения. Т.е. фактически мы получаем встроенный в кластер CI\CD.
https://docs.openshift.com/container-platform/4.10/cicd/index.html
https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/buildconfig-build-openshift-io-v1.html
Данная концепция приводит к тому, что стандартный ресурс Deployment в Openshift заменяется на очень похожий DeploymentConfig, поддерживающий пересоздание подов при появлении нового кода https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/deploymentconfig-apps-openshift-io-v1.html

7) само собой новая веб-консоль и новая CLI утилита (oc), поддерживающие все вышеописанные возможности.

Вот пожалуй и все основные отличия Openshift. В целом неплохо, хотя и не так революционно, как Istio

#openshift #istio #cloud #k8s
Всем привет!

Вопрос на собесе для джуна - что будет, если в Java число разделить на ноль?
А если это число с плавающей точкой?
Или все-таки это вопрос не для джуна, а со звездочкой... )))
Детали: https://www.baeldung.com/java-division-by-zero
А если говорить про задачи на собес - то можно вот такую: https://habr.com/ru/articles/573080/

P.S. Обратите внимание на автора блога.

P.P.S. На самом деле мне не очень нравятся задачи такого рода, т.к. такие вещи нужно просто знать. А главный вопрос - а нужно ли знать? Подозреваю, что 80% разработчиков с таким кейсом не столкнется в своей работе.

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

Формат yaml все больше входит в нашу жизнь, самые очевидные примеры - k8s, Docker Compose и Ansible.
Его главным преимуществом я считаю ссылки - соблюдается принцип DRY.
Главным недостатком - зависимость от числа tab\пробелов как в Python.

А чтобы не дать лишнему пробелу все сломать - нужна валидация.

Для начала - валидация синтаксиса https://yamllint.readthedocs.io/en/stable/index.html
Хотя в списке ОС для скачивания нет Windows - он ставится на Win с помощью python + pip.
Также есть плагин для IDEA https://plugins.jetbrains.com/plugin/15349-yamllint

Да, подсветка синтаксиса хотя и не заменяет валидацию, но тоже полезна - IDEA, Notepad++ и Atom поддерживают его из коробки.

Далее можно прикрутить валидацию, специфичную для конкретной области применения.
Для k8s есть утилиты kubeval, kube-score и Polaris см. https://habr.com/ru/companies/flant/articles/511018/
Они проверяют манифесты на соответствие best practices.
В docker-compose валидация вызывается с помощью команды https://docs.docker.com/engine/reference/commandline/compose_config/
Для Ansible - базовые проверки встроены в Ansible, также есть ansible-lint, детали см. https://www.deploymastery.com/2023/03/31/how-to-verify-ansible-playbook-syntax/

Альтернатива - написать нужные проверки самому. Тут есть 4 библиотеки из уже приведенной выше статьи:
config-lint, copper, conftest, Polaris
https://habr.com/ru/companies/flant/articles/511018/ Основное различие - в языке, на котором будет ваш код проверки. Есть и декларативный yaml, есть и императивный JS.

#yaml #k8s #ansible #docker-compose #validation
Всем привет!

С большой вероятностью не ошибусь, если скажу, что большинство разработчиков не любит работать с legacy. Вижу это в резюме, сталкиваюсь с этим периодически на собеседованиях.
Почему? Там много кода, код непонятный, разбираться долго, нет новых технологий, есть куча правил, которые так просто не нарушишь...

А есть ли плюсы в работе с legacy?
Я как человек, примерно половину своей карьеры плотно работавший с legacy, могу сказать - да, есть.

Плюсы такие:
1) если речь идет не про поддержку, а про глубокий рефакторинг, то распилить legacy на микросервисы - это сложная архитектурная задача. Решив ее, получаешь опыт проектирования возможно даже больший, чем при создании этих сервисов с нуля. И этот опыт можно хорошо продать
2) не все legacy = го...код. Возможно все начиналось с хорошо спроектированного небольшого приложения, которое вовремя не разделили на части. Либо не хватало времени, либо не было необходимости. В таком случае в legacy приложении, особенно если оно достаточно большое, можно подсмотреть доказавшие свою полезность паттерны и архитектурные решения. А именно умение проектировать и наработанные паттерны являются основным преимуществом разработчика. Технологии меняются и их всегда можно доучить.
3) я достаточно много писал и буду писать о том, как важна читаемость кода, его компактность и в конечном итоге снижение когнитивной нагрузки при работе с кодом. Казалось бы это не про типичный legacy. В целом да. Но если все же научится "переваривать" большие объемы кода - это будет еще одним плюсом в копилку полезных навыков разработчика. Т.к. есть теория про "чистый код", а, увы, есть суровая практика. И "бизнес" любит людей, которые могут решить любую проблему, в т.ч. и с legacy.
4) любой сервис становится legacy. Поэтому отказываясь работать с legacy - сужаешь список своих возможностей. На растущем рынке это не критично, но всегда ли он будет так расти?

#legacy #skills
Всем привет!

Пару слов про отладку тестов, на примере Maven проекта и IDEA.

Если речь про модульные тесты - там проблем нет, ставим breakpoint и запускаем нужный тест в IDEA.

Проблемы есть с интеграционными тестами. Т.к.
1) тесты и код, который тестируем, запускаются в разных процессах
2) обычно интеграционные тесты запускаются с помощью Maven (Gradle), т.к. нужно поднять окружение, и проще и правильнее эти настройки один раз сделать в Maven и забыть.

Какие у нас варианты с отладкой?

1) вариант, описанный тут https://stackoverflow.com/questions/49390110/how-to-debug-integration-test-in-intellij
Если вкратце - запускаем тесты с помощью Maven в специальном отладочном режиме плагина failsafe (или surefire), потом подключаемся к процессу из IDEA в режиме удаленной отладки. Отладка называется удаленной, т.к. нужно подключаться к другому процессу. В данном случае на localhost.

2) запускаем наш сервис в "DEV режиме" через Maven. Также, как это делается для отладки кода и проверки функционала локально вручную. Обычно под это дело в проекте есть отдельный профиль Maven. После этого запускаем нужный интеграционный тест в Debug режиме из IDEA, из окна с кодом теста. Как минимум, интеграционные тесты Cucumber и Spring Boot IDEA поддерживает.

3) а что, если нужно поставить точку прерывания в коде сервиса, а не тестов? Тогда настаиваем в IDEA Run configuration для нашего контейнера сервлетов \ сервера приложений. Запускаем ее в DEBUG режиме, после чего запускаем тесты также, как и в предыдущем варианте.

Варианты 2 и 3 мне нравятся больше, т.к. не нужно использовать консоль - все делается средствами IDEA.

#debug #java #tests #integration-tests
Всем привет!

Продолжая тему Maven. Когда я изучал документацию по Maven, то наткнулся такую несколько странную возможность, как отключение компиляции через опцию -Dmaven.main.skip.
Почему, зачем? На первый взгляд - бессмысленно.
Но недавно на практике понял зачем она нужна.

Предположим в вашем pom есть некий плагин с достаточно сложными нестандартными настройками. Есть процесс, в котором нужно выполнить его goal. Если мы просто запустим goal командой mvn plugin:version:goal, то настройки из pom будут проигнорированы. Предположим, задать их из командной строки невозможно, т.к. плагин это не поддерживает. А даже если возможно - это будет дублирование, нарушение DRY, т.е. тоже плохой вариант)
Хуже всего то, что наш плагин находится в build lifecycle https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference после фазы compile. Пусть проект уже собран, но как известно инкрементальная компиляция в Maven существует, но с ней есть нюансы: https://stackoverflow.com/questions/16963012/maven-compiler-recompile-all-files-instead-modified/19653164#19653164
К слову - именно по скорости компиляции Maven сильно проигрывает Gradle.

Так вот - именно тут опция -Dmaven.main.skip и выходит на сцену, сильно уменьшая время выполнения.

P.S. Да, по моему опыту - плагин для компиляции Kotlin, увы, ее не поддерживает.

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

Я периодически провожу код-ревью. И лично у меня ранее был страх - а вдруг я не замечу что-то важное. Смотришь PR, явных ошибок не видно, но апрув "не ставится". А когда Pull Request (PR) очень большой - даже не хочется его открывать, т.к. примерно понимаешь, какой объем информации придется "загрузить в голову", чтобы точно можно было сказать - да, здесь ошибок нет. Крайний случай слишком тщательного подхода к код-ревью, встреченный мной на практике - когда разработчик просит освободить его от других задач, чтобы он мог полностью погрузиться в ревью: прочитать аналитику, изучить архитектуру кода...

Но как я уже писал в https://t.me/javaKotlinDevOps/146 - скорость прохождения код-ревью очень важна для быстрого выявления ошибок и предотвращения merge конфликтов. Что же тут можно сделать?

Во-первых я предлагаю рассматривать код-ревью как еще одну из сетей для поиска проблем в коде. Есть и другие сети - валидация в IDEA, модульные и интеграционные тесты, CI pipeline, SonarQube и другие инструменты статистического анализа, включая сканирования на уязвимости. Это если говорить о тех, что работают до код-ревью. После - регресс, тесты нового функционала, нагрузочное тестирование, демо (приемо-сдаточные испытания), канареечное развертывание, chaos engineering... Т.е. код-ревью - полезно, но это не последний рубеж обороны.

Второй момент: когда я провожу ревью - я вижу те проблемы, которые считаю важным. Т.е. мой взгляд субъективен, на него влияет мой опыт, и особенно проблемы, с которыми я сталкивался ранее. Да, важно то, что мой взгляд отличается от взгляда автора кода. Это позволяет найти те ошибки, которые автор из-за замыленности не увидел. Но с другой стороны - что-то я в принципе увидеть не могу. В этом плане будет полезно иметь несколько ревьюверов, внутри и кросс командное ревью.

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

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

Большинство Java разработчиков знают про Mockito - самый популярный фреймворк для создания заглушек. Но не ошибусь, если скажу, что большая часть разработчиков также не любит читать документацию) В т.ч. Mockito. А используемые инструменты надо знать.

Поэтому могу порекомендовать отличную статью про Mockito https://habr.com/ru/articles/444982/
Для затравки - из статьи можно узнать:
1) как определить - mock это или нет
2) в чем разница между when и do, когда все же нужен do
3) как одной лямбдой сделать сложную проверку входных параметров в конструкции when
4) как проверить порядок вызова методов
5) про сессии Mockito
и много других интересных особенностей фреймворка.

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

Уже был пост о том, как не надо использовать контекстные функции в Kotlin https://t.me/javaKotlinDevOps/189
Сразу может возникнуть вопрос - а когда их стоит использовать?

По ссылке уже был пример - для установки полей объекта, которые нельзя установить через конструктор. То ли потому, что подходящего конструктора\builder нет, то ли потому, что в момент создания объекта их значения еще не известны. Вот он:
val man = Person("Vasya").apply {
age = 20
city = "Moscow"
}

К слову - эту задачу можно было решить лет 20 назад в Delphi с помощью оператора with, мне его очень не хватало в Java))) И интересно, что в Kotlin with немного отличается по смыслу: https://kotlinlang.org/docs/scope-functions.html#function-selection

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

return claim.also {
log.info("Возвращаем $claim")
}

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

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

fun main() = doSomething().also { doAnotherThing(it) }

Если подкинете еще хорошие примеры в комментариях - буду благодарен.

#kotlin #readability
Всем привет!

Нашел полезную штуку - калькулятор сайзинга для Kafka - https://eventsizer.io/

P.S. Новый тэг - #utils
Всем привет!

Хочу рассказать про наверное самый способ улучшить читаемость. Например, у вас есть сложное условие из нескольких уровней, каждый из которых состоит из ряда проверок. Или длинный метод с кучей условий, который сложно понять и на который справедливо ругается SonarQube.

Решение такое - выделяем атомарные блоки кода или условия в отдельные private методы.
К слову, данный способ является одним из базовых рефакторингов под названием "extract method" из известной книжки Фаулера "Рефакторинг".

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

Окей, но даже если вам не повезет, и ваш компилятор этого не сделает - нужно иметь RPS (request per second) сильно больше 1, чтобы лишние вызовы метода сыграли свою роль. Причем даже в таком случае длинная цепочка вызовов методов должна быть в основном сценарии. Кажется, что под эти три условия попадает не так много кода. И в любом случае у нас есть НТ.

Еще может возникнуть вопрос с unit tests - их число тоже нужно увеличивать? Ответ - не обязательно, нет жесткой связки 1 к 1 теста и метода. Тест можно написать на группу взаимосвязанных методов, главное закрыть все возможные пути выполнения кода. Да и не нужно тестировать private методы.

И еще важный момент - extract method позволяет решить еще один часто встречающийся кейс. Предположим у вас есть дублирующийся код, отличающийся только одним небольшим блоком. Решение навскидку (на Kotlin):

fun doSomething(booleanParam: Boolean): SomeResult {
if (booleanParam) {
doAnotherThing()
}
// some code
}

Но приходится вводить Boolean параметр, а это хоть и не общепризнанный антипаттерн, по этому вопросу идут hollywars, но приближается к этому статусу)
Поэтому можно сделать так:

fun doSomething(): SomeResult {
// some code
}

fun doSomethingExtended(): SomeResult {
doAnotherThing()
return doSomething()
}

Итог: не нужно боятся выделять новые методы.

#refactoring #readability #antipatterns