(java || kotlin) && devOps
342 subscribers
13 photos
2 videos
7 files
419 links
Полезное про Java и Kotlin - фреймворки, паттерны, тесты, тонкости JVM. Немного архитектуры. И DevOps, куда без него
Download Telegram
Java vs Python, часть не помню какая)

Я уже делал несколько постов про то, как инструменты, исходно появившиеся в экосистеме Python, мигрируют в Java.
Причина я думаю понятна - большое число Java программистов, развитая экосистема.

Вот еще пример.

Важной частью Data Science является веб скрапинг (Web Scraping) - обход сайтов в сети интернет и получение из них определенного рода данных. И если вбить эти два слова "веб скрапинг" в поиск - он сразу подставит python)
Вот типичная статья из выдачи Яндекса https://habr.com/ru/companies/ruvds/articles/796885/
Основные python инструменты оттуда - BeautifulSoup, Scrapy, Selenium, lxml, pyquery

А что есть в Java? Есть ли что-то?)

BeautifulSoup - собственно парсинг страниц сайтов. Аналог в Java - jSoup https://www.baeldung.com/java-with-jsoup
Scrapy - тоже парсинг, но с многопоточкой, работой с сессией, куками. Т.е. для массового скрейпинга и работы со сложными сайтами. В Java - Webmagic https://www.baeldung.com/java-webmagic-web-crawler Возможностей поменьше, но инструмент в наличии
Selenium - не зависит от языка, вообще говоря написан на Java. В интеграционных тестах на Java я его еще лет 15 назад использовал.
lxml - быстрый парсер xml\html. Вообще у Java большой выбор парсеров: DOM, SAX, Stax. Но тут речь про работу с HTML, а HTML - это конечно подмножество XML, но, как правило - XML с ошибками. Зато в Java есть библиотечка TagSoup, цитата: "SAX-compliant parser written in Java that, instead of parsing well-formed or valid XML, parses HTML as it is found in the wild".
pyquery - работа с HTML в стиле jquery. Вот тут аналога не нашел, но, кажется, не критично.

Итого - экосистемы не изолированы, хорошие идеи перетекают из одной в другую. Java хоронить рано)

#java #python #data_science
👍21🔥1
Астрологи объявили 2025 годом уязвимостей в Tomcat)

По крайней мере у меня складывается такое впечатление.
И похоже не только впечатление.
https://www.cve.org/CVERecord/SearchResults?query=apache+tomcat
24 уязвимости в 2025 году, по сравнению 15 с 2024. И год еще не закончился)

Предположу, что проблема скорее не в том, что Tomcat кривой по архитектуре или дырявый, а это обратная сторона популярности. Все-таки Tomcat - вариант по умолчанию встроенного сервера для Spring Boot приложений. И большинство его не меняют. Больше инсталляций, больше людей, которые их хотят сломать.

Но не Tomcat единым, как говорится.
Есть еще как минимум 4 сервера для JVM приложений:
1) Jetty
2) Undertow
3) Netty
4) Open Liberty

Все они production ready.
Кто может заменить Tomcat для Spring Boot приложений?
И нужно ли менять?

Начнем с того, кто не сможет.
Netty - это не контейнер сервлетов, синхронное взаимодействие Spring Web MVC он просто не поддерживает. Зато это выбор номер один для реактивщины. Как в Spring, так и в конкурирующих фреймворках Quarkus/Micronaut/Vert.x/Helidon.
И очевидно он выдает намного большую производительность и меньшее потребление памяти, по сравнению с Tomcat. Но требует полного переписывания логики на принципах реактивного программирования. А это сложно и требует я бы сказал повышенной квалификации.

Open Liberty - бывший IBM Websphere Liberty Profile, ушедший в open source. Хотя он и совместим со Spring Boot https://openliberty.io/docs/latest/deploy-spring-boot.html, два факта говорят о том, что смысла так делать нет:
1) одна из главных фишек Open Liberty - полная поддержка Java EE/Microprofile. Это точно не про Spring.
2) среди встроенных серверов Spring Boot нет Open Liberty в отличие от остальных четырех кандидатов.
Тоже побыстрее Tomcat, поддерживает модульность (а это необходимое условие при полной поддержке Java EE).

Остаются два кандидата - Jetty и Undertow.

Undertow - полностью JBoss Undertow - тоже бывшая коммерческая разработка, ушедшая в open source. Архитектурно сделана в неблокирующем стиле а-ля Netty, но с поддержкой сервлетов (Spring Web MVC). Что должно положительно сказаться на производительности. Плюс можно плавно мигрировать с кода в классическом стиле к реактивному. Минус по сути один - мало распространена, меньше сообщество. Да, и уязвимостей мало https://www.cve.org/CVERecord/SearchResults?query=undertow

И наконец Jetty. Архитектура классическая, как и у Tomcat. Разработчики делают фокус на модульной структуре: даже поддержка http (обычного, HTTP v1) обеспечивается модулем и может быть отключена. Кому интересно - вот список модулей из стандартной поставки: https://jetty.org/docs/jetty/12.1/operations-guide/modules/standard.html
Сообщество поменьше, чем у Tomcat, но достаточно большое, учитывая 20 лет на рынке. Уязвимостей сильно меньше в этом году https://www.cve.org/CVERecord/SearchResults?query=Jetty, при сравнимом количестве в 2024.

Вывод: а надо ли куда-то переходить? Для Spring Web MVC приложения большой разницы в производительности, потреблении памяти и надежности на ПРОМ я не ожидаю. Как я говорил - все сервера production ready. Но в плане уязвимостей - возможно, с Jetty жизнь станет немного спокойнее. Не ложное ли это успокоение - может "хакеры" еще не добрались до Jetty? Время покажет, но учитывая 20 лет на рынке ... очень может быть, что и нет, не ложное.

P.S. Интересно, что и IBM, и Redhat (JBoss)) пошли одним путем - выделить ядро своего сервера в отдельный lite компонент и сделать его open source.

#java #web #servlet
Новая LTS Java.

Я о Java 25.
Вышла не вчера, поэтому также вышла и хорошая статья с обзором нововведений https://habr.com/ru/companies/T1Holding/articles/946778/.
Там даже табличка включения новых фич от 21 до 25 версии есть. И примеры кода - было\стало.
И от меня как всегда пару комментариев)

Для начала бросаются в глаза две фичи со "странным" названием Quantum-Resistant ...
Почему бросаются - квантовые компьютеры ожидаются в промышленном использовании в течение 10+ лет, а устойчивые к взлому квантовым компьютером алгоритмы в Java появились уже сейчас.
С - стратегия.
Б - банковское ПО)

Три фичи со словами Ahead-of-Time, главная из них - Ahead-of-Time Class Loading & Linking.
Это дальнейшее развитие темы CDS https://t.me/javaKotlinDevOps/316
Т.е. ускорение старта приложения.
Если CDS убирает этап верификации классов сохраняя в архиве уже проверенные классы,
то Ahead-of-Time Class Loading & Linking как следует из названия сохраняет всю необходимую для работы с классами информацию. Так сказать в распакованном виде, поэтому ее сразу можно грузить в Metaspace.
Одно но: набор классов у всех разный, поэтому нужно запустить приложение в тестовом режиме и собрать данные по актуальным классам, которые и будут сохранены в архиве.
Заодно сохраняется и статистика их использования (Ahead-of-Time Method Profiling), что позволяет при старте JVM сразу запустить компиляцию часто используемых методов.
Последняя фича - это offline Profile-Guided Optimization https://t.me/javaKotlinDevOps/315, которая ранее была killer feature коммерческих JVM: Azul ReadyNow и GraalVM Enterprise Native Image.
Итоговое ускорение загрузки: 42% vs 33% у CDS https://www.happycoders.eu/java/ahead-of-time-class-loading-and-linking/

Есть еще две оптимизационные фичи: Compact Object Headers и Linking Run-Time Images without JMODs.
Первая уменьшает размер любого объекта в памяти, оптимизируя заголовки. Вторая - уменьшает объем JDK, убирая оттуда JMOD файлы. JMOD появились вместе с модулями Java как развитие jar.
И классы в jmod файлах уже есть в JDK, т.е. имеем дублирование. Сейчас его убрали, размер JDK стал меньше на 25%. Важно в облаках с тысячами микросервисов.

На самом деле технология модулей в Java до сих пор не прижилась в коммерческой разработке, но команда Java не сдается)
Module Import Declarations - можно разом импортировать все классы в модуле. С одной стороны загрязняется область видимости, с другой - удобно.

Markdown Documentation Comments: Markdown - стандарт документации в ИТ в целом, получаем больше возможностей в JavaDoc. Да, JavaDoc нужны не всегда, но пригодится.

Фичи с JFR в названии - допилен профайлер: меньше влияние на исполнение кода (JFR Cooperative Sampling), больше данных (JFR Method Timing & Tracing).

Unnamed Variables & Patterns: _ (подчеркивание) обозначает для компилятора и валидаторов неиспользуемую переменную. Java пополнила длинный список языков, где это уже есть)

Scoped Values - более безопасный вариант Thread Local.

Также дошли до prod ready версии фичи из моего поста про Java 22 https://t.me/javaKotlinDevOps/278
* Launch Multi-File Source-Code Programs
* Implicitly Declared Classes and Instance Main Methods
* Stream Gatherers
* Class-File API
* Statements before super

Итого - решаются проблемы с производительностью и объемом, допиливается функционал (стримы, модули, JFR, Thread Local, GC), стандартизируются API (Class-File API), немного синтаксического сахара (_).

А String templates https://t.me/javaKotlinDevOps/246 выкинули. Слишком отличается от мэйнстрима, я про идею процессора STR."xxx", обрабатывающего строки

#java #jdk #java_new_version
Серия "хозяйке на заметку", а точнее разработчику библиотек на заметку.

Разработка библиотек отличается от разработки приложения тем, что публичные API в них живут намного дольше, и об этом надо помнить.
Любое публичное API, т.е. все public классы и методы, должно быть обратно совместимым как минимум в текущей мажорной версии.

Но жизнь как всегда сложнее. И что же у нас есть?

Java

1) объявить метод устаревшим с какой-то версии - @Deprecated.
Причем эту аннотацию можно не просто повесить на метод, у нее есть два поля: forRemoval и since, см. https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Deprecated.html

2) указать на что заменяем метод. @Deprecated не предоставляет такого механизма.
Но есть на свете добрые люди: https://errorprone.info/docs/inlineme
Как это может быть использовано:
а) статический анализ, собственно errorprone плагин: https://errorprone.info/docs/installation
б) миграция: https://docs.openrewrite.org/recipes/java/logging/log4j/inlinemethods

3) скрыть метод для потребителей не удаляя его из кодовой базы библиотеки. Т.е. оставляя его для тулов или для внутреннего использования. Java - снова нет( И даже добрые не помогли(

4) указать степень зрелости API. Стандартно - опять нет, но есть такая библиотечка @API Guardian https://github.com/apiguardian-team/apiguardian, позволяющая пометить API примерно так:

@API(status = STABLE, since = "1.0")
public class StableService {
@API(status = EXPERIMENTAL)
public void experimentalMethod() {
}

@API(status = DEPRECATED, since = "2.0")
public void deprecatedMethod() {
}

@API(status = INTERNAL)
public void internalMethod() {
}
}


Используется в JUnit, к слову.

Более простая альтернатива: @Beta из Guava, https://guava.dev/releases/23.4-jre/api/docs/com/google/common/annotations/Beta.html

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

Kotlin

1) @Deprecated
2) @Deprecated(replaceWith) https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-replace-with/
3) @Deprecated(level) https://www.baeldung.com/kotlin/deprecation
4-5) Механизм Opt-In: https://kotlinlang.org/docs/opt-in-requirements.html#opt-in-to-inherit-from-a-class-or-interface

// Library code
@RequiresOptIn(message = "This API is experimental. It could change in the future without notice.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime

@MyDateTime
// A class requiring opt-in
class DateProvider


// Client code
@OptIn(MyDateTime::class)

// Uses DateProvider
fun getDate(): Date {
val dateProvider: DateProvider
// ...
}

Все это, естественно, поддерживается в IDEA из коробки.
Плюс в Kotlin можно использовать @API Guardian

Получилась реклама Kotlin, что не удивительно, учитывая время его появления и назначение языка.

#api #java #kotlin
null safety в Java - счастье на горизонте?)

Я уже писал про проблему null safety в Java, особенно ярко видимую на фоне Kotlin.
https://t.me/javaKotlinDevOps/98
В посте по ссылке выше разработчики Kotlin собрали поддерживаемые ими виды аннотаций а-ля @NotNull https://kotlinlang.org/docs/java-interop.html#nullability-annotations
И их число говорит о многом, а точнее о состоянии разброда и шатания в Java мире.

Так вот - похоже в войне Nullable аннотаций наметился победитель, и это JSpecify https://jspecify.dev/docs/user-guide/.
С одной стороны это очередная внешняя библиотека:

dependencies {
implementation 'org.jspecify:jspecify:1.0.0'
....
}


Которую поддерживает IDEA при поиске проблем. Но она и другие библиотеки поддерживает.

Что же изменилось?

А то, что собрался ряд достаточно известных компаний: Google, Oracle, JetBrains, Uber, VMware/Broadcom (а значит и Spring), и они стандартизировали именно JSpecify.
Что это значит, ряд примеров:
1) Spring переводит свой фреймворк на JSpecify к Spring 7\Spring Boot 4
2) про JetBrains и IDEA c Kotlin я уже сказал
3) Google внедряет новые аннотации в Guava. И наверняка куда-то еще)
...

Две основные фишки нового подхода:
1) Uber доработала плагин компилятора NullAway на основе errorprone:

tasks.withType(JavaCompile).configureEach {
options.errorprone {
disableAllChecks = true // Other error prone checks are disabled
option("NullAway:OnlyNullMarked", "true") // Enable nullness checks only in null-marked code
error("NullAway") // bump checks from warnings (default) to errors
option("NullAway:JSpecifyMode", "true") // https://github.com/uber/NullAway/wiki/JSpecify-Support
}
}


и warning в IDEA легким движением руки превращается в error компиляции.
Работает в JDK 17,21 и 22+ https://bugs.openjdk.org/browse/JDK-8225377
Аналогично можно сделать в Maven.

2) Другое важное изменение - возможность задавать значение null safety по умолчанию для пакета, модуля или класса.

@NullMarked
package org.example;

@NullMarked
class MyClass {


Эти объявления означают, что все поля и переменные в классе или пакете должны быть not null.
А если null значение все же нужно - нужно явно пометить его аннотацией @Null

Чтобы заменить старые аннотации на новые есть правила OpenRewrite https://docs.openrewrite.org/recipes/java/jspecify/jspecifybestpractices

Пару ложек дегтя:
1) Oracle в JDK пока аннотации не внедряет. Зато JDK пропатчила начиная с 17-й, чтобы валидация на этапе компиляции заработала.
2) Hibernate присматривается https://github.com/hibernate/hibernate-orm/discussions/6220.

Что я могу сказать в итоге - удачи, дело нужное!

А в прикладе внедрять уже можно. Ситуация НЕ похожа на известную шутку: было 10 разных стандартов, люди решили это изменить и их стало одиннадцать)
Проблема есть, и массовому внедрению ее решения мешал по большому счету тот факт, что единого решения не было.

#null_safety #java
🔥2
Концепция venv (virtualenv) в Python

Концепция крутая, как по мне ноутбуки и виртуальные окружения - две самые крутые фичи в Python.

Если вкратце о ее сути: ты создаешь для каждого проекта отдельную виртуальную среду, со своим интерпретатором Python (разные версии) и своим набором библиотек.
Это удобно, и решает проблему конфликта зависимостей. Небольшое уточнение: если бы все сервисы и библиотеки явно указывали версии зависимостей - конфликтов бы не было, но мы же говорим о реальном мире.
К слову, концепцию позаимствовала и Java, я про jenv - https://t.me/javaKotlinDevOps/442 - правда, ограничить можно только версию Java.

Но блин.
Почему утилит, реализующих виртуальные окружения столько:
- venv
- virtualenv
- uv
- Poetry
- PDM
- Hatch
- Rye
- Conda
- Mamba
- Micromamba
- Pixi
- Pipenv
- pyenv-virtualenv
- virtualenvwrapper
- Tox
- Nox
- Devbox
- Flox
- Devenv.sh
- Spack
- Vex
????

Явная иллюстрация анекдота про 10 стандартов)

Ясно, что они не идентичны по функционалу.
1) кто-то добавляет возможность менеджера пакетов (и это правильно),
2) кто-то позволяет формировать список зависимостей проекта requirements.txt (и это тоже правильно),
3) кто-то добавляет возможность делать lock зависимостей (спорная фича IMHO).
Кто-то просто устарел. Кто-то заточен для тестов, где нужна куча разных сред. Кто-то просто добавляет небольшие фишки в другой менеджер, типа убирает необходимость явно включать использование виртуального окружения в консоли (activate).
Но все же...
Причем 4 из них имеют официальный статус)

P.S. Самой крутой и современной считается uv. На данный момент.

#python #java #virtual_env
Что не докрутили в record-ах?

Для начала кратко о том, что докрутили:
1) компактное объявление, типовые методы из коробки
2) иммутабельность
3) минимально необходимая расширяемость - дополнительные конструкторы, интерфейсы, обычные методы, статические поля, методы и внутренние классы.

Получаем аналог data class в Kotlin. Или структур из древних языков типа C.

Но с небольшим отличием - не хватает метода копирования "из коробки".

Почему так сделали? Есть же Cloneable интерфейс. И его даже можно добавить в record руками.

Думаю, причина в иммутабельности record и скажем так скомпрометированности clone().

Для иммутабельной сущности нет смысла в полной копии - можно использовать текущий объект.

С clone() основная проблема в том, что "из коробки" он делает поверхностную копию, но при переопределении может дать полную. И вообще полную копию автоматически сделать сложно. А это приводит к путанице - метод один, а поведение может отличаться.

В итоге приходим к тому, что иметь возможность быстро сделать поверхностную копию записи с изменением пары полей было бы неплохо. И такой JEP есть https://openjdk.org/jeps/468
Надеюсь внедрят.

#java #иммутабельность
Снова минутка цитат на канале:
«Термин „структурное программирование“ был введён в 1969 году.
С тех пор термин „структурный“ применялся к любой деятельности в области ПО, включая структурный анализ, структурный дизайн и структурное валяние дурака».
Стив Макконнелл «Совершенный код».


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

Я уже писал про структурный дизайн - https://t.me/javaKotlinDevOps/400.
Напомню, там была речь о том, что не обязательно заводить кучу объектов и интерфейсов, если процесс простой и раскладывается на три части - подготовка данных, преобразования и запись.
Тогда его можно реализовать в виде сервиса, "чистой" модели и репозитория. К слову: ETL = Extract -> Transform -> Load - о том же.

Так вот - структурное программирование тоже раскладывает любой процесс на три части, только уже на уровне метода: последовательный код, условия и циклы.
Казалось бы - ну да, очевидно это так. Но есть нюанс - тут речь идет о проблеме множественных выходов из метода.
Структурное программирование появилось как ответ на широкое распространение оператора go to и призвано бороться с ним.
Опять вопрос - go to мы победили, тогда зачем эти "предания старины глубокой"?
Нет, не победили. Точнее победили, но не до конца.
Т.к. у нас есть множественный return и throw. А если копнуть глубже, и расширить проблему на любые прыжки по коду - break и continue.
Надо ли от них отказываться, учитывая что парадигма то вроде полезная?
На мой взгляд - нет.
Охранные выражения (guard pattern) - однозначно полезны.
throw для сигнализации об ошибке - тоже ок, они для этого создавались.
С рядом условий:
1) unchecked
2) не надо просто для передачи управления
3) должен быть определен слой\процесс перехвата исключений на уровне сервиса
break и continue - если без них код сложнее читать - тоже допустимы. Прыжки то небольшие, в рамках цикла. Хотя я ими пользуюсь редко, кейсов мало.

Т.е. снова приходим к искусству компромиссов.
Всякий раз, перед написанием такого оператора стоит подумать - нет ли других вариантов? Не усложняется ли он чтение и понимание кода?
Суть структурного программирования - код каждой операции должен просто читаться. Нет "спагетти-коду"!

#book_review #java #code #structure_programming #structure_xxx #principles
Медленная загрузка сервиса - значит Java?)

Есть такая проблема у Java, в частности при использовании Spring Framework. А точнее когда поверх Spring-а накручиваются свои компоненты.
Загружается куча классов, много кода инициализации = много времени. Как с этим борются - см. по тэгу #java_start_boost
Но только ли это проблема Java?

Запускал небольшую AI модельку на Python. Один скрипт. Скрипт стартует более 20 секунд.
Ну, думаю, модель так долго грузится. Померил - нет, модель порядка 3 секунд. Она уже в виде кэша скачана на локальный компьютер, да и не LLM это.
Антивирус? Интерпретатор Python?

Нет, всего лишь библиотека sentence-transformers.
На самом деле конечно не всего лишь. Она под капотом грузит движок для инференса - PyTorch. Плюс другие зависимости.
Но за 20 секунд старта ответственна именно строчка c импортом:

from sentence_transformers import SentenceTransformer


Тут еще видится "выстрелил" высокий уровень абстракции, принятый в Python.
Пишешь пару строк - у тебя все работает. Удобно? Да. Но есть нюансы)

Вывод - высокий уровень может превратится в айсберг. Ты видишь вершину, а под ней еще...

#python #java
Сложно не заметить, что последние пару месяцев у меня основная тема блока - "жемчужины" из книги Совершенный код.

Сегодня еще один пост, пост-"мысль вслух".

Самое удивительное в этой книжке - это два факта:
1) на английском она издана в 2004 году
2) она актуальна.

Я пытаюсь вспомнить, что же там устарело и вспоминаю лишь следующее:
а) в Java появились Enum (на тот момент еще нет)
б) Visual Basic умер (там есть примеры в числе прочего на VB)
в) IDE стали сильно лучше, считать открывающие и закрывающие скобки самому уже не надо
г) кажется все языки получили свой аналог xUnit, "костылить" свой подобный фреймворк тоже не надо
д) у нас есть git и история изменений в IDEA, "прихранивать" копию исходников перед изменением не нужно
е) на способы проверки повреждения данных в памяти из-за кривых указателей смотришь с ужасом, но все такие главы подписаны - для C\C++ и при желании их можно пропускать. Да и скорее всего большая часть этой информации актуальна до сих пор.

И пожалуй это все! За 20+ лет.
Даже обсуждение go to и глобальных переменных лишь на первый взгляд кажется не актуальным для Java...

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

#book_review #java
💯5
Магические 80% покрытия кода тестами.

Часто возникает вопрос - почему 80?
Краткий ответ - почему бы и нет)

А если серьезно: оценка может быть числовой (процент покрытия) или бинарной (достаточно или нет).
Бинарная плоха тем, что не документирована и зависит от мнения эксперта. Это может привести к проблемам на код-ревью.
А тут умные люди из SonarQube придумали метрику покрытия https://docs.sonarsource.com/sonarqube-server/user-guide/code-metrics/metrics-definition#coverage
и дали её рекомендуемое значение. И это не 100%, т.е. запас есть.
Считаю, что от этой рекомендации стоит отталкиваться.
К тому же JaCoCo, обычно используемый для расчета покрытия, позволяет гибко настраивать сам процесс.

Следующий вопрос, который может возникнуть: "Почему ради достижения 80% я должен писать тесты на элементарный код?" Я про getter, setter и все, все, все https://t.me/javaKotlinDevOps/34
Ответ: "Нет, не нужны эти тесты".
Лишний код можно исключить из покрытия:
1) generated код исключается по умолчанию начиная с JaCoCo 0.8.2
2) generated код Lombok - через lombok.addLombokGeneratedAnnotation = true (жаль, что только для Lombok это можно сделать, но есть еще альтернатива - см. следующий абзац.)
3) тривиальный код - явно исключая классы или пакеты по маске через настройки JaCoCo. Если какой-то код не получается исключить таким образом - это повод задуматься о рефакторинге.

Еще вопрос: "Зачем писать модульные (unit) тесты ради покрытия на интеграционный код: сервисные классы или классы контроллеров, которые представляют линейную цепочку вызовов методов?"
Ответ: "Не обязательно писать unit тесты".
Для простых микросервисов является нормальной перевернутая пирамида тестирования - когда интеграционных тестов разработки больше, чем модульных.
Простой код можно покрыть интеграционными тестами, включив их в общее покрытие. JaCoCo позволяет это настроить. Единственная проблема может быть, если тесты находятся в одном модуле, а код для покрытия - в другом, но и она решается.

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

Ну и если ничего не помогло - тогда уже стоит задуматься о новом Quality Gate в SonarQube с меньшим процентом покрытия.
Никакой магии нет - https://t.me/javaKotlinDevOps/403.
Но числовой показатель (80% по умолчанию), задокументированные исключения и цель покрыть максимум кода, в котором возможны ошибки, быть должны.

P.S. Еще AI можно попросить тесты написать, у него это неплохо получается)

#unittests #integration_tests #java
Почему победил компактный стиль форматирования кода?

Я про сталь Oracle\Sun и очень похожий на него стиль Google:

public class OrderService {

private static final int MAX_RETRIES = 3;

public String processOrder(Order order, boolean isPriority) {
if (order == null) {
...

vs

public class OrderService
{
private static final int MAX_RETRIES = 3;

public String processOrder(Order order, boolean isPriority)
{
if (order == null)
{
...


Базовый ответ - потому что он компактнее)

Но я бы накинул еще один аргумент. Рассуждение:

- стиль форматирования нужен человеку, и не нужен машине
- человеку важно понимать, где начало и конец логического блока кода или управляющей конструкции
- "железобетонный" способ это понять - четкие маркеры, хороший пример: begin-end в Delphi, If-End If в VB
- хороший, но не идеальный, т.к. слишком много символов - 8 вместо минимально возможных 2
- скобки на той же строке, что и управляющая конструкция, у Google\Sun - это по сути компактная эмуляция begin-end. Эмуляция потому что они не обязательны. Скобки как бы становятся частью управляющей конструкции - if, for, while, switch, try.
- а вот альтернативный вариант - это что-то странное, т.к. скобки по отступам находятся на уровне управляющей конструкции, но зачем тогда перенос на новую строку?

Тогда логичнее вот так:

public class OrderService
{
private static final int MAX_RETRIES = 3;

public String processOrder(Order order, boolean isPriority)
{
if (order == null)
{
...

Но это еще страннее смотрится.

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

P.S. Спонсор выпуска - Совершенный код, Стив Макконнелл)

#java #formating
👍1
Что C++ унаследовал от Java?

Внимательный читатель должен сказать - стой, автор, ты ничего не перепутал? Может Java от C++?

Не перепутал)
Да, Java был создан как безопасная и легко портируемая альтернатива C++.
Но кое-что он вернул прародителю.

Как ни странно - это стандарт документирования кода. C++ изначально шел без стандарта документирования. Используйте что хотите. А JavaDoc с Java был изначально. По факту стандартной тулой для документации С++ стал Doxygen. А Doxigen взял за основу JavaDoc.
Такие дела)


#java #c++
Снова нападки на Scala)

Я уже немного писал про Scala когда говорил о выборе новых языков программирования https://t.me/javaKotlinDevOps/251
Но осталось чувство недосказанности. Сложный - да, о ведь функционально крутой. Может стоит набрать команду "спецназа" от разработки, пусть на Scala пишут ядро системы?

Я бы не стал. Сложность это полбеды. Сложность не там, где ей стоит быть - вот проблема.

Большиство предметных областей дают нам бизнесовую сложность. Если бы это было не так - вместо разработки стоило бы купить готовое решение. Или взять готовую библиотеку.
Сложность должна быть в бизнес-логике. А не в конструкциях языка.

Второй момент - основная задача разработчика (чего-то сложнее hello world) - борьба со сложностью. SOLID, DRY. переиспользование кода, микросервисы, уровни приложения, говорящие имена, читаемость кода, DDD, итеративная разработка... - все это помогает уменьшить сложность. А тут язык провоцирует ее увеличение.

И ещё пример. Google. Компания может позволить себе нанять наверное любого программиста. Популяризовать любой язык.

Но что она делает?

Видит проблему на backend.
C++ быстр, но не безопасен и сложен.
Java безопасная, попроще, но не идеал.
И придумывает Go: быстрый и простой. Ещё заточенный на многопоточность, но простую - goroutines.

Мобильная разработка - есть завязка на JDK. Почему так - тема отдельная. Базовый язык для JDK - Java, про Java см. выше. Тут появляется более простой Kotlin - и Google делает его стандартом Android разработки.

Итого - в обоих случаях Google сделал разработку проще. production подход. Хотя где-то у них используется Scala.

#java #kotlin #scala
👍1
Почему в Python "неправильная" документация.

Если посмотреть библиотечный Python код, то там можно увидеть вот такое:

class IntervalArray(IntervalMixin, ExtensionArray):
"""
Pandas array for interval data that are closed on the same side.


Или такое:

@classmethod
def _validate(cls, left, right, dtype: IntervalDtype) -> None:
"""
Verify that the IntervalArray is valid.


Что-то к так с документацией, да?)
Зачем питонисты решили сделать все наоборот - комменты после кода???
До кода же логичнее - вначале читаешь доки, потом если надо смотришь код?

Не от балды, нет.
Интерпретатор при загрузке модуля читает первое выражение в теле класса/функции/метода и, если это строковый литерал, помещает его в атрибут ___doc___ соответствующего объекта. Работает принцип convention over configuration.

Также документация выводится с помощью метода help(obj) - если надо прямо в коде. Или через рефлексию - inspect. Или с помощью CLI утилиты pydoc.
Описывается формат документации стандартом PEP 257. Т.е. все продумано.

Причём поля класса документируются точно также для единообразия. Хотя на них стройная система, описанная выше рушится.
И появляется интересный нюанс - если по привычке писать документацию к полям в JavaDoc стиле, то она сопоставится с другим полем)

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

P. S. Как я обратил на это внимание? Один агент написал документацию в формате JavaDoc, другой на ревью заметил, что это не по стандарту Python)

#lang #python #java #conv_over_conf