Всем привет!
Снова попробую сам с собой поспорить ... санитары, ау ... так ли хорош принцип 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) Первое возражение я уже упомянул в предыдущем посте. А как же полный контроль над настройками проекта? Мало ли что там в значениях по умолчанию.
Ответ: при текущей модульности и сложности ПО - это видимость контроля. Невозможно вынести все настройки в один файл. А даже если и возможно - как потом с этим работать?
С другой стороны достаточный набор модульных и регрессионных тестов плюс нагрузочное тестирование дает некую уверенность, что все настроено верно. А тесты нужны в любом случае.
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
И "последняя серия" про 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 чатов для задач разработки.
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
gitverse.ru
README.md - master | Gitverse
README.md - master. Актуальные файлы и описания. Ветки и обсуждения на платформе для разработчиков GitVerse.
Всем привет!
Немного мыслей по 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
Немного мыслей по 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
Msi
Ноутбуки с ИИ
О ноутбуках с искусственным интеллектом
Всем привет!
Поговорим снова о микросервисах. Я уже писал, почему не стоит делать слишком мелкие микросервисы https://t.me/javaKotlinDevOps/305
Но встает закономерный вопрос - "сколько вешать в граммах", в смысле - а какого размера должны быть микросервисы?
Обозначим нижний и верхний предел, а для этого придется вспомнить DDD.
Для начала рассмотрим понятие ограниченного контекста (bounded context). Это связанный набор сущностей из реального мира, для наименования которых используется "единый язык" (ubiquitous language) - непротиворечивый набор терминов. Эти сущности описываются в аналитике, тест-кейсах и превращаются в классы в нашем сервисе и в таблицы в БД. Контекстом как правило занимается одна команда - так проще всего поддерживать "единый язык". И за микросервис тоже должна отвечать одна команда. Т.е. ограниченный контекст - это отличный кандидат на микросервис. Но при этом у одной команды может быть несколько микросервисов. И контекст может быть достаточно большим. Т.е. у нас есть верхняя граница микросервиса.
Теперь рассмотрим понятие агрегата - группу сущностей, имеющую уникальный идентификатор, изменение которой производится атомарно. Т.е. агрегат - граница транзакции в БД. А т.к. возможность делегировать управление транзакцией СУБД - это очень крутая штука, то разделять агрегат между разными БД не стоит. При этом один микросервис = одна БД. Поэтому агрегат - нижняя граница микросервиса.
#microservices #ddd
Поговорим снова о микросервисах. Я уже писал, почему не стоит делать слишком мелкие микросервисы https://t.me/javaKotlinDevOps/305
Но встает закономерный вопрос - "сколько вешать в граммах", в смысле - а какого размера должны быть микросервисы?
Обозначим нижний и верхний предел, а для этого придется вспомнить DDD.
Для начала рассмотрим понятие ограниченного контекста (bounded context). Это связанный набор сущностей из реального мира, для наименования которых используется "единый язык" (ubiquitous language) - непротиворечивый набор терминов. Эти сущности описываются в аналитике, тест-кейсах и превращаются в классы в нашем сервисе и в таблицы в БД. Контекстом как правило занимается одна команда - так проще всего поддерживать "единый язык". И за микросервис тоже должна отвечать одна команда. Т.е. ограниченный контекст - это отличный кандидат на микросервис. Но при этом у одной команды может быть несколько микросервисов. И контекст может быть достаточно большим. Т.е. у нас есть верхняя граница микросервиса.
Теперь рассмотрим понятие агрегата - группу сущностей, имеющую уникальный идентификатор, изменение которой производится атомарно. Т.е. агрегат - граница транзакции в БД. А т.к. возможность делегировать управление транзакцией СУБД - это очень крутая штука, то разделять агрегат между разными БД не стоит. При этом один микросервис = одна БД. Поэтому агрегат - нижняя граница микросервиса.
#microservices #ddd
Telegram
(java || kotlin) && devOps
Всем привет!
При проектировании системы применяя микросервисный подход всегда появляется главный вопрос - как делить?
Сделаешь слишком крупно - получишь маленький монолит. Это как правило всем понятно, т.к. от монолита мы пытаемся уйти создавая микросервисы.…
При проектировании системы применяя микросервисный подход всегда появляется главный вопрос - как делить?
Сделаешь слишком крупно - получишь маленький монолит. Это как правило всем понятно, т.к. от монолита мы пытаемся уйти создавая микросервисы.…
Всем привет!
Редко даю ссылки на другие каналы, но сейчас сделаю исключение.
Папка с каналами коллег из Сбера - https://t.me/addlist/Hjh12dzfjzhmY2Qy
Сразу скажу - Java и в целом бэк-разработку тут не ищите.
А вот если хотите расширить кругозор - аналитика, тестирование, веб-разработка, облака, AI, менеджмент - есть из чего выбрать.
Выбирайте!)
Редко даю ссылки на другие каналы, но сейчас сделаю исключение.
Папка с каналами коллег из Сбера - https://t.me/addlist/Hjh12dzfjzhmY2Qy
Сразу скажу - Java и в целом бэк-разработку тут не ищите.
А вот если хотите расширить кругозор - аналитика, тестирование, веб-разработка, облака, AI, менеджмент - есть из чего выбрать.
Выбирайте!)
Telegram
IT talks
Alexey Ignatov invites you to add the folder “IT talks”, which includes 19 chats.
Всем привет!
Вопрос - где применяется подход DDD?
Аналитика, разработка, тестирование. Конечно архитектура АС, с нее все начинается.
Но это еще не все.
Есть такой класс систем как Data Warehouse (DWH) или аналитическое хранилище данных. В это хранилище попадают данные из всех бизнес-сервисов компании для дальнейшего анализа. Т.об. мы разделяем оперативную БД и аналитическую, снимая лишнюю нагрузку с оперативной БД. Особенность Data Warehouse - технологии обработки и хранения данных отличаются от используемых в системах оперативной обработки данных. Hadoop, Greenplum, ClickHouse... А значит нужны специалисты, которые подготовят хранилище под ваши данные и настроят синхронизацию с оперативной БД. Но эти специалисты не знают ваш домен, в отличие от команды. Плюс они часто становятся "бутылочным горлышком". Плюс структура данных постоянно меняется...
Что делать?
Data Warehouse специалисты готовят инфраструктуру, а за подготовку и синхронизацию данных, актуальность их структуры и способ предоставления этих данных потребителям отвечает бизнес команда. Это же ее bounded context. Подход называется Data Mesh. Вот неплохая статья на эту тему https://habr.com/ru/companies/vk/articles/720652/
P.S. На самом деле DevOps в своем идеальном виде о том же - DevOps инженеры готовят инфраструктуру, а за сборку и деплой отвечает команда.
#ddd #data_mesh
Вопрос - где применяется подход DDD?
Аналитика, разработка, тестирование. Конечно архитектура АС, с нее все начинается.
Но это еще не все.
Есть такой класс систем как Data Warehouse (DWH) или аналитическое хранилище данных. В это хранилище попадают данные из всех бизнес-сервисов компании для дальнейшего анализа. Т.об. мы разделяем оперативную БД и аналитическую, снимая лишнюю нагрузку с оперативной БД. Особенность Data Warehouse - технологии обработки и хранения данных отличаются от используемых в системах оперативной обработки данных. Hadoop, Greenplum, ClickHouse... А значит нужны специалисты, которые подготовят хранилище под ваши данные и настроят синхронизацию с оперативной БД. Но эти специалисты не знают ваш домен, в отличие от команды. Плюс они часто становятся "бутылочным горлышком". Плюс структура данных постоянно меняется...
Что делать?
Data Warehouse специалисты готовят инфраструктуру, а за подготовку и синхронизацию данных, актуальность их структуры и способ предоставления этих данных потребителям отвечает бизнес команда. Это же ее bounded context. Подход называется Data Mesh. Вот неплохая статья на эту тему https://habr.com/ru/companies/vk/articles/720652/
P.S. На самом деле DevOps в своем идеальном виде о том же - DevOps инженеры готовят инфраструктуру, а за сборку и деплой отвечает команда.
#ddd #data_mesh
Хабр
Data Mesh: что это такое и для чего он нужен инженерам
Команда VK Cloud перевела статью о новом подходе к построению архитектуры данных Data Mesh с помощью lakeFS — системы управления версиями данных с открытым исходным кодом, которая преобразует...
Всем привет!
Cуммирую серию постов про DDD - https://telegra.ph/Izuchaem-DDD--predmetno-orientirovannoe-proektirovanie-08-30
#ddd #books #book_review
Cуммирую серию постов про DDD - https://telegra.ph/Izuchaem-DDD--predmetno-orientirovannoe-proektirovanie-08-30
#ddd #books #book_review
Telegraph
Изучаем DDD – предметно-ориентированное проектирование
Всем привет! Еще в начале лета в моих постах были намеки на хорошую книгу по DDD. Сейчас как раз самое время про нее рассказать))) Влад Хононов "Изучаем DDD – предметно-ориентированное проектирование". Настоятельно рекомендую к прочтению всем, кто интересуется…
Всем привет!
Сегодня расскажу про еще один поучительный факап из моей практики.
Более 10 лет назад. Стартап. Я на данный момент и СТО, и разработчик в одном лице. Есть задача, задача в целом понятна. Декомопзирую на микросервисы и подзадачи, начинаю пилить. Дохожу до XML binding - преобразования XML в объекты и обратно. Да, тогда API в основном были XML. Решил погуглить - что сейчас есть на рынке. Кроме известного многим JAXB нахожу JiXB. Не известный тогда, и тихо умерший сейчас. Читаю описание и нахожу бенчмарк, показывающий что он ... не помню точно, но скажем в 1.5 раза быстрее JAXB. Думаю - о, круто, надо брать. Начинаю прикручивать к Spring приложению. Наталкиваюсь на кучу подводных камней - это не работает, то не работает, документации мало, ошибки не информативные и не гуглятся, т.к. сообщества особо нет. В общем убил неделю на прикручивание к проекту одной библиотеки. В итоге все заработало, конечно. А проект не был доведен до работающего состояния и так и не взлетел - как по бизнесовым причинам, так и по причине неготовности к нужному моменту.
Итоги. До сих пор стыдно за такое проектное решение. Стыдно по следующим причинам:
1) напомню, речь про стартап, т.е. нужно быстро создать работающий прототип, а не исследовать новые технологии
2) преждевременная оптимизация - данных по требуемому RPS и доступному железу на тот момент у меня не было. Нагрузочное тестирование не проводилось. Стал бы JAXB узким местом - далеко не факт
3) использовать в промышленной разработке новые, не доказавшие свою зрелость библиотеки - это риск. Очень важны сообщество (ответы на stackoverflow, а сейчас в AI чате) и работающие без бубна связки, например, Spring+конкретная технология. А риск во-первых должен быть оправдан - см. предыдущий пункт, а во-вторых - должен быть сценарий отката. Если библиотека по факту оказалась сырой - не надо заниматься реверс-инжинирингом, плодить костыли, героически превозмогать трудности. Лучше откатится на какой-то надежный вариант.
#fuckup #xml #java
Сегодня расскажу про еще один поучительный факап из моей практики.
Более 10 лет назад. Стартап. Я на данный момент и СТО, и разработчик в одном лице. Есть задача, задача в целом понятна. Декомопзирую на микросервисы и подзадачи, начинаю пилить. Дохожу до XML binding - преобразования XML в объекты и обратно. Да, тогда API в основном были XML. Решил погуглить - что сейчас есть на рынке. Кроме известного многим JAXB нахожу JiXB. Не известный тогда, и тихо умерший сейчас. Читаю описание и нахожу бенчмарк, показывающий что он ... не помню точно, но скажем в 1.5 раза быстрее JAXB. Думаю - о, круто, надо брать. Начинаю прикручивать к Spring приложению. Наталкиваюсь на кучу подводных камней - это не работает, то не работает, документации мало, ошибки не информативные и не гуглятся, т.к. сообщества особо нет. В общем убил неделю на прикручивание к проекту одной библиотеки. В итоге все заработало, конечно. А проект не был доведен до работающего состояния и так и не взлетел - как по бизнесовым причинам, так и по причине неготовности к нужному моменту.
Итоги. До сих пор стыдно за такое проектное решение. Стыдно по следующим причинам:
1) напомню, речь про стартап, т.е. нужно быстро создать работающий прототип, а не исследовать новые технологии
2) преждевременная оптимизация - данных по требуемому RPS и доступному железу на тот момент у меня не было. Нагрузочное тестирование не проводилось. Стал бы JAXB узким местом - далеко не факт
3) использовать в промышленной разработке новые, не доказавшие свою зрелость библиотеки - это риск. Очень важны сообщество (ответы на stackoverflow, а сейчас в AI чате) и работающие без бубна связки, например, Spring+конкретная технология. А риск во-первых должен быть оправдан - см. предыдущий пункт, а во-вторых - должен быть сценарий отката. Если библиотека по факту оказалась сырой - не надо заниматься реверс-инжинирингом, плодить костыли, героически превозмогать трудности. Лучше откатится на какой-то надежный вариант.
#fuckup #xml #java
Всем привет!
Наткнулся сегодня на еще одну книжку про AI. Что опять?)
Для начала у нее интересное название - "Охота на электроовец" https://markoff.science/#book
Но есть еще две причины, по которым я решил про нее написать.
1) книжка научно-популярная - история развития AI и обзор текущего состояния. До сих пор не встречал таких. При этом написана программистом (бывшим программистом судя по текущей должности). Кажется, для вкатывания в тему, если есть пробелы\проблемы в математическом образовании - неплохой вариант.
2) автор - Сергей Марков - из России, что встречается не часто. Более того - автор живет в России на данный момент. Т.е. его можно в теории встретить на какой-либо конференции и позадавать вопросы. Ну и проблем перевода точно не будет)
Скачать можно бесплатно, бумажную версию скоро выпустят тут https://dmkpress.com/catalog/computer/data/978-5-93700-333-1/
Я лично планирую прочитать.
Да, о минусах - иллюстрация на обложке для электронной версии .. ну такое. Ну и 2 тома, 1200 страниц - не всякую дорогу осилит идущий)
P.S. Угадайте, в какой компании работает автор?)
#ai #books
Наткнулся сегодня на еще одну книжку про AI. Что опять?)
Для начала у нее интересное название - "Охота на электроовец" https://markoff.science/#book
Но есть еще две причины, по которым я решил про нее написать.
1) книжка научно-популярная - история развития AI и обзор текущего состояния. До сих пор не встречал таких. При этом написана программистом (бывшим программистом судя по текущей должности). Кажется, для вкатывания в тему, если есть пробелы\проблемы в математическом образовании - неплохой вариант.
2) автор - Сергей Марков - из России, что встречается не часто. Более того - автор живет в России на данный момент. Т.е. его можно в теории встретить на какой-либо конференции и позадавать вопросы. Ну и проблем перевода точно не будет)
Скачать можно бесплатно, бумажную версию скоро выпустят тут https://dmkpress.com/catalog/computer/data/978-5-93700-333-1/
Я лично планирую прочитать.
Да, о минусах - иллюстрация на обложке для электронной версии .. ну такое. Ну и 2 тома, 1200 страниц - не всякую дорогу осилит идущий)
P.S. Угадайте, в какой компании работает автор?)
#ai #books
Dmkpress
Охота на электроовец. Большая книга искусственного интеллекта. В двух томах (эконом-издание)
Купить книгу «Охота на электроовец. Большая книга искусственного интеллекта. В двух томах (эконом-издание)», автора Марков С. С. в издательстве «ДМК Пресс». Выгодные цены в Москве, доставка. Заказать книги и учебники на официальном сайте издательства.
Всем привет!
Давненько не было постов на канале, что поделать - конец квартала, авральный режим on.
Но я вернулся) К делу.
Java всегда славилась своим boiler plate кодом. Ремарка - конечно же не только boiler plate, но сейчас про него и про борьбу с ним. Борьба идет, и в Java 16 (а точнее в Java 14 но в режиме preview) появились records, они же записи.
Делаешь вот такое объявление:
и получаешь из коробки конструктор, getter, equals(), hashСode() и toString().
Т.е все то, что раньше приходилось писать руками или использовать Lombok. Ага, Lombok. Т.е. он стал не нужен? Не совсем. Если внимательно глянуть на список того, что под капотом делает record, то можно заметить, что там нет setter-а. Т.е. record - это иммутабельный объект и value object. Две записи с одним и тем же набором полей всегда равны. Это не баг, это фича. Маленькое дополнение - record еще меняет классический getter c getXyz на просто xyz(), но это детали. Еще дополнение - вот тут среди прочих фичей Java 17 достаточно интересно о работе с record https://habr.com/ru/companies/jugru/articles/652821/
Т.е. получается, что record заменяет @Value из Lombok.
Но не заменяет:
1) полноценный @Data - изменяемый класс без boiler plate
2) кейс, когда мы не хотим все сразу getter, toString() ... а хотим только часть этих методов
3) @Builder - тут проще показать, чем объяснять:
4) @Log - простое добавление логгера в класс
5) и наконец @SneakyThrows - если вы не любите checked exception
#java #lombok #boiler_plate_free
Давненько не было постов на канале, что поделать - конец квартала, авральный режим on.
Но я вернулся) К делу.
Java всегда славилась своим boiler plate кодом. Ремарка - конечно же не только boiler plate, но сейчас про него и про борьбу с ним. Борьба идет, и в Java 16 (а точнее в Java 14 но в режиме preview) появились records, они же записи.
Делаешь вот такое объявление:
public record Point(int x, int y) {}
и получаешь из коробки конструктор, getter, equals(), hashСode() и toString().
Т.е все то, что раньше приходилось писать руками или использовать Lombok. Ага, Lombok. Т.е. он стал не нужен? Не совсем. Если внимательно глянуть на список того, что под капотом делает record, то можно заметить, что там нет setter-а. Т.е. record - это иммутабельный объект и value object. Две записи с одним и тем же набором полей всегда равны. Это не баг, это фича. Маленькое дополнение - record еще меняет классический getter c getXyz на просто xyz(), но это детали. Еще дополнение - вот тут среди прочих фичей Java 17 достаточно интересно о работе с record https://habr.com/ru/companies/jugru/articles/652821/
Т.е. получается, что record заменяет @Value из Lombok.
Но не заменяет:
1) полноценный @Data - изменяемый класс без boiler plate
2) кейс, когда мы не хотим все сразу getter, toString() ... а хотим только часть этих методов
3) @Builder - тут проще показать, чем объяснять:
Person.builder()
.name("Adam Savage")
.city("San Francisco")
.build();
4) @Log - простое добавление логгера в класс
5) и наконец @SneakyThrows - если вы не любите checked exception
#java #lombok #boiler_plate_free
Хабр
Java 17 для тех, кто не следил. Часть 1
Уже вышла Java 18, но для всех, кто сидит на LTS, по-прежнему остаётся актуальной версия 17. Такие люди могут не отслеживать постоянно фичи каждой новой версии, а спокойно заниматься своими делами и...
Небольшое дополнение по Java records. Как известно, Java - это огромное количество библиотек и фреймворков и, следовательно, вопросы совместимости.
Так вот. Spring Boot Web записи поддерживает, как в контроллере, так и в http клиентах. Java сериализация естественно, это же часть спецификации Java. Jackson сериализация. Mapstruct. И Spring Data JPA, там где это возможно, учитывая иммутабельность https://www.baeldung.com/spring-jpa-java-records
Что я забыл? Наверное забыл, но 3 года прошло - поддержку должны были уже запилить)
#java #spring
Так вот. Spring Boot Web записи поддерживает, как в контроллере, так и в http клиентах. Java сериализация естественно, это же часть спецификации Java. Jackson сериализация. Mapstruct. И Spring Data JPA, там где это возможно, учитывая иммутабельность https://www.baeldung.com/spring-jpa-java-records
Что я забыл? Наверное забыл, но 3 года прошло - поддержку должны были уже запилить)
#java #spring
Baeldung
Using Java Records with JPA | Baeldung
Learn how we can use records with JPA and Spring Data JPA.
Всем привет!
Увидел у коллеги аналитика в канале интересное мнение. Разработка - это синоним унижения, т.к. у вас всегда что-то не будет работать.
С мнением не согласен)
Посыл, что что-то всегда не будет работать - абсолютно верный. Причём сломаться может даже сборка проекта, в котором ещё ничего не меняли. Т.е. разработка ещё не началась, а уже что-то сломалось) Обидно)
Только на мой взгляд такая ситуация - это вызов. И в т.ч. и в этом кайф от разработки.
P.S. Но как я писал ранее в посте примере про внедрение проблемной технологии (крепостное слово Jixb): если решение вызова занимает неделю или две, вместо пары дней, и все это время команда ждёт - вы свернули не на ту дорогу. Не всякие вызовы стоит принимать)
#dev
Увидел у коллеги аналитика в канале интересное мнение. Разработка - это синоним унижения, т.к. у вас всегда что-то не будет работать.
С мнением не согласен)
Посыл, что что-то всегда не будет работать - абсолютно верный. Причём сломаться может даже сборка проекта, в котором ещё ничего не меняли. Т.е. разработка ещё не началась, а уже что-то сломалось) Обидно)
Только на мой взгляд такая ситуация - это вызов. И в т.ч. и в этом кайф от разработки.
P.S. Но как я писал ранее в посте примере про внедрение проблемной технологии (крепостное слово Jixb): если решение вызова занимает неделю или две, вместо пары дней, и все это время команда ждёт - вы свернули не на ту дорогу. Не всякие вызовы стоит принимать)
#dev
Всем привет!
Продолжим про тестовые библиотеки. Достаточно часто возникает задача проверить в тесте структурированные текстовые данные. Я про XML, json и yaml как самые распространённые варианты. XML первым указан по старшинству, а не распространённости) И он пока ещё жив.
Зачем для этого нужно специализированная библиотека:
1) текст может отличаться формированием - пробелами и переносами строк. Иногда это важно при сравнении, но часто нужно проигнорировать
2) могут быть «лишние» тэги/атрибуты - которые не должны участвовать в сравнении
3) может отличаться порядок тэгов
4) может стоят задача проверить только отдельные элементы в дереве, или их количество
Одной библиотеки для всех форматов нет, но есть две - XMLUnit и JsonAssert. Так думал я, пока не начал копать тему глубже. И искать, чем же можно проверить yaml. Оказывается, есть «более лучшая» замена JsonAssert, которая:
1) умеет и в json, и в yaml, причём может сравнивать json и yaml. И также сравнивать с Java обьектом
2) умеет все это делать в стиле Assert/Truth, он же method chaining. А это облегчает как написание условий проверки благодаря auto competition в IDE, так и их чтение. А возможно в некоторых случаях позволит отказаться от BDD фреймворка.
3) прозрачно работает с разными источниками данных - строка и файл
Встречайте - ModelAssert https://github.com/webcompere/model-assert
И более подробно https://www.baeldung.com/json-modelassert
Что интересно - автор сам написал статью на baeldung и ссылается на неё в документации.
Ещё важный момент - подчеркивается совместимость библиотеки со Spring MockMvc и Mockito. Возможно даже ради этой поддержки автор и запилил совместимость с Hamcrest. И последнее - отдельно продумано тестирование json с guid. Во-первых можно игнорировать различия конкретных значений uuid (они могут генерироваться в каждом тесте), во-вторых легко написать проверку формата uuid.
А что же XML - вот хорошая статья по XMLUnit https://www.baeldung.com/xmlunit2
Он может примерно то же самое, но без method chaining. Но зато с валидацией по схеме (xsd). Что кстати неплохо характеризует отличия в подходах к работе с XML и json)
#unittests #rare_test_libs #XML #json #yaml
Продолжим про тестовые библиотеки. Достаточно часто возникает задача проверить в тесте структурированные текстовые данные. Я про XML, json и yaml как самые распространённые варианты. XML первым указан по старшинству, а не распространённости) И он пока ещё жив.
Зачем для этого нужно специализированная библиотека:
1) текст может отличаться формированием - пробелами и переносами строк. Иногда это важно при сравнении, но часто нужно проигнорировать
2) могут быть «лишние» тэги/атрибуты - которые не должны участвовать в сравнении
3) может отличаться порядок тэгов
4) может стоят задача проверить только отдельные элементы в дереве, или их количество
Одной библиотеки для всех форматов нет, но есть две - XMLUnit и JsonAssert. Так думал я, пока не начал копать тему глубже. И искать, чем же можно проверить yaml. Оказывается, есть «более лучшая» замена JsonAssert, которая:
1) умеет и в json, и в yaml, причём может сравнивать json и yaml. И также сравнивать с Java обьектом
2) умеет все это делать в стиле Assert/Truth, он же method chaining. А это облегчает как написание условий проверки благодаря auto competition в IDE, так и их чтение. А возможно в некоторых случаях позволит отказаться от BDD фреймворка.
3) прозрачно работает с разными источниками данных - строка и файл
Встречайте - ModelAssert https://github.com/webcompere/model-assert
И более подробно https://www.baeldung.com/json-modelassert
Что интересно - автор сам написал статью на baeldung и ссылается на неё в документации.
Ещё важный момент - подчеркивается совместимость библиотеки со Spring MockMvc и Mockito. Возможно даже ради этой поддержки автор и запилил совместимость с Hamcrest. И последнее - отдельно продумано тестирование json с guid. Во-первых можно игнорировать различия конкретных значений uuid (они могут генерироваться в каждом тесте), во-вторых легко написать проверку формата uuid.
А что же XML - вот хорошая статья по XMLUnit https://www.baeldung.com/xmlunit2
Он может примерно то же самое, но без method chaining. Но зато с валидацией по схеме (xsd). Что кстати неплохо характеризует отличия в подходах к работе с XML и json)
#unittests #rare_test_libs #XML #json #yaml
GitHub
GitHub - webcompere/model-assert: Assertions for data models
Assertions for data models. Contribute to webcompere/model-assert development by creating an account on GitHub.
Всем привет!
Продолжение про тесты, на этот раз интеграционные.
Доминирующий протокол для интеграции сейчас - http(s). REST, GraphQL, разные кастомные реализации. Если мы получаем данные по http - значит где-то есть http client. Он куда-то стучится. Как можно протестировать эту часть интеграционной цепочки?
На первый взгляд, самый простой вариант - развернуть в TestContainers реальный экземпляр сервиса поставщика. Но у нас же микросервисы, а значит он, возможно, вызывает ещё кого-то. И т.д. Даже если не вызывает - ходит в БД.
Поэтому для теста, да и для отладки, нужна заглушка. Кстати, в большинстве случаев это может быть одна и та же заглушка.
Заглушка может быть standalone и встроенная. Я за встроенную, т.к. удобно держать в одном репозитории с кодом и сам код, и все необходимые настройки для его отладки и работы. Кроме стендозависмых конечно.
Что нас нужно от заглушки:
1) возможность старта на произвольном порту и передачи этого порта в код (сервер всегда localhost). Захардкодить порт можно, но тесты запускаются на CI конвейере, в т.ч. на используемом совместно сервере. И вообще не должны зависеть от среды запуска.
2) удобная возможность задавать разные ответы для разных path, например, method chaining
3) учёт параметров в URL
4) возможность задать http код ответа
5) возможность задать http заголовки ответа
6) возможность эмулировать таймаут
Ну и в идеале простая инициализация в тесте, например, с помощью аннотации.
И вот наконец кандидаты.
1) Wiremock. Главные плюсы - большое число возможностей, накопленных за время существования, и возможность работы как во встроенном режиме, так и standalone. Примеры фишек Wiremock - сценарный режим, когда можно задать ответ в зависимости от предыдущего запроса. Встроенный генератор случайных данных в полях ответа. Возможность использовать данные запроса в ответе (templating). Статья как подружить Wiremock с тестами https://www.baeldung.com/spring-webclient-wiremock-integration-testing
2) @RestClientTest - это «магическая» аннотация Spring Boot, автоматически связывающая добавленный в класс теста RestTemplate с сервером заглушки. Т.е. настройку порта делать не нужно. Вот статья по использованию https://www.baeldung.com/restclienttest-in-spring-boot
Если используете Spring и RestTemplate или его наследника RestClient - наверное оптимальный вариант. Для WebClient - асинхронщины и реактивщины - не годится, соответствующий тикет был отклонен командой Spring https://github.com/spring-projects/spring-boot/issues/8404
3) А рекомендует Spring для WebClient использовать MockWebServer. Вот статья https://howtodoinjava.com/java/library/mockwebserver-junit-webclient/
Из интересных фишек я заметил возможность получения информации о последнем запросе, пришедшем на сервер. И простейший сценарный режим, когда можно настроить очередь ответов для ряда последовательных запросов. Настраивать сложнее, чем предыдущие два варианта.
Итого: рекомендую @RestClientTest для синхронного Spring и Wiremock для остального.
#integration_tests #rare_test libs
Продолжение про тесты, на этот раз интеграционные.
Доминирующий протокол для интеграции сейчас - http(s). REST, GraphQL, разные кастомные реализации. Если мы получаем данные по http - значит где-то есть http client. Он куда-то стучится. Как можно протестировать эту часть интеграционной цепочки?
На первый взгляд, самый простой вариант - развернуть в TestContainers реальный экземпляр сервиса поставщика. Но у нас же микросервисы, а значит он, возможно, вызывает ещё кого-то. И т.д. Даже если не вызывает - ходит в БД.
Поэтому для теста, да и для отладки, нужна заглушка. Кстати, в большинстве случаев это может быть одна и та же заглушка.
Заглушка может быть standalone и встроенная. Я за встроенную, т.к. удобно держать в одном репозитории с кодом и сам код, и все необходимые настройки для его отладки и работы. Кроме стендозависмых конечно.
Что нас нужно от заглушки:
1) возможность старта на произвольном порту и передачи этого порта в код (сервер всегда localhost). Захардкодить порт можно, но тесты запускаются на CI конвейере, в т.ч. на используемом совместно сервере. И вообще не должны зависеть от среды запуска.
2) удобная возможность задавать разные ответы для разных path, например, method chaining
3) учёт параметров в URL
4) возможность задать http код ответа
5) возможность задать http заголовки ответа
6) возможность эмулировать таймаут
Ну и в идеале простая инициализация в тесте, например, с помощью аннотации.
И вот наконец кандидаты.
1) Wiremock. Главные плюсы - большое число возможностей, накопленных за время существования, и возможность работы как во встроенном режиме, так и standalone. Примеры фишек Wiremock - сценарный режим, когда можно задать ответ в зависимости от предыдущего запроса. Встроенный генератор случайных данных в полях ответа. Возможность использовать данные запроса в ответе (templating). Статья как подружить Wiremock с тестами https://www.baeldung.com/spring-webclient-wiremock-integration-testing
2) @RestClientTest - это «магическая» аннотация Spring Boot, автоматически связывающая добавленный в класс теста RestTemplate с сервером заглушки. Т.е. настройку порта делать не нужно. Вот статья по использованию https://www.baeldung.com/restclienttest-in-spring-boot
Если используете Spring и RestTemplate или его наследника RestClient - наверное оптимальный вариант. Для WebClient - асинхронщины и реактивщины - не годится, соответствующий тикет был отклонен командой Spring https://github.com/spring-projects/spring-boot/issues/8404
3) А рекомендует Spring для WebClient использовать MockWebServer. Вот статья https://howtodoinjava.com/java/library/mockwebserver-junit-webclient/
Из интересных фишек я заметил возможность получения информации о последнем запросе, пришедшем на сервер. И простейший сценарный режим, когда можно настроить очередь ответов для ряда последовательных запросов. Настраивать сложнее, чем предыдущие два варианта.
Итого: рекомендую @RestClientTest для синхронного Spring и Wiremock для остального.
#integration_tests #rare_test libs
Baeldung
Integration Testing Spring WebClient Using WireMock | Baeldung
Learn how to utilize WireMock API to stub HTTP-based client requests when using WebClient.
Всем привет!
Продолжим тему тестирования http взаимодействий. Кроме http клиента приложение может выставлять API. Этот пост про REST API, как наиболее распространённое. В мире победившего Spring endpoint обычно создаётся с помощью Spring @RestController, но в теории может быть и JAX-RS контроллер или что-то другое, даже «голый» сервлет.
Можно рассмотреть 4 случая.
1) модульное тестирование слоя контроллеров Spring приложения. В этом случае все сервисы в контроллере «мокаются», а Spring context загружается в ограниченном объёме, необходимом для эмуляции контроллера. Это кстати крутая фишка Spring - эмуляция контроллера без реального сетевого взаимодействия для модульных тестов. Ключевые слова - MockMvc и @WebMvcTest. Хорошее описание тут: https://sysout.ru/testirovanie-kontrollerov-s-pomoshhyu-mockmvc/, надо смотреть п. 2
Как я уже писал ранее - встроенные assert-ы MockMvc для json можно при желании заменить на ModelAssert, см. мой пост https://t.me/javaKotlinDevOps/343
2) интеграционное тестирование всех слоёв Spring приложения, но без сети. Вообще говоря, что считать интеграционным тестом - отдельная большая тема, но в большинстве статей, что я видел, такие тесты называются интеграционными. Используется тот же MockMvc, но уже с @SpringBootTest. Основное отличие - загружается весь Spring Context. Поэтому тест медленнее, чем больше приложение, тем медленнее. Если надо - в контексте можно поменять бины для тестового режима через Spring Profiles. Пример такого текста - в статье выше см. п. 1
3) интеграционное тестирование Spring приложения с сетью. Используется @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) и TestRestTemplate. Сервер для тестов запускается на произвольном порту, порт можно получить в тесте. Тесты этого типа ещё медленнее. Когда может быть полезен - нужно приближённое «к бою» тестирование. Или какие фишки http протестировать, типа редиректа. Вот пример https://sysout.ru/testirovanie-spring-boot-prilozheniya-s-testresttemplate/
А вот сравнение всех 3 подходов https://www.baeldung.com/spring-mockmvc-vs-webmvctest
4) у нас не Spring контроллер. Или уже есть опыт использования RestAssured, и он сугубо позитивный) Или нужны какие-то фишки RestAssured. А их много - xsd/json валидация, проверка длительности выполнения, встроенное логирование запроса и ответа, в т.ч. условное - в случае ошибки, использование Groovy для получения данных из тела запроса (!). Также данная библиотека рекомендуется для BDD тестов, т.к придерживается принятой там терминологии Given-When-Then https://en.m.wikipedia.org/wiki/Given-When-Then Для выполнения теста приложение нужно вначале запустить, например, через фазу pre-integration-test цикла сборки Maven. Вот неплохой tutorial https://www.baeldung.com/rest-assured-tutorial
Итого - как всегда в Java есть хорошие инструменты для разных задач.
#unittests #integration_test #rare_test_libs
Продолжим тему тестирования http взаимодействий. Кроме http клиента приложение может выставлять API. Этот пост про REST API, как наиболее распространённое. В мире победившего Spring endpoint обычно создаётся с помощью Spring @RestController, но в теории может быть и JAX-RS контроллер или что-то другое, даже «голый» сервлет.
Можно рассмотреть 4 случая.
1) модульное тестирование слоя контроллеров Spring приложения. В этом случае все сервисы в контроллере «мокаются», а Spring context загружается в ограниченном объёме, необходимом для эмуляции контроллера. Это кстати крутая фишка Spring - эмуляция контроллера без реального сетевого взаимодействия для модульных тестов. Ключевые слова - MockMvc и @WebMvcTest. Хорошее описание тут: https://sysout.ru/testirovanie-kontrollerov-s-pomoshhyu-mockmvc/, надо смотреть п. 2
Как я уже писал ранее - встроенные assert-ы MockMvc для json можно при желании заменить на ModelAssert, см. мой пост https://t.me/javaKotlinDevOps/343
2) интеграционное тестирование всех слоёв Spring приложения, но без сети. Вообще говоря, что считать интеграционным тестом - отдельная большая тема, но в большинстве статей, что я видел, такие тесты называются интеграционными. Используется тот же MockMvc, но уже с @SpringBootTest. Основное отличие - загружается весь Spring Context. Поэтому тест медленнее, чем больше приложение, тем медленнее. Если надо - в контексте можно поменять бины для тестового режима через Spring Profiles. Пример такого текста - в статье выше см. п. 1
3) интеграционное тестирование Spring приложения с сетью. Используется @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) и TestRestTemplate. Сервер для тестов запускается на произвольном порту, порт можно получить в тесте. Тесты этого типа ещё медленнее. Когда может быть полезен - нужно приближённое «к бою» тестирование. Или какие фишки http протестировать, типа редиректа. Вот пример https://sysout.ru/testirovanie-spring-boot-prilozheniya-s-testresttemplate/
А вот сравнение всех 3 подходов https://www.baeldung.com/spring-mockmvc-vs-webmvctest
4) у нас не Spring контроллер. Или уже есть опыт использования RestAssured, и он сугубо позитивный) Или нужны какие-то фишки RestAssured. А их много - xsd/json валидация, проверка длительности выполнения, встроенное логирование запроса и ответа, в т.ч. условное - в случае ошибки, использование Groovy для получения данных из тела запроса (!). Также данная библиотека рекомендуется для BDD тестов, т.к придерживается принятой там терминологии Given-When-Then https://en.m.wikipedia.org/wiki/Given-When-Then Для выполнения теста приложение нужно вначале запустить, например, через фазу pre-integration-test цикла сборки Maven. Вот неплохой tutorial https://www.baeldung.com/rest-assured-tutorial
Итого - как всегда в Java есть хорошие инструменты для разных задач.
#unittests #integration_test #rare_test_libs
SYSOUT
Тестирование контроллеров с помощью MockMvc - SYSOUT
Класс MockMvc предназначен для тестирования контроллеров. Он позволяет тестировать контроллеры без запуска http-сервера. То есть при выполнении тестов сетевое соединение не создается. С MockMvc можно писать как интеграционные тесты, так и unit-тесты. Ниже…
Всем привет!
Небольшое дополнение про Given When Then из предыдущего поста. Данная формулировка пошла из BDD тестирования - Behavior driven development. BDD - это приемочное тестирование. Но в модульных (юнит) тестах существует аналогичная концепция - AAA - Arrange - Act - Assert. Суть та же - тест делится на 3 этапа: подготовка данных - вызов тестируемого метода - проверка результата.
Обычно эти три части в тесте разделяются пустой строкой для читаемости. В случае RestAssured и method chainig так не выйдет, но стоит разделить этапы переводом на новую строку. Arrange опционален, Act и Assert - обязательны. Act и Assert стоит разделить, даже если тянется рука сразу проверить результат вызова метода.
#unittests
Небольшое дополнение про Given When Then из предыдущего поста. Данная формулировка пошла из BDD тестирования - Behavior driven development. BDD - это приемочное тестирование. Но в модульных (юнит) тестах существует аналогичная концепция - AAA - Arrange - Act - Assert. Суть та же - тест делится на 3 этапа: подготовка данных - вызов тестируемого метода - проверка результата.
Обычно эти три части в тесте разделяются пустой строкой для читаемости. В случае RestAssured и method chainig так не выйдет, но стоит разделить этапы переводом на новую строку. Arrange опционален, Act и Assert - обязательны. Act и Assert стоит разделить, даже если тянется рука сразу проверить результат вызова метода.
#unittests
Всем привет!
Есть такое известное правило - DRY - Don't Repeat Yourself. Оно касается кода, оно касается и настроек. Окей, задали мы настройки в одном месте - например, в корневом pom файле или build.gradle(.kts). Как пробросить их во все необходимые файлы при сборке? Этот процесс называется property expansion. К слову - в Maven есть понятие resource filtering. Это нечто большее - проход по всем ресурсным файлам, их фильтрация и кастомизация. Но обычно как раз таки используется для property expansion. Так вот, нашел неплохую статью как сделать это в Maven и Gradle https://www.baeldung.com/spring-boot-auto-property-expansion Что интересно - решение Maven выглядит более продуманным.
#gradle #maven #buildtool
Есть такое известное правило - DRY - Don't Repeat Yourself. Оно касается кода, оно касается и настроек. Окей, задали мы настройки в одном месте - например, в корневом pom файле или build.gradle(.kts). Как пробросить их во все необходимые файлы при сборке? Этот процесс называется property expansion. К слову - в Maven есть понятие resource filtering. Это нечто большее - проход по всем ресурсным файлам, их фильтрация и кастомизация. Но обычно как раз таки используется для property expansion. Так вот, нашел неплохую статью как сделать это в Maven и Gradle https://www.baeldung.com/spring-boot-auto-property-expansion Что интересно - решение Maven выглядит более продуманным.
#gradle #maven #buildtool
Baeldung
Automatic Property Expansion with Spring Boot | Baeldung
Learn about the property expansion mechanism provided by Spring through Maven and Gradle build methods.
Всем привет!
Давно не писал про Kotlin, а в названии канала он есть на почетном втором месте) Исправляюсь.
Основная фишка Kotlin - это упрощение написания и чтения кода за счет упрощения языка. В чем упрощение: все типы - объектные, функция всегда возвращает результат, нет неявных преобразований, нет проверяемых исключений, некоторые стандартные паттерны (синглтон, делегат) стали частью языка - не нужно изобретать велосипед. Возможность переопределения операций и полноценные функциональные типы - на самом деле тоже. Операция - краткий общеупотребительный вариант метода, функцию можно передавать как объект не создавая для этого объект.
Но как всегда есть нюансы.
Вот например inline методы и связанный с ним reified https://www.baeldung.com/kotlin/reified-functions
При беглом знакомстве возникают 2 вопроса:
1) разработчики Kotlin загрязняют язык, ведь компилятор, а скорее JVM, сами справятся с inline?
2) Kotlin хакнул type erasure для generic?
Ответ на оба вопроса - нет.
И есть отличная статья на эту тему https://habr.com/ru/articles/775120/ Автора знаю лично, рекомендую почитать эту и другие его статьи про Kotlin.
Для ленивых ))) ответы:
1) inline нужен только для методов с параметрами функционального типа, чтобы избежать обвертывания функции в объект. Java компилятор не умеет работать с функциональными типами, увы
2) reified не нарушает спецификации Java, компилятор Kotlin лишь сохраняет тип там, где он его знает, и это касается только inline методов
И про простоту Kotlin в целом и сложность inline. Как выглядит процесс со стороны:
1) у нас полноценные функциональные типы
2) в коде их будет много
3) Java не умеет с ними работать
4) сделаем inline, чтобы не снизить производительность при работе с такими типами
5) появляются баги из-за inline, приходится вводить ключевые слова noinline и crossinline. Подробнее об этом есть в статье выше.
6) кто-то просит: раз при inline мы знаем исходный тип generic - давайте дадим возможность работы с ним, появляется reified
7) возникают новые баги, их фиксят
...
Процесс вымышленный, возможно, в реальности было по-другому. Я хотел подчеркнуть вот что: одна фича тянет за собой другую, другая - несколько особых случаев. И все это усложняет язык, хотя цель была противоположная.
P.S. Ну и да, получается, во всем виновата Java)
#kotlin #java
Давно не писал про Kotlin, а в названии канала он есть на почетном втором месте) Исправляюсь.
Основная фишка Kotlin - это упрощение написания и чтения кода за счет упрощения языка. В чем упрощение: все типы - объектные, функция всегда возвращает результат, нет неявных преобразований, нет проверяемых исключений, некоторые стандартные паттерны (синглтон, делегат) стали частью языка - не нужно изобретать велосипед. Возможность переопределения операций и полноценные функциональные типы - на самом деле тоже. Операция - краткий общеупотребительный вариант метода, функцию можно передавать как объект не создавая для этого объект.
Но как всегда есть нюансы.
Вот например inline методы и связанный с ним reified https://www.baeldung.com/kotlin/reified-functions
При беглом знакомстве возникают 2 вопроса:
1) разработчики Kotlin загрязняют язык, ведь компилятор, а скорее JVM, сами справятся с inline?
2) Kotlin хакнул type erasure для generic?
Ответ на оба вопроса - нет.
И есть отличная статья на эту тему https://habr.com/ru/articles/775120/ Автора знаю лично, рекомендую почитать эту и другие его статьи про Kotlin.
Для ленивых ))) ответы:
1) inline нужен только для методов с параметрами функционального типа, чтобы избежать обвертывания функции в объект. Java компилятор не умеет работать с функциональными типами, увы
2) reified не нарушает спецификации Java, компилятор Kotlin лишь сохраняет тип там, где он его знает, и это касается только inline методов
И про простоту Kotlin в целом и сложность inline. Как выглядит процесс со стороны:
1) у нас полноценные функциональные типы
2) в коде их будет много
3) Java не умеет с ними работать
4) сделаем inline, чтобы не снизить производительность при работе с такими типами
5) появляются баги из-за inline, приходится вводить ключевые слова noinline и crossinline. Подробнее об этом есть в статье выше.
6) кто-то просит: раз при inline мы знаем исходный тип generic - давайте дадим возможность работы с ним, появляется reified
7) возникают новые баги, их фиксят
...
Процесс вымышленный, возможно, в реальности было по-другому. Я хотел подчеркнуть вот что: одна фича тянет за собой другую, другая - несколько особых случаев. И все это усложняет язык, хотя цель была противоположная.
P.S. Ну и да, получается, во всем виновата Java)
#kotlin #java
Baeldung on Kotlin
Reified Functions in Kotlin | Baeldung on Kotlin
Learn how to use reified functions in Kotlin
Всем привет!
Одна из моих любимых тем: разработка - искусство компромиссов. Поиск по тэгам #dev_compromises и #arch_compromises. Следствие этого подхода, принцип, который я бы назвал - "не все так однозначно".
Вопрос - как вы относитесь к рефлексии в Java?
Досрочный ответ: рефлексия - это плохо, лучше не использовать. Если дошло до рефлексии - значит в архитектуре проблема.
Чтобы лучше разобраться в теме надо ответить на вопрос: а почему плохо?
Ответа два:
1) рефлексия позволяет нарушить принципы ООП и, следовательно, архитектуру приложения. Автор скрыл внутренности класса через private, а мы туда лезем своими "грязными руками")))
2) снижение производительности. Тут частично работает тот факт, что делаются лишние вызовы кода. Но самое главное - JIT компилятор плохо умеет оптимизировать такой код, т.к. он слишком динамический. Изменится может сам класс, который приходит на вход метода с рефлексией
Окей, инкапсуляция нарушается, код работает медленно. Не используем?
А что с поиском аннотаций по коду? Не своих - до них мы еще дойдем - чужих, чтобы получить некие метаданные об объекте. Большинство вариантов вот тут основано на рефлексии https://www.baeldung.com/java-scan-annotations-runtime
Или у нас есть аннотации, созданные с помощью Spring AOP - это проще, чем AspectJ, если у вас используется Spring. А Spring AOP использует динамические прокси, создаваемые в runtime https://www.baeldung.com/spring-aop-vs-aspectj А с помощью чего создается прокси в runtime - правильно, рефлексии.
Да что там AOP - создание бинов из @Configuration - это тоже вызов методов @Bean через рефлексию.
Почему же рефлексию используют и предлагают к использованию, если это такая проблемная технология?
Вернемся к двум ее недостаткам:
1) не надо использовать рефлексию для вызова private методов или доступа к private полям. Если такая задача встала - у вас в самом деле проблемы с архитектурой
2) не надо использовать рефлексию часто и при этом в высоконагруженных приложениях. Тот же Spring использует рефлексию только при старте приложения для инициализации прокси и бинов. И к слову в т.ч. и поэтому старт Spring приложения может быть долгим, и люди с этим борются, см. мой цикл статей про ускорение старта #java_start_boost Более того, разработчикам Spring для поддержки native image пришлось серьезно допиливать его в т.ч. из-за динамических прокси и @Configuration https://docs.spring.io/spring-boot/reference/packaging/native-image/introducing-graalvm-native-images.html
Итого: рефлексию стоит рассматривать как возможность получить метаданные о классе. Помня при этом о производительности.
И если вопрос упирается в производительность - всегда есть альтернативы рефлексии. Это работа с байт-кодом не в runtime:
1) compile time (свой компилятор, см. статью про AspectJ)
2) post-compile time (свой плагин для сборки, см. Jandex для поиска аннотаций https://smallrye.io/jandex/jandex/3.2.2/index.html)
3) load-time (свой агент+classloader, см. статью про AspectJ)
Все варианты сложнее в реализации и подключении к проекту, зато вносят минимальное влияние в runtime.
P.S. Да, если при упоминании о динамических прокси вы вспомнили про задачку с собесов о вложенном @Transactional - это оно. И ответ на этот вопрос не так очевиден https://habr.com/ru/articles/347752/
#java #reflection #dev_compromises
Одна из моих любимых тем: разработка - искусство компромиссов. Поиск по тэгам #dev_compromises и #arch_compromises. Следствие этого подхода, принцип, который я бы назвал - "не все так однозначно".
Вопрос - как вы относитесь к рефлексии в Java?
Досрочный ответ: рефлексия - это плохо, лучше не использовать. Если дошло до рефлексии - значит в архитектуре проблема.
Чтобы лучше разобраться в теме надо ответить на вопрос: а почему плохо?
Ответа два:
1) рефлексия позволяет нарушить принципы ООП и, следовательно, архитектуру приложения. Автор скрыл внутренности класса через private, а мы туда лезем своими "грязными руками")))
2) снижение производительности. Тут частично работает тот факт, что делаются лишние вызовы кода. Но самое главное - JIT компилятор плохо умеет оптимизировать такой код, т.к. он слишком динамический. Изменится может сам класс, который приходит на вход метода с рефлексией
Окей, инкапсуляция нарушается, код работает медленно. Не используем?
А что с поиском аннотаций по коду? Не своих - до них мы еще дойдем - чужих, чтобы получить некие метаданные об объекте. Большинство вариантов вот тут основано на рефлексии https://www.baeldung.com/java-scan-annotations-runtime
Или у нас есть аннотации, созданные с помощью Spring AOP - это проще, чем AspectJ, если у вас используется Spring. А Spring AOP использует динамические прокси, создаваемые в runtime https://www.baeldung.com/spring-aop-vs-aspectj А с помощью чего создается прокси в runtime - правильно, рефлексии.
Да что там AOP - создание бинов из @Configuration - это тоже вызов методов @Bean через рефлексию.
Почему же рефлексию используют и предлагают к использованию, если это такая проблемная технология?
Вернемся к двум ее недостаткам:
1) не надо использовать рефлексию для вызова private методов или доступа к private полям. Если такая задача встала - у вас в самом деле проблемы с архитектурой
2) не надо использовать рефлексию часто и при этом в высоконагруженных приложениях. Тот же Spring использует рефлексию только при старте приложения для инициализации прокси и бинов. И к слову в т.ч. и поэтому старт Spring приложения может быть долгим, и люди с этим борются, см. мой цикл статей про ускорение старта #java_start_boost Более того, разработчикам Spring для поддержки native image пришлось серьезно допиливать его в т.ч. из-за динамических прокси и @Configuration https://docs.spring.io/spring-boot/reference/packaging/native-image/introducing-graalvm-native-images.html
Итого: рефлексию стоит рассматривать как возможность получить метаданные о классе. Помня при этом о производительности.
И если вопрос упирается в производительность - всегда есть альтернативы рефлексии. Это работа с байт-кодом не в runtime:
1) compile time (свой компилятор, см. статью про AspectJ)
2) post-compile time (свой плагин для сборки, см. Jandex для поиска аннотаций https://smallrye.io/jandex/jandex/3.2.2/index.html)
3) load-time (свой агент+classloader, см. статью про AspectJ)
Все варианты сложнее в реализации и подключении к проекту, зато вносят минимальное влияние в runtime.
P.S. Да, если при упоминании о динамических прокси вы вспомнили про задачку с собесов о вложенном @Transactional - это оно. И ответ на этот вопрос не так очевиден https://habr.com/ru/articles/347752/
#java #reflection #dev_compromises
Baeldung
Scanning Java Annotations at Runtime | Baeldung
Learn about scanning Java annotations at runtime.