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

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

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

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

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

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

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

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

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

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

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

Продолжу серию постов https://t.me/javaKotlinDevOps/269 про оптимизацию производительности Java приложения.
В первых двух частях я говорил про такие технологии как:
1) native image - компиляция в нативный код на этапе сборки, т.об. устраняется необходимость class loading-а и JIT компиляции
2) CRaC - сохраняет и восстанавливает состояние работающего Docker образа с JRE на диск, т.об. мы получаем уже оптимизированный код

Какие еще могут быть способы выйти на оптимальную производительность побыстрее? native image мы пока отбрасываем, у нас обычная JVM и на ней запускается байт-код.
Встречный вопрос - а что мешает достижению оптимальной производительности? Как ни странно - JIT компилятор. Ведь чтобы ему понять, как оптимизировать байт-код, нужно собрать статистику. Причем процесс сбора статистики может быть цикличным - собрали, оптимизировали, поняли что оптимизация неверная, вернули байт-код обратно... И это все требует времени. А почему бы тогда не собрать статистику по использованию кода заранее, прихранить ее куда-нибудь, а потом использовать сразу со старта.
Эта техника называется Profile-Guided Optimization, в нее умеет GraalVM https://www.graalvm.org/latest/reference-manual/native-image/optimizations-and-performance/PGO/basic-usage/ и упоминаемая ранее Azul JDK https://docs.azul.com/prime/Use-ReadyNow Но к сожалению оба - только в коммерческой версии.
Еще похожую технику использует стандартная OpenJDK при tired compilation https://for-each.dev/lessons/b/-jvm-tiered-compilation но в данном случае речь идет про отпимизацию в течение одной рабочей сессии.

P.S. Это еще не все возможные варианты, не переключайтесь)

P.P.S. Может возникнуть вопрос - зачем GraalVM использует профилирование, он же и так все оптимизировал? Нет, не все. На этапе компиляции нет информации об реальном использовании кода. А оптимизация - это не только компиляция в нативный код, это еще может быть выбрасывание лишних проверок, разворачивание цикла и т.д.

#jre #performance #java_start_boost
Всем привет!

Продолжим рассказ про разные способы ускорения Java. Для начала я бы разделил ускорение в целом на 4 более конкретных направления:
1) ускорение запуска приложения за счет оптимизации\отмены первоначальной загрузки классов
2) ускорение выхода приложения на оптимальную производительность путем оптимизации JIT - Just In Time - компиляции байт-кода в нативный
3) ускорение запуска и в какой-то степени выполнения приложения за счет более легковесного фреймворка, используемого для разработки приложения
4) оптимизация сборщика мусора для достижения нужного баланса между затрачиваемыми ресурсами и паузой в обслуживании клиентских запросов, она же Stop the World

Сегодня поговорим про первое направление. С одной стороны упомянутые ранее и native image, и CRaC тоже ускоряют запуск. Но обе технологии имеют ограничения. native image запрещает reflection и динамическую загрузку классов. Образ, сохраненный с помощью CRaC, может содержать что-то лишнее, и с данной технологией нельзя просто так перезапустить приложение при сбое - т.к. возможно причина сбоя лежит в данных, подгруженные из образа.

Начну издалека.
В Java 5 появилась вот такая фича - https://docs.oracle.com/en/java/javase/21/vm/class-data-sharing.html Class-Data Sharing, сокращенно CDS.
Фича появилась и была забыта. Есть такие фичи, про которые все забывают сразу после релиза новой Java) Еще модульность из Java 9 можно вспомнить.

О чем эта фича? Мы записываем в файл метаданные загруженных классов из classpath. Потом этот файл мапился в память работающей JVM. Зачем? Цели было две:
1) расшаривание классов между несколькими инстансами JVM и т.об. уменьшение потребления RAM
2) ускорение запуска (вот оно!)

Вначале фича работала только с классами Java core. Файл с архивом классов Java core входит в состав JDK, найти его можно по имени classes.jsa. Занимает на диске сравнительно немного - 10-15 Мб. И кстати, CDS в Java включена по умолчанию, используется как раз этот файл.

Позже, в Java 10 https://openjdk.org/jeps/310 появилась возможность дампить и пользовательские классы, эту фичу назвали AppCDS. В Java 13 создание архива было упрощено https://openjdk.org/jeps/350
Пользовательские классы можно добавить в архив предварительно запустив процесс со специальной опцией командной строки -XX:ArchiveClassesAtExit

А если у нас Spring? Ребята в Spring 6.1 обратили внимание на данную опцию и добавили ключ командной строки, позволяющий собрать информацию о динамически загружаемых классах именно для Spring Boot приложения https://docs.spring.io/spring-framework/reference/integration/cds.html
А еще дали рекомендации, как максимально точно собрать информацию о классах и подтвердили, что данная опция ускоряет загрузку на ~30% https://spring.io/blog/2023/12/04/cds-with-spring-framework-6-1 Почему подтвердили - именно такую цель ставили разработчики CDS в JEP 310, упомянутом выше.

Итого - идея в чем-то похожа на Profile-Guided Optimization. Только здесь мы предварительно собираем информацию не об использовании кода, а о загруженных классах. Чем больше информации соберем - тем быстрее будет старт приложения. Минусы - версия JDK, Spring и classpath в целом должны совпадать при тестовом прогоне и использовании в ПРОМе.


#jre #performance #spring_boot #spring #java_start_boost
Всем привет!

Ну и еще одна оптимизация времени старта Java приложения. Самые внимательные уже могли ее заметить пройдя по ссылкам из предыдущего поста.

С момента появления Spring Boot упаковка приложения в fat jar - jar содержащий все зависимости и Tomcat в придачу (или другой контейнер сервлетов) - стала неким стандартом.
Но fat jar при исполнении требуется распаковать. А разархивация всегда требовала времени, не зря архиваторы используются как бенчмарки для процессорных тестов.

Соответственно, можно заранее разложить зависимости по отдельным файлам для ускорения старта. Вот как рекомендует это делать Spring https://docs.spring.io/spring-boot/reference/packaging/efficient.html
Судя по данным статьи из вчерашнего поста это даст еще 25% ускорения при старте https://spring.io/blog/2023/12/04/cds-with-spring-framework-6-1

#performance #spring #jvm #java_start_boost
Всем привет!

Ну и последний вариант ускорения старта Java приложения. Самый радикальный, наверное. Отказ от Spring.

Надо отметить, что чистый hello world Spring сервис в плане старта не так уж плох, плюс минус 4 секунды. Основные проблемы начинаются с ростом числа зависимостей. И Spring можно тюнить, подробнее про это можно почитать здесь: https://www.baeldung.com/spring-boot-startup-speed Единственный момент, который мне не понравился - я бы не отключал C2 компиляцию - скорость старта может и увеличится, а вот выйти на оптимальную производительность не получится. И еще интересное исследование - https://github.com/dsyer/spring-boot-allocations Авторы выключили в Spring Boot все, за что мы его любим - Dependency Injection и быструю автоконфигурацию, повесили все на единственный classloader и ускорили старт в 5(!) раз. Только зачем нужен такой Spring?)

Но вернемся к отказу от Spring. Писать на голой Java я не предлагаю) Есть две альтернативы - Quarkus и Micronaut. Оба при создании основной целью ставили получить более быстрый и легковесный фреймворк, чем Spring.

Вот сравнительный бенчмарк Quarkus https://habr.com/ru/companies/haulmont/articles/443242/ Ускорение старта простейшего приложения в 5 раз, до 0.75 секунд. Я беру цифры без native image (GraalVM ), т.к. в этом случае и Spring будет "летать". Для интереса я сравнил локально, разница получилась не в 5 раз, а примерно в 2, с 2.5 до 1.2 секунды. За счет чего получилось ускориться можно почитать тут https://dev.to/nutrymaco/how-quarkus-use-build-time-to-start-your-application-faster-50n Если вкратце - Dependency Injection происходит во время достаточно сложного процесса компиляции.

А вот сравнение Micronaut со Spring https://www.baeldung.com/micronaut-vs-spring-boot Разница чуть поменьше, в 2,5 раза, но тоже ничего) Вот тут, авторы объясняют, почему они быстрее Spring - https://guides.micronaut.io/latest/building-a-rest-api-spring-boot-vs-micronaut-data-gradle-java.html И снова - внедрение зависимостей на этапе компиляции, нет рефлексии и создаваемых в runtime прокси.

Почему я назвал этот вариант самым тяжелым - оба фреймворка сильно отличаются от Spring - по используемым аннотациям, по API в целом. Кроме того они не такие зрелые, им порядка 5-6 лет, поэтому там просто меньше функционала.

#performance #spring #quarkus #micronaut #java_start_boost
Всем привет!

Как приучить себя писать модульные, они же unit тесты?
1) начинать лучше на новом проекте. Основная проблема с тестами в том, что часто писать тесты сложно - приходится создавать много моков, возможно рефакторить код. На новом проекте проще изначально начать писать тестируемый код. Особенно хорошо изначально тестируемый код получается писать используя TDD. А потом, когда втянешься - можно дописать тесты и для legacy)
2) изначально определить, что обязательно должно быть покрыто тестами, остальное исключить из контроля покрытия. Если конечно у вас подключен контроль покрытия) Ничто так не демотивирует, как написание ненужных тестов на тривиальный код
3) заставить себя написать первые скажем 100 тестов. Или 200. После того, как ключевые классы с бизнес-логикой будут покрыты тестами, появляется уверенность при рефакторинге кода. Правишь что-то, запускаешь тесты, убеждаешься, что ничего не сломал. Возвращаешься к коду спустя полгода, что-то правишь и снова все ок. Это одно из самых крутых свойств нормального покрытия кода тестами. Но для начала этого уровня покрытия нужно достичь, т.е. первое время видимого эффекта от тестов не будет.
4) переписать медленные тесты, разделить быстрые и медленные. Как правило это разделение совпадет с модульные-интеграционные. Модульные запускать как можно чаще. Причина - ожидание 5 минут ну когда же закончатся тесты - бесит
5) самый смешной пункт - включить в IDEA отображение успешно пройденных тестов. Сотня зеленых галочек... успокаивает что ли))))

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

Хочется сказать пару слов о практике T-Shape. Это когда помимо своей основной специальности - например, разработки, ты развиваешь навыки в чем-то еще. Какие именно - если рассмотреть состав типовой команды, то это будут аналитик или тестировщик. Если смотреть дальше - это могут быть DevOps, НТ. Даже может быть сопровождение ПРОМа. Насколько я знаю, такая практика применяется в лидере российского ИТ - Яндексе. Рассмотрим плюсы и минусы на примере разработчика-тестировщика.

Плюсы в целом очевидны:
1) взаимозаменяемость членов команды
2) упрощение найма за счет унификации

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

2) как я вижу развитие инженерных специальностей и ИТ в частности - все развиваются в сторону более узкой специализации. Да, любую технологию, фреймворк, библиотеку или платформу можно изучить. Проблема в том, что их очень много. Много и в разработке, и в тестировании. И "распыляя" свои усилия на 2 направления есть риск полноценно не научится ни тому, ни другому.

3) этот пункт субъективный из-за того, что я разработчик. Сравнивая разработку и тестирование как две области деятельности я бы всегда выбирал разработку. IMHO, подчеркну, что INHO, она сложнее, имеет больше направлений и поэтому интереснее. Отсюда риск, что на тестирование будет выделяться меньше времени. Вопрос в уровне инженерной культуры и дисциплине, но это снова человеческий фактор. В каких-то командах баланс будет найден, в каких-то нет и в итоге мы получим недотестированный код и баги ПРОМа.

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

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

В комментариях к предыдущему посту (на Хабре) справедливо заметили, что T-Shape может быть вынужденный.
Это когда есть приложение на редкой технологии, а команда создавшая его разбежалась. Примеры технологий, которые вспомнил: Informatica, Erlang, хранимые процедуры в БД... Или legacy монолит и снова команды уже нет. А точнее остались 1-2 человека. На рынке людей или не найдёшь (редкая технология) или они не тянут распил незнакомого им монолита (второй кейс).
В этом случае оставшиеся члены команды поневоле становятся t-shape-ми.
Случай грустный. При выборе технологий была допущена ошибка, ее приходится исправлять. Но есть и плюсы. Опыт трансформации legacy, да ещё в T-shape режиме - задача очевидно сложная. А бизнесу нужны люди, умеющие решать сложные задачи.

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

Когда заходит речь о разделении обязанностей между разработчиками и DevOps споры возникают в двух моментах - манифесты k8s\Openshift и CI джобы - они же джобы сборки.
Поговорим про первые.
Мое мнение - за манифесты k8s\Openshift должны отвечать разработчики. Почему? А вот почему:
1) liveness\readiness probes - только разработчики знают, по каким URL они находятся. Конечно в мире Spring Boot и Actuator есть некая стандартизация, но не везде и не всегда. Не всегда actuator подходит для healthcheck, но это отдельная тема
2) liveness\readiness timeouts - разработчики точно знают сколько времени старт пода. DevOps-ы могут это время эмпирически определить, но это требует времени)
3) timeouts, circuit breaker, retry - опять же только разработчики могут сказать, реализовали они их на прикладном уровне или требуется настройка на уровне Service Mesh. Могут быть требования корпоративной архитектуры\сопровождения ПРОМ, их определяющие, но опять же не везде и не всегда.
4) куда пишутся логи, какие существуют метрики, где их можно взять. Снова можно повториться, что где-то это стандартизировано, где-то нет.
5) любые другие тонкие облачные настройки - переменные среды, значение параметров в ConfigMap, поддержка graceful shutdown ....
Наверняка DevOps или сопровожденец со всем этим разберется. Но будет ли это эффективно?

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

В продолжение предыдущего поста попробую сам себе возразить.
Предположим, что наши DevOps инженеры так круто настроили pipeline, что все атрибуты, которые должен настроить разработчик, параметризованы и могут быть легко настроены разработчиком. Например, с помощью чартов Helm. Хотя по большому счёту не важно.
Значит ли это, что разработчик может расслабиться и не изучать все эти ваши Deployment, Service, EnvoyFilter, VirtualService и прочие? Мой ответ - нет. И вот почему.
1) если рассуждать дальше, то и Docker разработчику не нужен. Пусть его же DevOps-ы настраивают. А я на Tomcat встроенном запущу. Но вспомним в чем суть Docker - единая среда у разработчиков, тестировщиков и ПРОМа. Что позволяет избежать большой части ошибок, возникающих из-за разницы настроек окружения. Не всех, но большого числа
2) окей, Docker пусть будет. А k8s? Но идея та же. Приложение в облаке ведёт себя по другому, чем в standalone. Его может в любой момент прибить k8s и поднять на другой node. А это ограничивает возможности локального кэширования. В облаке несколько приложений может работать параллельно. Это нужно учитывать, например, при чтении из топика Kafka. Более того число подов может меняться - см. HorizontalPodAutoscaler. Еще момент - по умолчанию у нас ephemeral storage и надеятся на то, что те же логи сохранятся после перезапуска, нельзя. Ещё момент - одно из Cloud Native требований - быстрый старт приложения, опять же из-за потенциального перезапуска в любой момент. На этот момент не всегда обращают внимание, хотя варианты улучшения времени запуска есть, см. серию постов выше. И это я вспомнил навскидку, возможно что-то ещё упустил.

Надеюсь, я вас убедил. Если нет - жду в комментах)

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

Я иногда даю ссылки в своих постах на википедию. Ясное дело, что 100% гарантии достоверности статей в вики никто не даст. Народное творчество. Но в большинстве своем техническая (!) информация верна. Но есть забавные нюансы.

Ищу информацию по алгоритмам, используемым в Rate Limiters. Есть такой алгоритм - Token Bucket. Есть статья по нему https://ru.wikipedia.org/wiki/Алгоритм_текущего_ведра
Алгоритм статья описывает в целом верно, хотя и добавляет туда сетевой специфики, видимо автор создал ее разбираясь в работе сетей, например QoS.
Но посмотрим на название. Алгоритм текущего ведра. Токен = текущее?
Причем проблема не в творческом переводе. У меня уже была ссылка на статью с описанием основных алгоритмов https://habr.com/ru/articles/448438/
Смотрим туда Leaky Bucket - протекающее ведро. Вполне логичный перевод. Но у нас же Token bucket. Или алгоритм маркерной корзины, что собственно мы и видим в первой же строчке статьи вики. Это два разных алгоритма. А статья создана в 2008 году, сразу с неправильным заголовком.

Что в итоге - в итоге путаница. Если "загуглить" заголовок - https://yandex.ru/search/?text=Алгоритм+текущего+ведра то мы увидим условно 5 ссылок на Leaky Bucket и 5 ссылок на Token Bucket, причем последние - это копии статьи с русскоязычной вики в других вики.
Второй вывод - мало просто скопировать википедию...)

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

Ну что, началось)
https://www.piter.com/collection/all/product/programmirovanie-na-python-s-pomoschyu-github-copilot-i-chatgpt
Ок, ещё одна книжка про ChatGPT. Смотрим аннотацию: «Используя GitHub Copilot, можно простым языком описать, что должна делать программа, а искусственный интеллект тут же сгенерирует ее.
Узнайте, как создавать и улучшать программы на Python с помощью ИИ, даже если прежде вы не написали ни строчки компьютерного кода.». И ещё: « Глава 4 — первая из двух глав, в которых вы научитесь читать код на языке Python. Действительно, Copilot будет писать код за вас, но вам нужно уметь читать его, чтобы определить, будет ли он делать то, что вы хотите. И не волнуйтесь: Copilot поможет вам читать код!»
И это не ролик, не статья, целая книга...
Войти в IT, если с первого раза не получилось) Интересно, на собесах Copylot уже используют?)
Меня только один вопрос мучает: если человек не захотел или не смог освоить язык программирования (фреймворк) - как хорошо он сможет спроектировать сервис или алгоритм?

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

Недавно я уже писал о пользе стандартизации на примере формата данных для сохранения информации о микросервисе - https://t.me/javaKotlinDevOps/291 (cyclonedx). А еще в одном посте - про работу с исключениями - упоминал библиотечку для вывода информации об ошибке в API - https://t.me/javaKotlinDevOps/310 (jdoctor).
Так вот - стандартизация добралась и сюда)
Во-первых, как выяснилось - уже с 2016 года есть стандарт "Problem Details for HTTP APIs" https://datatracker.ietf.org/doc/html/rfc7807
Во-вторых - в Spring Boot 3, т.е. с 2021 года, появилась его имплементация. Вот неплохая статья, описывающая детали https://www.baeldung.com/spring-boot-return-errors-problemdetail
Если вкратце - ответ при ошибке будет иметь стандартизированный вид похожий на такой:
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "Invalid request content.",
"instance": "/sales/calculate"
}

Библиотеки, решающие подобную задачу в Java уже были:
1) упомянутый ранее https://github.com/melix/jdoctor,
2) https://www.wimdeblauwe.com/blog/2022/12/01/the-error-handling-spring-boot-starter-library-vs-spring-6-problemdetail/
...
Но я думаю, что именно данное решение - от Spring, да еще по стандарту - имеет шансы распространиться достаточно широко и популяризовать данную практику.

Что еще хочется отметить:
1) стандартизация - это хорошо. Каждый поставщик API разрабатывает формат для ответа при ошибке, каждый потребитель - специфический код обработки ошибок для всех вызываемых сервисов. А при этом понятно, что формат информации об ошибке мало зависит от бизнес-процесса
2) еще в 2018 году в Сбере формат ответа для REST запроса был стандартизирован. Это круто. Не круто то, что формат отличается от RFC. И то, что область его применения была ограничена общением с фронтом

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

Я часто вижу в проектах лишние настройки. Как правило, они попадают в проект следующими путями:
1) скопировали из каркаса\образца\соседнего сервиса не задумываясь - нужны эти настройки или нет. Да, принцип "работает - не трогай" встречается и у разработчиков)
2) решили явно прописать какие-то настройки, так сказать для надежности

Я считаю, что так делать не надо. Почему?

1) лишние настройки раскрывают нам лишние детали, которые или не нужны вообще, или нужны, но не сейчас. Повышается когнитивная сложность кода. Знать все детали своего сервиса - это хороший подход, был, лет 10-20 назад. Сейчас ПО очень сильно развилось в плане специализации, количество зависимостей среднего проекта - несколько сотен, поэтому знать все детали просто невозможно.
2) следствие из сказанного выше - ухудшается читаемость кода. Да, это моя любимая тема. Мы чаще читаем код, чем пишем. Настройки тоже часть кода.
3) среди скопированных настроек могут быть не нужные в данный момент. Код легко меняется, ТЗ меняется также легко, поэтому добавлять что-то "на вырост" не стоит
4) портянка настроек, в которую что-то постоянно добавляется, может превратится в некий аналог "большого кома грязи", который будут боятся трогать. Как разработчики, так и сопровождение. Чтобы этого не допускать - настройки нужно чистить. Чтобы меньше было чистить - не нужно добавлять лишнее. Как-то так)

А вообще есть такой хороший принцип, описывающий то, что я хочу сказать: convention over configuration. Тоже одна из моих любимых тем. Принцип говорит о том, что должны быть некие настройки по умолчанию, устраивающие большинство потребителей. Эти настройки потребитель не задает, они заданы где-то внутри сервера или библиотеки.

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

Снова попробую сам с собой поспорить ... санитары, ау ... так ли хорош принцип convention over configuration.

1) Первое возражение я уже упомянул в предыдущем посте. А как же полный контроль над настройками проекта? Мало ли что там в значениях по умолчанию.
Ответ: при текущей модульности и сложности ПО - это видимость контроля. Невозможно вынести все настройки в один файл. А даже если и возможно - как потом с этим работать?
С другой стороны достаточный набор модульных и регрессионных тестов плюс нагрузочное тестирование дает некую уверенность, что все настроено верно. А тесты нужны в любом случае.

2) Если система прячет от нас настройки - она менее гибка, и в нестандартном use case ее придется настраивать "через одно место". И это в самом деле важный момент. convention over configuration не означает, что разработчик компонента спрятал все настройки в "черный ящик". Это неправильный convention over configuration. Правильный - разработчик продумал некие настройки по умолчанию, удовлетворяющие основные use cases, но оставил возможность подтюнить при необходимости.
Это может быть application.yaml в Spring Boot, код на Kotlin или Groovy DSL в Gradle или даже написание плагина в Maven. Последний кейс может показаться антипримером - настроить что-то под себя достаточно сложно. Кто-нибудь делал свой Maven плагин?) Но как раз за это многие и любят Maven - сделать из скрипта сборки "большой ком грязи" на Maven гораздо сложнее, чем в том же Gradle. Так что кажется, что и такой вариант допустим.

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

И "последняя серия" про convention over configuration.
Я уже говорил, почему стоит придерживаться данного принципа разработчику и команде в целом. Но можно посмотреть чуть шире.

1) с настройками приложения могут работать люди, не относящиеся к команде - тестировщики, DevOps-инженеры (да, они не должны этим заниматься, но занимаются), сопровождение ПРОМ. И у них будут похожие проблемы:
а) слишком много настроек
б) не понятно, что важно, что нет
в) не понятно, у всех одинаковые настройки (скопированные из каркаса) или у кого-то есть особенности, требующие, чтобы на них обратили внимание. По-хорошему, все это должно быть описано в документации к релизу, но случается всякое)

2) если ты разработчик какой-то библиотеки или сервиса, то вывалить на пользователей сотню настроек, давая им возможность все кастомизировать "под себя" - самый простой, но не самый правильный вариант. Даже если ко всем настройкам есть подробная документация, но как я уже написал выше - случается всякое) Правильный подход - подумать, как этим сервисом будут пользоваться. Это на самом деле критическая проблема. Не для всех, для того же open sourse проблема видится не критичной - библиотека, которую неудобно использовать, скорее всего не пройдет "естественный отбор". А вот в "кровавом enterprise" проблема вполне себе существует. Не всегда пользователи могут отказаться от использования какой-то части платформы. Так вот, чтобы понять оптимальные настройки по умолчанию - надо поставить себя на место пользователя. Или собрать обратную связь, или пользоваться своим продуктом. Т.об. принцип convention over configuration способствует движению в правильном направлении. Хотя конечно не является гарантией.

Вот теперь пожалуй всё)

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

Запилил небольшое сравнение AI чатов для задач разработки.
https://gitverse.ru/javadev/ai-tools-comparision/content/master/README.md
Почему в Git - потому что там есть полноценный Markdown и таблицы.

Фокус на бесплатных инструментах - для тех, кто хочет попробовать. Сравнение функциональное + бенчмарки, без реальных запросов. По реальным задачам сделаю отдельный пост.

Пока мне больше всего нравится Perplexity. Работает без VPN, есть ссылки на источники, под капотом несколько мощных моделей, можно загружать книжки для пересказа и есть упор на точный поиск в интернете. Далеко не все инструменты в принципе умеют искать в интернете. Но даже те, что умеют - часто галлюцинируют. Примеры:
1) что нового в Java 22 - все, кто умеют искать, ответили более менее точно
2) первая тройка на Олимпиаде 2024 и разбивка по медалям - точно ответила только Perplexity, остальные показали рандомные цифры и даже страны.
Из минусов - в бесплатном режиме есть 5 запросов в режиме Pro в день, но нет выбора модели. Т.е. какая модель использовалась - понять невозможно. Но отвечает неплохо.
По VPN - это может быть критично, если уже сидишь под рабочим VPN.

Также выглядят интересными ChatGPT, Deepseek Coder и Mistral.

Еще замечания:
1) YandexGPT добавил как гарантировано доступный в России, хотя сам Яндекс для разработки ее не позиционирует. И еще забавный момент - в Алисе последняя версия YandexGPT доступна ограничено, а в Cloud - похоже что нет. Более того, она и отвечает лучше на "той же" версии модели по вопросам разработки. Лучше, но все равно слабее иностранных конкурентов.
2) GigaCode - это отдельная модель, отличающаяся от GigaChat. Доступна только через плагин IDE. Ребята неплохо развиваются, хотя и с упором на AutoCompletion, а не режим чата.
3) Copilot c сайта выглядит как вариант ChatGPT, отстающий от него по версиям, и главное - не заточенный под разработку, а под интеграцию с продуктами Microsoft. Скорее всего Copilot из GitHub - это другая, дообученная модель. Но, увы, только платная https://github.com/features/copilot
4) размер контекста модели - понятие растяжимое. Напомню - контекст определяет размер запроса, ответа и памяти модели в рамках текущего диалога. Почему растяжимое - не столько из-за того, что считается в токенах, а токен не равен слову. Похоже каждый инструмент интерпретирует это число по-своему - вот тут интересно насчет ChatGPT https://habr.com/ru/articles/758890/ Вот что пишет Perplexity: By default Perplexity reads at least 4000 tokens per question but it can read many more with file upload. Longer pasted text is converted to a file automatically.
5) если инструмент показывает источник ответа - не факт, что ответ в точности такой, как в источнике. Но в любом случае источник полезен.
6) Deepseek Coder и Mistral не так известны, но заточены под работу с кодом и неплохо работают судя по бенчмаркам, поэтому и попали в сравнение

P.S. Я не спец по ML инструментам, я только учусь)

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

Немного мыслей по AI моделям.

Вышло довольно много open source моделей - LLama от запрещенной Meta, Mistral, DeepSeek, Grok 1 от Twitter. Еще есть Gemma от Google - легкая, возможно не самая новая модель, специализированные модели от OpenAI. Это хорошо, так как дает возможность подключения к разработке моделей команд, не имеющих большого числа денег на GPU. Дообучение моделей (fine tuning) дешевле первичного обучения. Запуск уже обученной модели - тоже дешевле. Плюс open source - это гарантия, что к AI будет доступ даже если сервисы, описанные мной ранее по тем или иным причинам закроются. И Мета конечно выделяется среди остальных тем, что отдала в open source последнюю тяжелую (большое число параметров) версию модели.

Второй момент: в тестах и в новостях сравниваются 2 группы моделей - общего назначения и специализированные. Общего назначения - ChatGPT, Claude, Gemini, Llama, Grok, DeepSeek, Mistral, YandexGPT, GigaChat. Специализированные, на примере разработки - DeepSeek-Coder-V2, Codestral, CodeLlama, Phind, GigaCode. Можно сделать вывод, что модели последнего поколения достаточно мощные, чтобы хорошо справляться со специализированными задачами, типа написания кода. Но любую модель всегда можно подтюнить, и тогда она или превзойдет модель общего назначения или будет сравнима с ней даже имея меньший размер (требуя меньше железа).

Еще тренд - разделение моделей на легкие и тяжелые. Например, LLama 8b, 70b и 405b, это число параметров в billions. Т.е. есть понимание, что большие модели - это дорого в облуживании, при этом во многих случаях применяются для "стрельбы из пушки по воробьям". Некоторые модели позиционируются как доступные для запуска локально. Локально с правильной видеокартой или AI чипом https://ru.msi.com/Landing/AI-Laptop/nb конечно)

#ml #ai #llm