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

Нашел отличное видео по исключениям в Java https://www.youtube.com/watch?v=UIbbNsta2UE

Краткий конспект, не влияющий на рекомендацию посмотреть видео:
1) затраты на выбрасывание исключений конечно же есть, но если исключение в вашем сервисе равно ошибке, то проблем с производительностью не будет. Т.к. ошибки как правило не выбрасываются сотнями и тысячами в секунду
2) если ваши исключение выбрасывается в строго определенном месте кода - можно убрать из него stack trace, это неплохо так увеличит производительность. На самом деле если просто не обращаться к stack trace, то она уже увеличится, но для надежности лучше вообще не прикреплять stack trace к исключению. Или использовать StackWalking API https://www.baeldung.com/java-9-stackwalking-api
3) самый спорный и опасный совет для того же кейса - исключение, выбрасываемое в одном месте - закэшировать исключение, так его выброс будет еще быстрее. Но по сути это старый добрый go to. Использовать с осторожностью!)
4) исключение должно содержать весь контекст ошибки, в идеале с предложениями по ее исправлению. Чтобы структурировать информацию об ошибке есть библиотека https://github.com/melix/jdoctor Активность в репозитории слабенькая, но сама идея мне нравится.
5) как известно, есть исключения, которые не стоит ловить - например, OutOfMemory и StackOverflow. Но если очень надо, то OutOfMemory все же можно) Главное - заранее создать все необходимые для сохранения информации о проблеме объекты, ведь после появления OutOfMemory памяти уже не будет.

А еще из интересного - после просмотра видео станет понятно, как работает SneakyThrows в Lombok

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

TDD конечно крутая штука в плане правильного проектирования сервиса. Правильное проектирование - имеется в виду получить публичное Java API, удобное для использования, если не с первого раза, то с меньшим количеством итераций. О плюсах TDD уже говорил тут https://t.me/javaKotlinDevOps/32 И не только я)

Но кажется есть элемент, который можно к этой технике добавить.
Перед тем, как начинать писать первый тест для еще несуществующего класса - выписать как можно больше тестовых кейсов. Не для одного метода или даже класса, а для фичи, которую надо реализовать в текущей итерации. В виде готового набора тестов это сделать сложно, т.к. кода еще нет, поэтому как комментарии.
Что там может быть:
1) входные данные -> выходные данные
2) обработка возможных исключений
3) повторный запуск: идемпотентность, докат или ошибка
4) параллельный запуск
5) поведение при различных значениях настроек
6) поведение при различных настройках кодировки, языка, часового пояса, файловой системы
7) эффекты из-за отсутствия транзакционности (там где ее нет)
...
И возможно выписывание этих кейсов приведет к изменению дизайна системы. Или к пониманию, что метод\класс\модуль имеет слишком сложную логику. Или в нем много побочных эффектов. Или что есть дублирование логики между классами, которая решается либо их объединением, либо вынесением ее в третий класс. Возможно, стоит изменить границы транзакции.

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

#tdd #system_design
Всем привет!

Недавно посмотрел достаточно интересное видео про управление техдолгом https://youtu.be/pvZDcytPU3w
Почему именно техдолг - это мои "вьетнамские флешбэки", лет 8 назад я пришел на свое текущее место работы как раз с этой задачей.

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

Но видео мне понравилось и могу его порекомендовать. И вот почему.
Речь идет о извечной проблеме разработчика - "сделать все красиво". А точнее идеально. А это идеально может потребовать недели, месяца, ... А у нас Agile, спринты в 2 недели, ежедневные дейли, бизнес ждет свою фичу.

Что предлагается делать:
1) не надеяться, что декомпозиция бизнес задачи на планировании будет идеальной
2) если при реализации выясняется, что фичу невозможно сделать в запланированные сроки, а их можно прикинуть исходя из длины спринта, числа задач и их оценки - нужно сделать часть фичи, допускающую продвижение дальше всей команды. Опять же - декомпозировать правильно сложно, но итеративно это получается лучше. Главное, повторюсь - минимум кода, позволяющего продвинуться дальше команде.
3) расставить по коду подробные TODO, рассказать команде что сделано, а что нет и почему, и влить доработку AS IS. Т.об. мы гарантировано получаем большую прозрачность. А если повезет, а точнее, если удалось правильно определить, что блокирует команду сейчас - еще и лучший Lead Time.
4) далее некий робот сканирует код, находит там TODO и делает из них таски в вашем таск-трекере
5) таски будут оценены на очередном планировании и взяты в работу, возможно другим разработчиком

Самое интересное - для одной и той же исходной задачи процесс может повторяться. И, наверное, если это происходит в 5-10 раз - стоит детальнее взглянуть на задачу. Похоже она сильно повлияла на архитектуру приложения.

У подхода есть и минусы:
1) TODO может быть сильно много, и они захламят бэклог. Нужен механизм приоритезации, в видео про это есть. Если копать дальше - не всякое TODO должно попадать в бэклог. Какие-то TODO - это хотелки, которые вначале стоит обсудить с командой
2) техдолг может висеть в бэклоге месяцами, нужен механизм контроля за его исполнением
3) подход нужно объяснить бизнесу. Что это не несделанная задача - а дополнительно декомпозированная. Но, кажется, прозрачность бизнес оценит. А если удастся уложиться в сроки - тем более.

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

P.S. Отдельное спасибо автору за исторический экскурс - откуда взялось слово техдолг. Почему долг? Кто кому должен?) Спойлер - это аналогия с миром финансов

#техдолг
Всем привет!

Продолжаю серию полезных видео - 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