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

В каждой новой версии JDK есть изменения разной степени сложности и важности. Одно из самых важных, но на первый взгляд простых изменений, после появления которого первая возникающая мысль была: "А почему так не сделали сразу???" - это нормальный стектрейс для NPE (NullPointerException) в Java 14.

Вот еще одно похожее изменение - https://openjdk.org/jeps/445 - планируемое в 21 релиз.
Часто бывает нужно что-то быстро проверить, алгоритм или библиотеку. Т.е. у нас Java приложение из одного класса. Но нужен же метод main, а его сигнатура - не самая простая для запоминания штука. Приветствую данную фичу двумя руками)

P.S. Да, в Kotlin все еще проще - https://kotlinlang.org/docs/basic-syntax.html#creating-classes-and-instances )))

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

Внимание - вопрос.
А какой фичи вам не хватает в языке? Не обязательно речь о Java

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

Возвращаясь к теме open source продуктов, вышедших из enterprise. Если присмотреться к списку https://t.me/javaKotlinDevOps/154 то можно заметить, что в нем нет банков. Причем не только российских - вообще никаких. 
Какие могут быть причины?

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

2) большАя часть уникальных разработок в банках связана с информационной безопасностью (ИБ). Т.е. берем open source и добавляем туда продвинутую ролевую модель авторизации, аудит, поддержку нужных стандартов шифрования... Штука специфическая, банковская, для других классов АС не нужная. В смысле ИБ нужна всем, но не всем в такой степени, как у банков. Опять же - много ИТ ресурсов уходит на доработку под требования ИБ, на другие доработки их не хватает.

3) окей, почему тогда нет рынка финансового opensource? Ну или я о нем не знаю, поправьте, если я ошибаюсь))) Т.е. никто не выкладывает финансовые библиотеки, фреймворки, утилиты на github, хотя наверняка они есть. Предположу, что это связано с банковскими требованиями по безопасности, бюрократией и консервативной корпоративной культурой. Ну т.е. просто нет такого процесса в банках. Сразу отмечу, что не стоит путать алгоритмы и фреймворки. Алгоритмы скоринга заемщика, фрод-мониторинга, расчета ставки, ... являются ноу-хау банка и никто их выкладывать в открытый доступ в здравом уме не будет. Но код, который этот алгоритм выполняет - почему бы и нет.

#opensource #fintech
Всем привет!

Есть типичный пример плохого кода - большие процедуры, десятки или даже сотня строк каждая, неговорящие имена переменных, клубок вызовов, также известный как спагетти код. А тут прилетает задача - сервис нужно доработать, добавив какую-то важную проверку.
Есть техники для борьбы с плохим кодом. В первую очередь это собственно ООП - разделение кода по классам. Потом можно применить принцип единственной ответственности - каждый класс и метод отвечает за что-то одно. Далее идут принципы, описанные в книге "Чистый код" - понятные наименования, небольшие методы. Можно еще заполировать все это DDD - выделив ограниченный контекст. И разделить код по слоям, например, используя гексагональную архитектуру. Или даже разделить на микросервисы)
В результате получим десятки маленьких объектов, с четкой областью ответственности, хорошо читаемый код в каждом методе.
Но можно упустить важный момент - после выполнения всех доработок понять как работает система в целом (!) все равно будет сложно. Т.к. система стала слишком большой и сложной. И тут на приходит на помощь принцип KISS - Keep it simple. Перед тем, как начинать проектировать и кодить стоит задать вопрос - нужна ли еще одна валидация в коде? Может она уже есть в микросервисе, из которого мы получаем данные? Может вероятность появления таких данных в ПРОМ (PROD) стремится к нулю? Может можно подключить внешнюю библиотеку, где все уже сделано до нас?
В общем не забывайте про KISS)

#arch #clean_code #principles
Всем привет!

По моему опыту далеко не все разработчики пришли в профессию с ИТ образованием. Я сам такой, в ВУЗе изучал только курс по базам данных, причем преподаватель изучал их вместе с нами) Следовательно, не все знают т.н. Computer Science, в т.ч. теорию алгоритмов.
Чтобы иметь понимание о базовых вещах предлагаю пару видео:

Сложность алгоритмов https://youtu.be/cXCuXNwzdfY
Сортировка https://youtu.be/PF7AqefS4MU

Да и в целом канал неплохой.
Мне понравилась наглядность - разбирается все на картинках - и пошаговый подход к разбору алгоритма, очень похожий на TDD)

Один минус, на каждые 10 минут видео в среднем одна реклама) Но что сделаешь, контент бесплатный)

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

Иногда возникает необходимость создать ветку в репозитории Git никак не связанную с уже существующими ветками.

Первым делом при такой потребности я хочу процитировать наверное самый популярный ответ на StackOverflow - а вам точно нужно это делать?) В данном случае он справедлив, т.к. не стоит хранить в одном репозитории слабосвязанный код:
а) приложение и его библиотеки
б) код и API\документацию\настройки\скрипты БД если их создают члены команды с разными ролями и разным подходом к код-ревью и слиянию - к примеру разработчики и аналитики
в) наоборот, если API\документацию\настройки\скрипты БД создают одни и те же люди - не стоит их разносить по разным веткам.

Но бывают кейсы, требующие нескольких несвязанных между собой веток. Например, две сильно различающиеся версии приложения.
Есть три способа решить эту задачу.
1) очевидный и неправильный - создать новую ветку на основе существующей, удалить все файлы и залить новые
2) изначально завести ветку c readme.md, от которой можно будет создавать новые чистые ветки
3) выполнить вот такие команды
git checkout --orphan newbranch
git rm -rf .
и далее как обычно.

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

Уже говорил про переиспользование кода в общих библиотеках https://t.me/javaKotlinDevOps/137
Поднимемся на уровень выше: возьмем набор библиотек с общим кодом, добавим туда реализацию обязательных архитектурных стандартов, требований сопровождения и безопасности - и получим платформу.
Какой должна быть хорошая платформа? Первый напрашивающийся ответ - смотри на Spring Framework. Но попытаюсь конкретизировать.

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

2) хорошая документация, cookbook, отвечающий на вопросы: зачем использовать? как подключить? особенности реализации, антипаттерны?

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

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

5) self-service - у бизнес-команды должна быть возможность самостоятельно выполнять любые задачи, не связанные с исправлением багов и доработками компонента платформы. Пример таких задач - регистрация нового потребителя, метаданные для компонентов платформы, валидация скриптов. Самостоятельно - т.е. без тикетов на платформу, без согласований в почте, без встреч с платформенной командой. В идеале - кладем нужные нам стройке в git, далее DevOps pipeline их обрабатывает и результат отражается как результат выполнения джоба. Если есть возможность доработать код платформы самостоятельно - через механизм Inner Source - вообще отлично!)

6) должны быть четко очерчены сроки поддержки старых версий платформы. Естественно, сроки должны соблюдаться

7) API платформенных компонент должен быть единообразным. Хороший пример из Spring - многочисленные xxxTemplate. Или использование application.yml как централизованное место для настроек. За этим должен следить архитектор(ы) и команда, отвечающая за cookbook и синтетическое приложение.

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

9) convention over configuration = минимум настроек, которые разработчики должны прописать руками. Как пример - Spring Boot, хотя надо сказать сам Spring пришел к этому не сразу) Конечно каждая бизнес-задача уникальна, но по моему опыту в большинстве случаев достаточно типовой конфигурации с небольшими доработками. Рассмотрим альтернативу: если для поднятия минимального каркаса нужны сотни настроек - никто не будет в них разбираться, все их просто будут копировать. И хорошо, если из последней проверенной версии синтетического приложения.

10) платформа должна своевременно выпускать фиксы уязвимостей. Вроде очевидно, но важно.

11) у платформенной команды есть свой team lead, свой бэклог и главное - свое видение продукта. И это правильно. Но фокус в развитии продукта должен быть на потребителях. Всех потребителях - сопровождение, ИБ и конечно же бизнес-команды. Лично знаю случаи, когда разработчики платформы уходили в бизнес-команды и говорили - да, что-то я не думал, что нашей платформой так сложно пользоваться) Еще кейс - в бизнес-командах изобретено несколько похожих друг на друга "велосипедов", которые по хорошему должны быть в платформе изначально.

#arch #conv_over_conf
Всем привет!

Минигайд по кодировкам в Maven.
Для начала - главное, что нужно знать про кодировки в целом:
1) UTF-8 рулит)
2) нужно явно указывать кодировку.

Как это сделать в Maven?

1)
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

Работает практически везде, за исключением пунктов 2) и 3) ниже.

2)
<properties>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

Работает для отчетных плагинов. Чтобы не выяснять для каких именно - проще установить и забыть)

3) Переменная среды JAVA_TOOL_OPTIONS равная -Dfile.encoding=UTF8
Работает тогда, когда Maven запускает отдельный Java процесс, в частности при запуске unit тестов из Maven. Причина падения тестов на Win, до этого успешно работающих на Mac\Lin. Падают из-за другой кодировки по умолчанию в Win.

4) Возможна точечная установка или переопределение кодировки для нужного плагина, например:
а) unit тесты
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
б) компиляция
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
Как видно из примеров - формат настроек у разных плагинов различается.

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

Еще немного про Maven. Есть несколько способов настроить версию Java в Maven, все они описаны в этой статье - https://www.baeldung.com/maven-java-version
Оптимальным начиная с Java 9 выглядит вариант с указанием
<properties>
<maven.compiler.release>9</maven.compiler.release>
</properties>
т.к. данное свойство заменяет собой три: source, target и bootclasspath. Последнее означает, что начиная с Java 9 все JDK умеют притворяться более ранними версиями с точностью до classpath, т.е. до предоставляемого API. А это важно при переходе на 11-ю и 17-ю Java - в первой выпилили Java EE модули, типа SOAP, во второй - закрыли internal пакеты.

Но это не все, что нужно знать про настройки версии JDK.
Если в проекте есть Kotlin - надежнее явно указать ему версию JDK. Для справки - старые версии Kotlin поддерживали только JDK 6 как target bytecode, потом был период JDK 8, сейчас поддерживается все версии https://kotlinlang.org/docs/maven.html
Настраивается так:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<configuration>
<jvmTarget>1.9</jvmTarget>
По хорошему плагин Kotlin должен переиспользовать maven.compiler.release, но я не нашел подтверждающей это информации.

Второй тонкий момент связан с IDEA. IDEA смотрит на maven.compiler.release, в результате правильно проставляет:
а) Source language level для корневого и дочерних модулей Maven - это можно увидеть в Project Structure -> Modules
б) Target bytecode для всех модулей - Double Shift, далее вбиваем "java compiler".
Но есть еще одна важная опция Project Structure -> Project -> SDK. Она определяет версию JDK, на которой будет собираться проект. Повторюсь, из-за сильных изменений в структуре JDK как минимум в 11 и 17 версиях сборка на более новой JDK может сломаться. Причем из логов причина ошибки будет не ясна(
Так вот, IDEA в данном кейсе игнорирует настройки Maven. Прямого решения у проблемы я не нашел, судя по всему, ребята из IntelliJ считают, что корневой модуль в проекте Maven и проект IDEA это не одно и тоже. И это фича, а не баг)
Но есть обходной путь. Если все или большинство ваших проектов живут на определенной версии JDK, то ее можно выставить в IDEA по умолчанию. Настраивается вот здесь: Double Shift, далее вбиваем "structure for new projects"

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

Когда-то давно - год назад - у меня была заметка, чем хорош k8s: https://t.me/javaKotlinDevOps/6
Там был упомянут Docker, пришло время подробнее раскрыть, что же дают нам контейнеры. Вообще говоря контейнеры и Docker не одно и тоже, но в данном случае различием можно пренебречь.

1) идентичное окружение на dev, test и prod. Да, JRE уже дает нам уровень абстракции от ОС и железа, и это большой плюс в плане запуска Java в разных ОС. Но есть проблемы:
а) разные версии JDK
б) разные сервера приложений\контейнеры сервлетов
в) разный classpath, часто как следствие предыдущего пункта
г) разные переменные среды
д) разное состояние файловой системы
Все это можно решить, но часто решение дорогое - сложные CD pipeline, долгое время деплоя, сложность поднятия prod-like среды на машине разработчика.
C Docker-ом мы получаем immutable infrastructure - набор ПО, настроек и состояние файловой системы зафиксированы на dev и остаются неизменными дальше.

2) легковесная изоляция сервисов. Контейнеризация обеспечивает изоляцию файловой системы, процессов, сетевых интерфейсов и резервирование ресурсов для каждого запущенного на сервере контейнера. Используются механизмы ядра Linux, подробнее см. https://habr.com/ru/articles/659049/
Ключевой момент тут - легковесная, т.к. технологии изоляции в виде виртуальных машин известны давно. Но виртуальная машина эмулирует железо, что сложно, см. стоимость лицензии VMware, к тому же приводит к достаточно высоким накладным расходам по CPU, памяти и диску. Плюс поверх виртуалки нужна гостевая операционная система, а значит запуск виртуалки - это долго.

3) легкость установки. Т.к в Docker сейчас упаковывается почти все (https://hub.docker.com/search, нужна регистрация), то появляется возможность быстро и без ущерба для компьютера разработчика развернуть необходимое серверное ПО - СУБД, Kafka, кэши, мониторинг... А если данные сервисы нужны для тестов - на помощь приходит Testсontainers https://java.testcontainers.org/ Все это работает на Linux, MacOS и Windows, например, с помощью Docker Desktop https://www.docker.com/products/docker-desktop/ Может возникнуть вопрос - откуда на Windows появились механизмы ядра Linux? Ответ: благодаря технологии WSL - https://learn.microsoft.com/ru-ru/windows/wsl/.
Аналогично на серверах - установка образа проще и стабильнее установки классического серверного ПО.

Если говорить именно о Docker - то в общем то это все, остальные преимущества раскрываются в связке с k8s и Service Mesh.

#docker #k8s
Всем привет!

Один из самых больших плюсов Java - ее экосистема. Что я под этим словом понимаю - библиотеки, фреймворки, инструменты для сборки, CI инструменты, клиенты для различных БД, очередей, систем мониторинга и т.д.
Приведу пример.
Есть такая штука Lombok.
У него одна из фичей - аннотация @Value, которая по сути добавляет поддержку records в Java до 14 версии. Еще аналогичная фича - data class в Kotlin. Другими словами, решаем задачу: без boiler plate кода получить иммутабельный класс, служащий только для хранения данных. Для использования как DTO к примеру.
Так вот. Недавно выяснил, что есть еще 2 специализированные библиотеки: AutoValue и Immutables - также решающие данную задачу)
Вот статья со сравнением https://dzone.com/articles/lombok-autovalue-and-immutables
Сравнивай, выбирай. Экосистема.

P.S. В самой статье, к слову поднимается один интересный вопрос - если Lombok получает целевой класс путем генерации байткода, то две другие библиотеки - путем генерации исходного кода. Второй подход на первый взгляд более прозрачный и надежный - сразу видно, что получается в итоге. А с Lombok - получаем "магию" и возможность посмотреть, что получилось под капотом, с помощью опции DeLombok. С другой строны код, который приходится писать самому, в случае Lombok проще.

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

Три лайфхака по работе с Maven:

1) чтобы заработала отладка в IDEA при запуске через Maven к примеру unit тестов:
для версий surefire плагина >= 2.14: use -DforkCount=0
http://maven.apache.org/plugins/maven-surefire-plugin/examples/debugging.html

2) запустить цель (goal) на дочернем модуле и всех его детях: maven --projects artifactId --also-make-dependents
Полезно на больших многомодульных проектах. Подбробнее https://maven.apache.org/guides/mini/guide-multiple-modules-4.html
Запускать цель напрямую но дочернем проекте нельзя, т.к в таком случае не применятся настройки из корневого проекта - как Maven, так и к примеру Lombok.
Еще важно - перед тем, как отлаживать дочерний проект нужно проинсталлировать в локальный Maven репозиторий те модули, от которых он зависит. Я про maven install.

3) по умолчанию maven следует принципу fail fast и это правильно) Но если нужно понять, в каком состоянии проект - можно запустить полную сборку игнорирую промежуточные ошибки до окончания сборки: maven --fail-at-end

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

В последние годы стала "модной" тема null safety. Суть в том, что не нужно хранить и передавать null значения, чтобы не напороться на Null Pointer Exception. В том же Kotlin null safety встроена в язык - все типы по умолчанию не могут содержать null.
И на самом деле это правильный подход. Но есть нюансы)

Рассмотрим такой случай - мы идем куда-то за данными, данные по бизнес-процессу там обязаны быть. Например, мы прихранили id записи где-то в пользовательском контексте в начале процесса и идем за данными в конце процесса. Но данных нет. Следуя null safety можно просто создать пустой объект - например, с помощью конструктора. Как вариант, часть полей этого объекта будет проинициализирована значениями по умолчанию.

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

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

#kotlin #code #patterns #principles #nullsafety #fail_fast
Всем привет.
Вопрос знатокам IDEA - что это за фича? Я знаю есть quick fix - и у некоторых из них есть опция - исправить во всем файле. Но тут я даже ничего не сделал) Т.е. IDEA сама нашла нужный enum и сделала import.
P.S. За пыль на экране извиняюсь)
#idea
Всем привет!

В продолжение темы функциональности IDEA и подготовки кода к code review, см. https://t.me/javaKotlinDevOps/148
Некоторые проверки и исправления можно подвесить на одно из двух событий:
1) на сохранение файла: Alt-Alt - Actions on Save. Рекомендую включить Reformat code и Optimize import.
2) перед commit на Git сервер - открыть окно Commit (Ctrl-K) и нажать там шестеренку. Рекомендую включить Analyze code, Check TODO и если выполнение тестов занимает приемлемое время - то еще и прогон тестов.
Легко заметить, что набор опций в обоих случаях похож, но на сохранении можно включить только те, где фиксы применяются без участия человека. В частности и Cleanup, и Analyze выполняют правила из набора инспекций (Inspections), только в первом случае включаются только те правила, где есть quick fixes, которые можно применить автоматически.
Насчет Cleanup - IMHO его вполне можно включить на commit, главное перепроверить набор активных правил: Shift-Shift - Inspections, а там включить фильтр Cleanup only. К слову - там еще есть профили с набором правил, можно добавить свой.
И еще важный момент - инспекции из IDEA можно запустить из командной строки, и т.об. включить в CI процесс: https://www.jetbrains.com/help/idea/command-line-code-inspector.html
Они частично повторяют проверки SonarQube, но не идентичны им.

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

Когда-то давным-давно все, ну или почти все, использовали сборку JDK от Oracle. Хочу рассказать что же изменилось и что можно использовать сейчас.

В 2019 году Oracle изменила лицензионную политику и использовать JDK, а также JRE, бесплатно можно лишь для личных нужд. Версия, которую можно так использовать, получила название OpenJDK. Для коммерческих целей нужно приобретать лицензию, вне зависимости от того, нужна вам поддержка Oracle или нет. Эта версия - Oracle JDK. Кроме лицензионных условий сейчас эти сборки ничем не отличаются. Закон обратной силы не имеет, поэтому все предыдущие сборки можно использовать бесплатно, но любой hotfix JDK после 2019 года попадет под новые условия.
Это была первая проблема. Но кроме нее есть еще одна. Каждая версия OpenJDK от Oracle - это важно, что от Oracle - распространяется только полгода, потом идет переход на новую версию. И патчи выходят только для самой последней версии. Это касается и LTS - версий с долговременной поддержкой. Т.е Oracle OpenJDK 17 патчилась и распространялась полгода, потом стала доступна OpenJDK 18. Для тех, кто всегда готов к обновлениям - гуд) Но это не только лишь все)
Подробнее про это все можно почитать тут https://habr.com/ru/articles/448632/

Что же можно выбрать взамен? Есть довольно много компаний и opensource сообществ, которые берут исходники от Oracle OpenJDK, добавляют туда необходимые патчи, компилируют все это под определенные ОС и процессоры и выпускают для свободного скачивания. Отличаются они по следующим характеристикам:
1) набор версий Java. Как правило у всех есть 3 последние LTS - 8, 11, 17. У большинства есть последняя версия не LTS версия. У некоторых - даже 6-я и 7-я Java! А наличие 6-й Java означает не просто доступность ее для скачивания, но и обратное портирование туда критических патчей.
2) набор поддерживаемых ОС - Linux, Windows, MacOS
3) набор поддерживаемых процессорных архитектур - x64, x86 (32 бита), ARM
4) поддержка из коробки native image https://www.graalvm.org/native-image/
5) поддержка из коробки минималистичного образа Linux - Alpine. Я писал об различиях Docker образов тут https://t.me/javaKotlinDevOps/131
6) формат дистрибутива - инсталлятор, Docker образ. А если говорить про Дinux - поддержка разных менеджеров пакетов - rpm, deb...
7) формат поддержки - как правило он всегда доступен за деньги, но в некоторых случаях - JDK от ИТ гигантов - SAP, Microsoft, Amazon - поддержка доступна только вместе с продуктами этих компаний. Т.е. по сути эти JDK не для всех, а для тех кто использует соответствующее облако или продукт.

Неплохая статья со сравнением - https://bell-sw.com/blog/oracle-java-alternatives-comparison-of-openjdk-distributions
В конце статьи - сравнительная таблица.

Я бы особо выделил Temurin - JDK от Opensource сообщества и Liberica - JDK от российских разработчиков, который по перечисленным выше 7 пунктам обгоняет всех конкурентов.

P.S. Еще один интересный факт: IntelliJ также выпускает свою версию JDK - с доработками для отрисовки IDE UI.

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

Я уже писал про паттерны https://t.me/javaKotlinDevOps/52 и их важность. Но есть штука поважнее паттернов - базовые принципы разработки. Чтобы стало понятнее приведу пример - SOLID.
Почему принципы важнее паттернов? Паттерн - это решение частной задачи. Лично я знаю больше паттернов, чем применял на практике) А в разработке я давно. Принципы же применимы практически к любой задачи.
Тот же S из SOLID - Single Responsibility: дорабатываешь какой-то метода - применим, создаешь новый класс - тоже, делишь код по модулям - аналогично, проектируешь набор микросервисов...
Я не люблю повторять то, что уже хорошо описано в интернете, поэтому вот статья с неплохим описанием - https://skillbox.ru/media/code/eto-klassika-eto-znat-nado-dry-kiss-solid-yagni-i-drugie-poleznye-sokrashcheniya/
Оффтопик - не ожидал от skillbox, обычно все ссылки у меня на Хабр или baeldung.

Что бы я добавил к описанным в статье принципам:
1) null safety. Плюсы: не получишь NullPointerException, не нужен код с проверкой на null, не нужно думать - так, на уровень выше я уже на null проверяю, тут вроде не нужно.. но если в будущем этот метод будет вызываться откуда-то еще. Жаль в Java ее достичь сложно, есть куча библиотек с аннотациями @Null\@NotNull, действуют они по разному, на эту тему можно отдельную статью написать. Важно то, что простого решения в Java нет. Зато есть в Kotlin)

2) иммутабельность. Главный плюс - большая устойчивость к ошибкам. Приведу пример: объект - это ссылка на область в памяти. Где еще в сервисе используется объект - часто быстро определить сложно. Вывод - меняя что-то в переданном в метод объекте можно поломать программу в неожиданном месте. Также неожиданным плюсом может быть большая производительность. Самый очевидный пример - иммутабельность строк. Еще - если у вас есть List и нужно убрать из него лишнее - возможно (возможно, надо проводить тесты!) оптимальнее будет создать новый список с нужными объектами, т.к. каждая модификация существующего - это перемещения в heap. Главное чтобы памяти было много и использовался современный сборщик мусора. Еще плюс - если объект иммутабельный, то его можно спокойно использовать в многопоточной программе. Изменения состояния нет, синхронизация доступа не нужна. Ну и бонусом - иммутабельный объект можно использовать как ключ, в том же HashSet\HashMap. В Java для иммутабельности есть records и final, в Kotlin - data class.

3) понятные наименования - я про переменные, методы, классы. Часто вижу две ошибки. Первая - злоупотребление сокращениями. Вторая - ситуативные названия. Т.е. при реализации конкретной фичи название кажется очевидным для автора кода. Но вот приходит новый разработчик. Он знает только о сервисе в целом, никакую старую аналитику он читать не будет, сразу полезет в код - в итоге многие названия покажутся ему непонятными. Общий принцип - называйте так, чтобы назначение кода было понятно новому разработчику. А любые более менее сложные условия выносите в методы с говорящими названиями. За подробностями - снова порекомендую книгу "Чистый код" Мартина.

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

Сегодня пост про очередной типичный вопрос на собеседовании.
Звучит он так: расскажите про жизненный цикл сборки Maven, он же build lifecycle.
Я вкратце уже писал про это https://t.me/javaKotlinDevOps/10. Но т.к. типичный ответ на собеседовании - перечисление циклов и фаз сборки, то хочется раскрыть тему. На самом деле вопрос про другое - в чем суть цикла сборки?

1) набор фаз сборки JVM проекта уже придуман и зафиксирован умными людьми) из команды Maven в виде Default Lifecycle https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference Т.е. считается, что список покрывает все потребности сборки. Как пример продуманности могу привести фазы pre-integration-test и post-integration-test, которые нужны для того, чтобы поднять и опустить контейнер сервлетов, менеджер очередей или БД до и после фазы интеграционных тестов (integration-test). Для обычных тестов (test) таких вспомогательных фаз нет.
2) последовательность фаз также зафиксирована, порядок менять нельзя да и нет смысла
3) большинство фаз являются опциональными, запускаются только если к фазе подключен хоть один плагин и либо в проекте присутствуют определенные файлы, либо есть настройки плагина, указывающие что ему делать - например, generate-sources или компиляция Kotlin
4) на одной фазе могут работать несколько целей (goal) из разных плагинов - например, компиляция Java и Kotlin на фазе compile или несколько тестовых фреймворков на фазе test
5) запуская определенный шаг сборки - mvn install - вы запускаете все предыдущие шаги цикла. И в большинстве случаев это правильно. Если такое поведение не требуется - нужно запустить конкретную цель у конкретного плагина, для моего примера это mvn install:install (плагин:цель). Т.е. тут совпадают название фазы сборки, плагина и цели. Так бывает не всегда, например, для фазы test-compile цель выглядит так compiler:testCompile
Итого: цель жизненного цикла сборки - стандартизировать процесс сборки.
Да и в принципе стандартизация - конек Maven. Тут и типовой набор папок https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html, и цикл сборки, и сложность написания своего кода для сборки, и достаточно богатый набор стандартных плагинов, для подключения которых ничего не надо делать (если быть точным - неплохо бы зафиксировать версию в pom), и архетипы, и конвенция по наименованию артефактов, и наконец центральный репозиторий - https://mvnrepository.com/repos/central

#maven #interview_question