Всем привет!
Постов долгое время не было, причина типичная - много работы. Вообще не помню времени, когда ее было мало((( И были ли вообще такие времена?)
Хотел бы поднять сегодня такую важную тему как взаимодействие разработчиков и сопровождения.
Для начала одна общеизвестная информация - разработчики и сопровождение исходя из своих задач обречены на противостояние.
Задача разработчиков - менять приложение, задача сопровождения - обеспечивать его работоспособность. А как известно: работает - не трогай) Любое изменение потенциальный источник проблем.
Отсюда часто следует одна крайность - сопровождение максимально критично относится к любым изменениям, разработка "виновна" по умолчанию, требуется строгое соблюдение регламентов, любая нестандартная просьба разработки встречается "в штыки".
Почему это плохо?
Сейчас основная методология разработки - это Agile в разных вариациях. Один из ключевых моментов в Agile - это команда, командная ответственность, гибкие решения в команде. А сопровождение в описываемом кейсе выступает внешним "врагом" - блокирует инициативы команды, замедляет скорость выпуска новых версий. А высокая частота выхода в ПРОМ - еще одна важная часть Agile.
С таким кейсом я, увы, сталкивался и наблюдал его губительный для команды эффект. Часто свои требования сопровождение объясняет требованиями надежности. Хорошее ли это объяснение - зависит от деталей. Если объяснение звучит как-то так - это снизит надежность, т.к. ... и идет описание причин - то да, хорошее.
Если слово надежность произносится, а никаких деталей не приводится - это признак того, что сопровождение боится изменений и не хочет развиваться.
Есть и другая крайность - сопровождение "согласно на все") Не выставляет никаких требований, принимает любые дистрибутивы. Кейс более редкий. Чем это плохо - разработчики опять же исходя из своих основных задач редко думают о том, как их код будет сопровождаться. Обычно на разработку времени хватает впритык.
Какой выход из данной ситуации?
Выставлять требования со стороны сопровождения.
Требования зависят от компании, отрасли, приложения, числа пользователей и много чего.
Но базовые требования могут быть такими:
1) список метрик, позволяющих отслеживать работоспособность
2) требования к логам - где и в каком объеме. Сюда же я бы добавил требования к фильтрации логов, с важным дополнением - возможность фильтрации зависит как от разработчиков бизнес-приложения, так и от разработчиков системы просмотра логов
3) требования к трассировке (tracing) - особенно важно если мы имеем дело с микросервисами
4) наличие инструкции для сопровождения в случае, если установка релиза требует ручных действий
5) наличие сценария отката на предыдущую версию. Это может быть выключение feature toggle или номер версии для отката. Самое важное - сама возможность отката. Это тоже требование, его нужно или соблюдать, или если это невозможно, например, в случае необратимых изменений в БД - составлять план действий на случай неудачной раскатки
6) фиксирование таймаутов внешних вызовов: я уже писал что бесконечные таймауты - одна из основных причин падения приложения
7) требования по UI для ручного разбора ошибок, если все предыдущие требования не помогли)
Почему я говорю "могут быть такие требования" - я все же изначально разработчик, поэтому имею некие предустановки и не вижу полной картины. Если есть возражения и дополнения - возражайте и дополняйте)
#dev #ops
Постов долгое время не было, причина типичная - много работы. Вообще не помню времени, когда ее было мало((( И были ли вообще такие времена?)
Хотел бы поднять сегодня такую важную тему как взаимодействие разработчиков и сопровождения.
Для начала одна общеизвестная информация - разработчики и сопровождение исходя из своих задач обречены на противостояние.
Задача разработчиков - менять приложение, задача сопровождения - обеспечивать его работоспособность. А как известно: работает - не трогай) Любое изменение потенциальный источник проблем.
Отсюда часто следует одна крайность - сопровождение максимально критично относится к любым изменениям, разработка "виновна" по умолчанию, требуется строгое соблюдение регламентов, любая нестандартная просьба разработки встречается "в штыки".
Почему это плохо?
Сейчас основная методология разработки - это Agile в разных вариациях. Один из ключевых моментов в Agile - это команда, командная ответственность, гибкие решения в команде. А сопровождение в описываемом кейсе выступает внешним "врагом" - блокирует инициативы команды, замедляет скорость выпуска новых версий. А высокая частота выхода в ПРОМ - еще одна важная часть Agile.
С таким кейсом я, увы, сталкивался и наблюдал его губительный для команды эффект. Часто свои требования сопровождение объясняет требованиями надежности. Хорошее ли это объяснение - зависит от деталей. Если объяснение звучит как-то так - это снизит надежность, т.к. ... и идет описание причин - то да, хорошее.
Если слово надежность произносится, а никаких деталей не приводится - это признак того, что сопровождение боится изменений и не хочет развиваться.
Есть и другая крайность - сопровождение "согласно на все") Не выставляет никаких требований, принимает любые дистрибутивы. Кейс более редкий. Чем это плохо - разработчики опять же исходя из своих основных задач редко думают о том, как их код будет сопровождаться. Обычно на разработку времени хватает впритык.
Какой выход из данной ситуации?
Выставлять требования со стороны сопровождения.
Требования зависят от компании, отрасли, приложения, числа пользователей и много чего.
Но базовые требования могут быть такими:
1) список метрик, позволяющих отслеживать работоспособность
2) требования к логам - где и в каком объеме. Сюда же я бы добавил требования к фильтрации логов, с важным дополнением - возможность фильтрации зависит как от разработчиков бизнес-приложения, так и от разработчиков системы просмотра логов
3) требования к трассировке (tracing) - особенно важно если мы имеем дело с микросервисами
4) наличие инструкции для сопровождения в случае, если установка релиза требует ручных действий
5) наличие сценария отката на предыдущую версию. Это может быть выключение feature toggle или номер версии для отката. Самое важное - сама возможность отката. Это тоже требование, его нужно или соблюдать, или если это невозможно, например, в случае необратимых изменений в БД - составлять план действий на случай неудачной раскатки
6) фиксирование таймаутов внешних вызовов: я уже писал что бесконечные таймауты - одна из основных причин падения приложения
7) требования по UI для ручного разбора ошибок, если все предыдущие требования не помогли)
Почему я говорю "могут быть такие требования" - я все же изначально разработчик, поэтому имею некие предустановки и не вижу полной картины. Если есть возражения и дополнения - возражайте и дополняйте)
#dev #ops
Всем привет!
На собеседовании я иногда задаю вопрос: приведите пример нарушения принципа Single responsibility. Или альтернативный вариант - а вот если в методе, к примеру, activateCard мы заодно отбросим метрики или залогируем результат - это нарушение принципа или нет.
На первый взгляд ответ - нет. Метрики и логи - это технический код, не бизнес функционал. Он может понадобиться в любом месте кода. Часто такой функционал реализуют с помощью аспектов, т.к. во-первых - это можно реализовать с помощью аспектов, а во-вторых - это красиво))), т.е. некий синтаксический сахар, улучшающий читаемость кода.
Но можно рассмотреть немного другую ситуацию. Предположим, есть код с математическими вычислениям. Или любой алгоритм. Или логика обработки данных. То, что хорошо реализуется в функциональном стиле - входные данные метода, результат, никаких внешних зависимостей. В нём нет внешних взаимодействий, сохранения в хранилище. Чистая логика. В этом случае логирование и метрики - это уже некая обработка полученного результата. Мы же не просто так выводим что-то в лог - это либо данные для разбора ошибки, либо отслеживание пользовательского пути, сбор статистики, отслеживание времени выполнения кода... Т.е. есть отдельная логика по месту и составу того, что мы логируем. Опять же контекст логирования часто требует инициализации, что добавляет ненужные зависимости в нашу логику. Поэтому такой код лучше поместить на уровень выше.
Итого: бизнес функционал и логирование/метрики - да, "чистая" логика - нет.
#logging #metrics #interview_question #code_design #solid #dev_compromises
На собеседовании я иногда задаю вопрос: приведите пример нарушения принципа Single responsibility. Или альтернативный вариант - а вот если в методе, к примеру, activateCard мы заодно отбросим метрики или залогируем результат - это нарушение принципа или нет.
На первый взгляд ответ - нет. Метрики и логи - это технический код, не бизнес функционал. Он может понадобиться в любом месте кода. Часто такой функционал реализуют с помощью аспектов, т.к. во-первых - это можно реализовать с помощью аспектов, а во-вторых - это красиво))), т.е. некий синтаксический сахар, улучшающий читаемость кода.
Но можно рассмотреть немного другую ситуацию. Предположим, есть код с математическими вычислениям. Или любой алгоритм. Или логика обработки данных. То, что хорошо реализуется в функциональном стиле - входные данные метода, результат, никаких внешних зависимостей. В нём нет внешних взаимодействий, сохранения в хранилище. Чистая логика. В этом случае логирование и метрики - это уже некая обработка полученного результата. Мы же не просто так выводим что-то в лог - это либо данные для разбора ошибки, либо отслеживание пользовательского пути, сбор статистики, отслеживание времени выполнения кода... Т.е. есть отдельная логика по месту и составу того, что мы логируем. Опять же контекст логирования часто требует инициализации, что добавляет ненужные зависимости в нашу логику. Поэтому такой код лучше поместить на уровень выше.
Итого: бизнес функционал и логирование/метрики - да, "чистая" логика - нет.
#logging #metrics #interview_question #code_design #solid #dev_compromises
Всем привет!
Может ли API с широким функционалом стать проблемой? Имея несколько реализаций от разных производителей ПО, являясь эталонной реализацией паттернов интеграции https://www.enterpriseintegrationpatterns.com/ при этом быть хуже конкретного продукта с ограниченым набором функционала?
Как можно догадаться из вопроса - ответ: да. Я про JMS vs Kafka.
JMS - это API из состава Java EE (сейчас Jakarta EE). Есть несколько реализаций: практически у каждого сервера приложений есть свой JMS - IBM, Oracle, JBoss, SAP, есть и Open source решения - ActiveMQ, Artemis MQ и другие.
Что есть в JMS? Стандарт широкий: есть очереди (точка-точка, ака P2P) и топики (подписка, ака PubSub), опциональная персистентность и транзационность, возможность настраиваемой маршрутизации и конвертации сообщений. И с security все хорошо.
У Kafka же только топики, нет продвинутой маршрутизации, трансформации, персистентность постоянная, транзакционности нету, гарантии однократной вычитки должен обеспечивать клиент. Да и вендор один. Но справедливости ради vendor lock нет, т.к продукт open source, за деньги только поддержка.
При этом Kafka успешно отвоевывает долю рынка. В чем же дело?
Секрет Kafka в том, что она выпустила достаточно простой, очень быстрый open source продукт, достаточный для большого числа клиентов. Этим нивелируется преимущество JMS в возможности выбора реализации. Причем Kafka быстрая с включённой по умолчанию персистентностью, а значит и высокой надёжностью. По скорости однозначно бьет все реализации JMS. Про то, как удалось добиться такого результата, я писал тут https://t.me/javaKotlinDevOps/91
В чем проблемы JMS:
попытка объять необъятное в API = переусложнение,
много вендорской специфики, которая может помешать смену реализации,
слишком большая роль брокера - все возможности по маршрутизации и трансформации не бесплатны по производительности, и кроме того ведут к тому, что обычная очередь превращается в Enterprise Service Bus, а у этой концепции есть свои минусы.
Я не хочу сказать, что JMS можно выкидывать, а лишь пишу почему Kafka удалось ее так сильно потеснить. Если вам нужно взаимодействие точка-точка и нет больших объёмов данных - JMS вполне подойдёт.
#kafka #jms #comparison
Может ли API с широким функционалом стать проблемой? Имея несколько реализаций от разных производителей ПО, являясь эталонной реализацией паттернов интеграции https://www.enterpriseintegrationpatterns.com/ при этом быть хуже конкретного продукта с ограниченым набором функционала?
Как можно догадаться из вопроса - ответ: да. Я про JMS vs Kafka.
JMS - это API из состава Java EE (сейчас Jakarta EE). Есть несколько реализаций: практически у каждого сервера приложений есть свой JMS - IBM, Oracle, JBoss, SAP, есть и Open source решения - ActiveMQ, Artemis MQ и другие.
Что есть в JMS? Стандарт широкий: есть очереди (точка-точка, ака P2P) и топики (подписка, ака PubSub), опциональная персистентность и транзационность, возможность настраиваемой маршрутизации и конвертации сообщений. И с security все хорошо.
У Kafka же только топики, нет продвинутой маршрутизации, трансформации, персистентность постоянная, транзакционности нету, гарантии однократной вычитки должен обеспечивать клиент. Да и вендор один. Но справедливости ради vendor lock нет, т.к продукт open source, за деньги только поддержка.
При этом Kafka успешно отвоевывает долю рынка. В чем же дело?
Секрет Kafka в том, что она выпустила достаточно простой, очень быстрый open source продукт, достаточный для большого числа клиентов. Этим нивелируется преимущество JMS в возможности выбора реализации. Причем Kafka быстрая с включённой по умолчанию персистентностью, а значит и высокой надёжностью. По скорости однозначно бьет все реализации JMS. Про то, как удалось добиться такого результата, я писал тут https://t.me/javaKotlinDevOps/91
В чем проблемы JMS:
попытка объять необъятное в API = переусложнение,
много вендорской специфики, которая может помешать смену реализации,
слишком большая роль брокера - все возможности по маршрутизации и трансформации не бесплатны по производительности, и кроме того ведут к тому, что обычная очередь превращается в Enterprise Service Bus, а у этой концепции есть свои минусы.
Я не хочу сказать, что JMS можно выкидывать, а лишь пишу почему Kafka удалось ее так сильно потеснить. Если вам нужно взаимодействие точка-точка и нет больших объёмов данных - JMS вполне подойдёт.
#kafka #jms #comparison
Enterprise Integration Patterns
A comprehensive pattern language for the robust design of asynchronous messaging solutions. The patterns stay product neutral and emphasize design trade-offs over specific technology choices.
Всем привет!
Я уже писал о важности рефакторинга.
Но как оценить, что рефакторинг достиг своих целей?
Можно экспертно. Но не всегда этот вариант годится для обоснования времени на рефакторинг у бизнеса.
Можно ли как-то подтвердить эффект цифрами?
Самый простой вариант - если проблема в производительности. Тогда изменяем TPS - transaction per second - до и после и демонстрируем эффект.
А если проблема в сложности кода как это чаще всего бывает?
Тогда на помощь могут прийти следующие метрики:
- цикломатическая сложность кода и другие похожие метрики https://www.tiobe.com/knowledge/article/demystifying-code-complexity/ После рефакторинга сложность должна снизиться, при этом в процессе может временно повышаться. А стандартные метрики хороши тем, что уже есть утилиты для их подсчёта. Например, Checkstyle https://checkstyle.org/checks/metrics/cyclomaticcomplexity.html или Sonarqube https://habr.com/ru/articles/565652/ Также благодаря тому, что эти метрики широко известны в узких кругах разработчиков )) их проще объяснить бизнесу. Или пусть изучают формулу, или верят на слово разработчикам)
- если сложность кода по каким-то причинам не подходит - можно рассмотреть среднее число строк в классе или методе. После рефакторинга это число также должно снижаться,
- в некоторых случаях может даже подойти абсолютное число строк кода. Если приложение «раздуто», то результатом рефакторинга станет уменьшение размера кодовой базы.
- число TODO в коде. Каждая TODO - потенциальный техдолг.
- число длинных комментариев в коде. Если код самодокументирующийся - с говорящими названиями методов и классов - то длинный комментарий можно рассматривать как аналог TODO
- скорость вникания в код сервиса для новых разработчиков. Изменить достаточно трудоёмко, но метрика хорошая
- число ошибок ПРОМ, связанных с изменяемым кодом. Если их много - значит с кодом что-то не так
- постоянно увеличивающееся или стабильно большое время разработки новых фичей. Например, по сравнению с временем в начале жизненного цикла сервиса. Сравнивать с другими командами и сервисам часто не корректно.
Отдельно я бы рассмотрел случай, когда новая фича не вписывается в существующую архитектуру. Может получится, что просто сделать ее будет быстрее, чем отрефакторить и сделать без техдолга. Эффект может проявится на следующих фичах, но априори это оценить сложно
#java refactoring #metrics
Я уже писал о важности рефакторинга.
Но как оценить, что рефакторинг достиг своих целей?
Можно экспертно. Но не всегда этот вариант годится для обоснования времени на рефакторинг у бизнеса.
Можно ли как-то подтвердить эффект цифрами?
Самый простой вариант - если проблема в производительности. Тогда изменяем TPS - transaction per second - до и после и демонстрируем эффект.
А если проблема в сложности кода как это чаще всего бывает?
Тогда на помощь могут прийти следующие метрики:
- цикломатическая сложность кода и другие похожие метрики https://www.tiobe.com/knowledge/article/demystifying-code-complexity/ После рефакторинга сложность должна снизиться, при этом в процессе может временно повышаться. А стандартные метрики хороши тем, что уже есть утилиты для их подсчёта. Например, Checkstyle https://checkstyle.org/checks/metrics/cyclomaticcomplexity.html или Sonarqube https://habr.com/ru/articles/565652/ Также благодаря тому, что эти метрики широко известны в узких кругах разработчиков )) их проще объяснить бизнесу. Или пусть изучают формулу, или верят на слово разработчикам)
- если сложность кода по каким-то причинам не подходит - можно рассмотреть среднее число строк в классе или методе. После рефакторинга это число также должно снижаться,
- в некоторых случаях может даже подойти абсолютное число строк кода. Если приложение «раздуто», то результатом рефакторинга станет уменьшение размера кодовой базы.
- число TODO в коде. Каждая TODO - потенциальный техдолг.
- число длинных комментариев в коде. Если код самодокументирующийся - с говорящими названиями методов и классов - то длинный комментарий можно рассматривать как аналог TODO
- скорость вникания в код сервиса для новых разработчиков. Изменить достаточно трудоёмко, но метрика хорошая
- число ошибок ПРОМ, связанных с изменяемым кодом. Если их много - значит с кодом что-то не так
- постоянно увеличивающееся или стабильно большое время разработки новых фичей. Например, по сравнению с временем в начале жизненного цикла сервиса. Сравнивать с другими командами и сервисам часто не корректно.
Отдельно я бы рассмотрел случай, когда новая фича не вписывается в существующую архитектуру. Может получится, что просто сделать ее будет быстрее, чем отрефакторить и сделать без техдолга. Эффект может проявится на следующих фичах, но априори это оценить сложно
#java refactoring #metrics
Всем привет!
Продолжая тему рефакторинга. Основное предусловие для начала рефакторинга - это наличие хорошего тестового покрытия. Т.к. мы не меняем бизнес функционал, а улучшаем код либо для повышения производительности, либо для его упрощения. Но при этом нужно гарантировать, что бизнес функционал не сломался, т.е. не появились регрессионные баги. Ведь рефакторинг, в отличие от новой фичи, может затронуть все приложение. Соответственно, баги могут появиться в любом месте, и без тестового покрытия - это большие риски.
Можно рассмотреть похожий кейс. У нас есть монолит, мы хотим распилить его на микросервисы. Это тоже своего рода рефакторинг, только на уровне архитектурном уровне. И тоже аналогичное условие для его начала - наличие достаточного набора тестов. В данном случае повышается важность интеграционных тестов.
Важный момент: в процессе подготовки к разбиению монолита или серьёзному рефакторингу может возникнуть вопрос-предложение - а давайте все выкинем и напишем заново. Так вот - одним из базовых критериев для ответа на этот вопрос также является покрытие тестами. Очевидно, не единственным, но важным. Другие критерии - объем техдолга, соответствие текущей архитектуры и целевой.
Еще кейс - разработчик «боится» рефакторить код, т.к. он слишком сложный или затрагивает слишком много зависимостей. С тестами решиться на рефакторинг намного проще.
Вывод простой - пишите тесты, это страховка при рефакторинге)
#refactoring #unittests #microservices
Продолжая тему рефакторинга. Основное предусловие для начала рефакторинга - это наличие хорошего тестового покрытия. Т.к. мы не меняем бизнес функционал, а улучшаем код либо для повышения производительности, либо для его упрощения. Но при этом нужно гарантировать, что бизнес функционал не сломался, т.е. не появились регрессионные баги. Ведь рефакторинг, в отличие от новой фичи, может затронуть все приложение. Соответственно, баги могут появиться в любом месте, и без тестового покрытия - это большие риски.
Можно рассмотреть похожий кейс. У нас есть монолит, мы хотим распилить его на микросервисы. Это тоже своего рода рефакторинг, только на уровне архитектурном уровне. И тоже аналогичное условие для его начала - наличие достаточного набора тестов. В данном случае повышается важность интеграционных тестов.
Важный момент: в процессе подготовки к разбиению монолита или серьёзному рефакторингу может возникнуть вопрос-предложение - а давайте все выкинем и напишем заново. Так вот - одним из базовых критериев для ответа на этот вопрос также является покрытие тестами. Очевидно, не единственным, но важным. Другие критерии - объем техдолга, соответствие текущей архитектуры и целевой.
Еще кейс - разработчик «боится» рефакторить код, т.к. он слишком сложный или затрагивает слишком много зависимостей. С тестами решиться на рефакторинг намного проще.
Вывод простой - пишите тесты, это страховка при рефакторинге)
#refactoring #unittests #microservices
Всем привет!
Я упоминал в посте про JMS vs Kafka про ESB - Enterprise Service Bus. Она же Корпоративная Сервисная Шина.
Какие плюсы и минусы данного решения?
Плюсов я вижу три:
1) унификация API в пределах компании
2) единая точка мониторинга и контроля всех интеграций
3) больше возможностей для переиспользования уже существующих API
Минусы такие:
1) т.к. ESB - это отдельная система, то ее разрабатывает как правило отдельная команда, которая быстро становится узким местом. Особенно при внедрении микросервисной архитектуры и резком увеличении числа интеграций
2) ESB как правило вносит дополнительные задержки, что особенно критично при синхронном взаимодействии
3) как правило ESB предлагают коммерческие компании, что приводит к vendor lock. Слезть с такого решения будет сложно
4) неочевидная штука - с одной стороны команда ESB унифицирует все API. Но с другой - API становятся перегруженными. Там будут какие-то стандартизированные для всех поля, общие базовые типы, которые во многих случаях будут избыточными
5) также ESB из-за стандартизации затрудняет развитие API. Т.к. унификация, а кроме того больше команд участвует в согласовании - три вместо двух
Вывод: на данном этапе развития ПО идея ESB выглядит избыточной.
Но что же с плюсами, как добиться того же результата с API точка-точка и микросервисной архитектурой?
1) унификация вещь полезная, главное чтобы она не была избыточной. Архитектор может выставить требования по API, DevOps - встроить их проверку в pipeline.
2) единая точка контроля - в случае облачной среды такой точкой может быть Istio или k8s. Либо ставить proxy на границах сред.
3) для переиспользования можно использовать каталог API. Да и не всегда переиспользование полезно, см. выше про избыточное API. Также отдельное API для каждого потребителя позволяет лучше контролировать доступ к данным
#api #esb
Я упоминал в посте про JMS vs Kafka про ESB - Enterprise Service Bus. Она же Корпоративная Сервисная Шина.
Какие плюсы и минусы данного решения?
Плюсов я вижу три:
1) унификация API в пределах компании
2) единая точка мониторинга и контроля всех интеграций
3) больше возможностей для переиспользования уже существующих API
Минусы такие:
1) т.к. ESB - это отдельная система, то ее разрабатывает как правило отдельная команда, которая быстро становится узким местом. Особенно при внедрении микросервисной архитектуры и резком увеличении числа интеграций
2) ESB как правило вносит дополнительные задержки, что особенно критично при синхронном взаимодействии
3) как правило ESB предлагают коммерческие компании, что приводит к vendor lock. Слезть с такого решения будет сложно
4) неочевидная штука - с одной стороны команда ESB унифицирует все API. Но с другой - API становятся перегруженными. Там будут какие-то стандартизированные для всех поля, общие базовые типы, которые во многих случаях будут избыточными
5) также ESB из-за стандартизации затрудняет развитие API. Т.к. унификация, а кроме того больше команд участвует в согласовании - три вместо двух
Вывод: на данном этапе развития ПО идея ESB выглядит избыточной.
Но что же с плюсами, как добиться того же результата с API точка-точка и микросервисной архитектурой?
1) унификация вещь полезная, главное чтобы она не была избыточной. Архитектор может выставить требования по API, DevOps - встроить их проверку в pipeline.
2) единая точка контроля - в случае облачной среды такой точкой может быть Istio или k8s. Либо ставить proxy на границах сред.
3) для переиспользования можно использовать каталог API. Да и не всегда переиспользование полезно, см. выше про избыточное API. Также отдельное API для каждого потребителя позволяет лучше контролировать доступ к данным
#api #esb
Всем привет!
Рекомендую далеко не новую, но интересную статья от всем известного Тагира Валеева про редкие фичи Java https://habr.com/ru/articles/253787/
#java
Рекомендую далеко не новую, но интересную статья от всем известного Тагира Валеева про редкие фичи Java https://habr.com/ru/articles/253787/
#java
Хабр
10 вещей, которых вы не знали о Java
Итак, вы работаете на Java с самого её появления? Вы помните те дни, когда она называлась «Oak», когда про ООП говорили на каждом углу, когда сиплюсплюсники думали, что у Java нет шансов, а апплеты...
Всем привет!
Ситуация: новый разработчик приходит в команды, начинает разбираться с кодом, pipeline, архитектурой, у него возникают вопросы. Когда стоит подойти к более опытному товарищу - тимлиду, техлиду, senior-у - а в каких случаях разобраться самому?
Однозначного ответа нет. Но есть ряд условий.
Когда стоит разобраться самому?
1) проблема не относится к специфике компании. Т.е. это что-то, что скорее всего можно нагуглить на stackoverflow или хабре. По своему опыту скажу, что такие вопросы очень раздражают, уметь гуглить должны все) Далее я рассматриваю случаи, когда вопрос касается специфики компании. Люди, которые спрашивают у коллег: объясни на пальцах как устроены сервлеты - могут стать героями локальных мемов (из собственного опыта)
2) примерно понятно где искать ответ. Если искать лень - для этого существуют чаты разработчиков. Там отвечает либо те, у кого в данный момент есть свободное время, либо те, кто настроен на помощь коллегам. А возможно даже "специально обученные" для ответов на вопросы по разработке люди
3) известно, что тимлид занимается более важной задачей, чем ваша текущая. Тогда стоит поискать другого специалиста в проблемной области, спросить об этом у коллег.
4) на похожий вопрос уже был получен ответ. Открою небольшой лайфхак на примере код-ревью. Есть простой способ проверить внимательность и понимание кода у автора Pull request: если в коде несколько однотипных багов - указываешь только первый и смотришь, поправил ли он остальные. Тут работает тот же принцип.
Когда можно и нужно спрашивать?
1) вообще не понятна причина проблемы. Опять же по моему опыту на самостоятельное решение такого рода проблем могут уходить дни, и даже недели. Либо делаются правки наугад и проверяются на тестовых стендах. А каждый такой цикл может занимать несколько часов. Или заводятся ошибочные тикеты, их отклоняют или перенаправляют и т.д При этом велика вероятность, что эксперт в данной области решит проблему за пару часов: или подскажет "секретный ингридиент", или скажет, что все надо делать по-другому))), или хотя бы направит к человеку, который сможет проблему решить. Еще важный момент - такое "хождение в потемках" может сильно демотивировать новичка и команду.
2) частный случай предыдущего - куда копать понятно, но есть подозрение, что вам на это потребуется условно день, а тимлид может разъяснить все на пальцах за 10 минут. В этом случае стоит в вопросе упомянуть про свою оценку.
3) тимлид сам предложил подходить к нему по любому вопросу. Не совсем по любому - см. пункты выше про гугление и повторы. Если сомневаетесь в сложности вопроса - об этом тоже можно спросить у лида.
4) сжатые сроки по текущей задаче, задача важная
5) все коллеги указывают на данного человека как на эксперта по вашему вопросу
6) вопрос важный: архитектурный или по структуре БД - и хочется посоветоваться с более опытным коллегой
Вывод: не нужно боятся спрашивать. Но не нужно спрашивать то, что вы как разработчик или должны знать, или можете быстро выяснить сами
#people_interactions
Ситуация: новый разработчик приходит в команды, начинает разбираться с кодом, pipeline, архитектурой, у него возникают вопросы. Когда стоит подойти к более опытному товарищу - тимлиду, техлиду, senior-у - а в каких случаях разобраться самому?
Однозначного ответа нет. Но есть ряд условий.
Когда стоит разобраться самому?
1) проблема не относится к специфике компании. Т.е. это что-то, что скорее всего можно нагуглить на stackoverflow или хабре. По своему опыту скажу, что такие вопросы очень раздражают, уметь гуглить должны все) Далее я рассматриваю случаи, когда вопрос касается специфики компании. Люди, которые спрашивают у коллег: объясни на пальцах как устроены сервлеты - могут стать героями локальных мемов (из собственного опыта)
2) примерно понятно где искать ответ. Если искать лень - для этого существуют чаты разработчиков. Там отвечает либо те, у кого в данный момент есть свободное время, либо те, кто настроен на помощь коллегам. А возможно даже "специально обученные" для ответов на вопросы по разработке люди
3) известно, что тимлид занимается более важной задачей, чем ваша текущая. Тогда стоит поискать другого специалиста в проблемной области, спросить об этом у коллег.
4) на похожий вопрос уже был получен ответ. Открою небольшой лайфхак на примере код-ревью. Есть простой способ проверить внимательность и понимание кода у автора Pull request: если в коде несколько однотипных багов - указываешь только первый и смотришь, поправил ли он остальные. Тут работает тот же принцип.
Когда можно и нужно спрашивать?
1) вообще не понятна причина проблемы. Опять же по моему опыту на самостоятельное решение такого рода проблем могут уходить дни, и даже недели. Либо делаются правки наугад и проверяются на тестовых стендах. А каждый такой цикл может занимать несколько часов. Или заводятся ошибочные тикеты, их отклоняют или перенаправляют и т.д При этом велика вероятность, что эксперт в данной области решит проблему за пару часов: или подскажет "секретный ингридиент", или скажет, что все надо делать по-другому))), или хотя бы направит к человеку, который сможет проблему решить. Еще важный момент - такое "хождение в потемках" может сильно демотивировать новичка и команду.
2) частный случай предыдущего - куда копать понятно, но есть подозрение, что вам на это потребуется условно день, а тимлид может разъяснить все на пальцах за 10 минут. В этом случае стоит в вопросе упомянуть про свою оценку.
3) тимлид сам предложил подходить к нему по любому вопросу. Не совсем по любому - см. пункты выше про гугление и повторы. Если сомневаетесь в сложности вопроса - об этом тоже можно спросить у лида.
4) сжатые сроки по текущей задаче, задача важная
5) все коллеги указывают на данного человека как на эксперта по вашему вопросу
6) вопрос важный: архитектурный или по структуре БД - и хочется посоветоваться с более опытным коллегой
Вывод: не нужно боятся спрашивать. Но не нужно спрашивать то, что вы как разработчик или должны знать, или можете быстро выяснить сами
#people_interactions
Всем привет!
Сегодня хотел бы поднять такую тему - что должно быть в проекте сервиса (в исходниках)?
Кроме собственно кода и файлов с настройками.
1) readme.md
Наличие: обязательно.
Содержимое: описание проекта, его идентификатор (для DevOps pipeline или в вашем реестре сервисов), описание вариантов сборки (отладка, запуск модульных и интеграционных тестов, чистовая сборка), структура каталогов, возможно важные особенности сборки
2) .gitignore
Наличие: обязательно
3) test.http
Наличие: крайне желательно
Содержимое: список URL для отладки на localhost в формате, который понимает IntelliJ IDEA
4) IDEA run configuration
Наличие: крайне желательно
Да, конфигурации тоже можно сохранять. Особенно полезны для больших проектов, допускающих отладку отдельных частей для скорости.
5) скрипты и настройки CI
Наличие: крайне желательно
Часто скрипты меняются вместе с кодом, лучше держать их вместе
6) todo.md
Наличие: желательно
Содержимое: техдолг с точки зрения разработчиков сервиса. Я специально делаю акцент на происхождение, т.к. еще есть внешний техдолг от архитекторов, сопровождения, ИБ, его обычно заводят в JIRA. Почему бы и внутренний техдолг не завести в JIRA? Можно, но есть два риска: если работа идет не по Scrum - задача потеряется в недрах системы, если работа идет по Scrum - слишком рьяный Scrum мастер в рамках гигиены JIRA может настоять на удалении задачи как непонятной\неактуальной. Храня же техдолг вместе с кодом мы можем свободно уточнять формулировки, разбивать на более мелкие задачи для последующего переноса в JIRA с взятием в ближайший спринт.
7) Maven или Gradle wrapper
Наличие: желательно, чтобы не зависеть от наличия утилиты в среде сборки
8) профили checkstyle и ему подобных утилит статического анализа кода
Наличие: возможно, если требуется подстройка для вашего сервиса
9) статическая часть папки .idea
Наличие: возможно по договоренности с командой
10) settings.xml для Maven
Наличие: возможно если они меняются от проекта к проекту
11) документация, естественно через автогенерацию
Наличие: возможно, особенно для библиотек
P.S. Еще может возникнуть вопрос про схемы API - их лучше держать отдельно, чтобы физически разделить интерфейс и реализацию.
#sources
Сегодня хотел бы поднять такую тему - что должно быть в проекте сервиса (в исходниках)?
Кроме собственно кода и файлов с настройками.
1) readme.md
Наличие: обязательно.
Содержимое: описание проекта, его идентификатор (для DevOps pipeline или в вашем реестре сервисов), описание вариантов сборки (отладка, запуск модульных и интеграционных тестов, чистовая сборка), структура каталогов, возможно важные особенности сборки
2) .gitignore
Наличие: обязательно
3) test.http
Наличие: крайне желательно
Содержимое: список URL для отладки на localhost в формате, который понимает IntelliJ IDEA
4) IDEA run configuration
Наличие: крайне желательно
Да, конфигурации тоже можно сохранять. Особенно полезны для больших проектов, допускающих отладку отдельных частей для скорости.
5) скрипты и настройки CI
Наличие: крайне желательно
Часто скрипты меняются вместе с кодом, лучше держать их вместе
6) todo.md
Наличие: желательно
Содержимое: техдолг с точки зрения разработчиков сервиса. Я специально делаю акцент на происхождение, т.к. еще есть внешний техдолг от архитекторов, сопровождения, ИБ, его обычно заводят в JIRA. Почему бы и внутренний техдолг не завести в JIRA? Можно, но есть два риска: если работа идет не по Scrum - задача потеряется в недрах системы, если работа идет по Scrum - слишком рьяный Scrum мастер в рамках гигиены JIRA может настоять на удалении задачи как непонятной\неактуальной. Храня же техдолг вместе с кодом мы можем свободно уточнять формулировки, разбивать на более мелкие задачи для последующего переноса в JIRA с взятием в ближайший спринт.
7) Maven или Gradle wrapper
Наличие: желательно, чтобы не зависеть от наличия утилиты в среде сборки
8) профили checkstyle и ему подобных утилит статического анализа кода
Наличие: возможно, если требуется подстройка для вашего сервиса
9) статическая часть папки .idea
Наличие: возможно по договоренности с командой
10) settings.xml для Maven
Наличие: возможно если они меняются от проекта к проекту
11) документация, естественно через автогенерацию
Наличие: возможно, особенно для библиотек
P.S. Еще может возникнуть вопрос про схемы API - их лучше держать отдельно, чтобы физически разделить интерфейс и реализацию.
#sources
Всем привет!
Хорошая подробная статья про кодировки в Java и что изменилось в Java 18 https://habr.com/ru/companies/jugru/articles/709952/
Еще порадовало, что кто-то заморочился и сделал вот такой навигатор: https://habr.com/ru/articles/147843/ )))
А вывод следующий: в существующих Java сервисах надо явно указывать кодировку, как я и говорил ранее: https://t.me/javaKotlinDevOps/193 В новых написанных на Java 18+ в большинстве случаев можно положится на кодировку по умолчанию - UTF-8. Если конечно вы не храните данные в другой кодировке) Или не работаете с Windows и ее консолью и файловой системой. Или кто-то в вашей команде
не проводит отладку на Windows.
#java #encoding
Хорошая подробная статья про кодировки в Java и что изменилось в Java 18 https://habr.com/ru/companies/jugru/articles/709952/
Еще порадовало, что кто-то заморочился и сделал вот такой навигатор: https://habr.com/ru/articles/147843/ )))
А вывод следующий: в существующих Java сервисах надо явно указывать кодировку, как я и говорил ранее: https://t.me/javaKotlinDevOps/193 В новых написанных на Java 18+ в большинстве случаев можно положится на кодировку по умолчанию - UTF-8. Если конечно вы не храните данные в другой кодировке) Или не работаете с Windows и ее консолью и файловой системой. Или кто-то в вашей команде
не проводит отладку на Windows.
#java #encoding
Хабр
JEP-400 или UTF-8 РєРѕРґРёСЂРѕРІРєР° РїРѕ умолчанию
Не прошло и пяти лет, как в Java 18 докатилось небольшое, но очень ожидаемое и обсуждаемое изменение: теперь во всех стандартных API используется UTF-8 кодировка по умолчанию. Это изменение, которое...
Всем привет!
Я уже писал о проблеме интероперабельности Kotlin-Java касающейся null safety - https://t.me/javaKotlinDevOps/190
Есть и еще одна, коллега столкнулся с ней недавно.
В Kotlin четко разделяет изменяемые и неизменяемые коллекции на уровне типов, по умолчанию предлагая делать их неизменяемыми.
В Java наоборот - по умолчанию все коллекции изменяемые, хотя неизменяемые создать тоже можно, например, Collections.unmodifiableXXX, но это не единственный способ.
Итого: предположу, что в Kotlin условно 90% коллекций немодифицируемые, в Java - наоборот 90% модифицируемые.
Что же будет при передаче коллекции из Kotlin в Java?
Да, хорошая практика независимо от языка - не менять передаваемые в метод параметры. Но эта практика не стимулируется к использованию Java.
Да, иммутабельность можно проверить, но делается это довольно криво и я подозреваю делается редко: https://ru.stackoverflow.com/questions/608545/collections-unmodifiable-как-определить
Отсюда получаем, что с большой вероятностью возможна ошибка UnsupportedOperationException на вставке в эти коллекции в Java.
#java #kotlin
Я уже писал о проблеме интероперабельности Kotlin-Java касающейся null safety - https://t.me/javaKotlinDevOps/190
Есть и еще одна, коллега столкнулся с ней недавно.
В Kotlin четко разделяет изменяемые и неизменяемые коллекции на уровне типов, по умолчанию предлагая делать их неизменяемыми.
В Java наоборот - по умолчанию все коллекции изменяемые, хотя неизменяемые создать тоже можно, например, Collections.unmodifiableXXX, но это не единственный способ.
Итого: предположу, что в Kotlin условно 90% коллекций немодифицируемые, в Java - наоборот 90% модифицируемые.
Что же будет при передаче коллекции из Kotlin в Java?
Да, хорошая практика независимо от языка - не менять передаваемые в метод параметры. Но эта практика не стимулируется к использованию Java.
Да, иммутабельность можно проверить, но делается это довольно криво и я подозреваю делается редко: https://ru.stackoverflow.com/questions/608545/collections-unmodifiable-как-определить
Отсюда получаем, что с большой вероятностью возможна ошибка UnsupportedOperationException на вставке в эти коллекции в Java.
#java #kotlin
Telegram
(java || kotlin) && devOps
Всем привет!
Сегодня пост о крутой фиче Kotlin, которая решила одну важную проблему. И добавила другую)
Я о Null safety.
Суть ее в том, что в Kotlin любой тип представлен в двух ипостасях - одна может содержать null значения, другая - нет.
String - не может…
Сегодня пост о крутой фиче Kotlin, которая решила одну важную проблему. И добавила другую)
Я о Null safety.
Суть ее в том, что в Kotlin любой тип представлен в двух ипостасях - одна может содержать null значения, другая - нет.
String - не может…
Всем привет!
Проверяемые исключения - еще одна вещь, которой отличаются Java и Kotlin.
В Kotlin их нет, и вот тут описано почему https://kotlinlang.ru/docs/reference/exceptions.html
Там же есть ссылка на диалог таких известных людей как Bruce Eckel и Anders Hejlsberg на эту тему https://www.artima.com/articles/the-trouble-with-checked-exceptions
Вот тут есть его русский перевод https://habr.com/ru/articles/221723/
В целом соглашусь с основным аргументом авторов: с ростом кодовой базы - а тут важно помнить, что кроме кода сервиса мы еще используем кучу библиотек включая вездесущий Spring Framework - проверяемых исключений становится слишком много. А их выборочная обработка в бизнес приложении, которое активно использует внешние библиотеки, часто не нужна. Т.е. есть цепочка вызова из к примеру 10 сервисов, а обработка исключений - в одном из них, максимум в двух. В остальных случаях их приходится пробрасывать. Отсюда приходим к throws Exception. А это явный антипаттерн.
Следовательно, в большинстве случаев вред от проверяемых исключений перевешивает пользу. Хотя идея - если рассматривать ее именно как идею - красивая: объявляем в API не только типы входящих и исходящих параметров, но и потенциально возможные ошибки. Вот только удобной реализации пока никто не придумал)))
#java #kotlin #exceptions #checked_exceptions
Проверяемые исключения - еще одна вещь, которой отличаются Java и Kotlin.
В Kotlin их нет, и вот тут описано почему https://kotlinlang.ru/docs/reference/exceptions.html
Там же есть ссылка на диалог таких известных людей как Bruce Eckel и Anders Hejlsberg на эту тему https://www.artima.com/articles/the-trouble-with-checked-exceptions
Вот тут есть его русский перевод https://habr.com/ru/articles/221723/
В целом соглашусь с основным аргументом авторов: с ростом кодовой базы - а тут важно помнить, что кроме кода сервиса мы еще используем кучу библиотек включая вездесущий Spring Framework - проверяемых исключений становится слишком много. А их выборочная обработка в бизнес приложении, которое активно использует внешние библиотеки, часто не нужна. Т.е. есть цепочка вызова из к примеру 10 сервисов, а обработка исключений - в одном из них, максимум в двух. В остальных случаях их приходится пробрасывать. Отсюда приходим к throws Exception. А это явный антипаттерн.
Следовательно, в большинстве случаев вред от проверяемых исключений перевешивает пользу. Хотя идея - если рассматривать ее именно как идею - красивая: объявляем в API не только типы входящих и исходящих параметров, но и потенциально возможные ошибки. Вот только удобной реализации пока никто не придумал)))
#java #kotlin #exceptions #checked_exceptions
Что делаете с проверяемыми исключениями из Java Core и внешних библиотек?
Anonymous Poll
38%
Честно пробрасываю все
54%
Сразу же ловлю и обрабатываю
23%
throws Exception скрипя зубами)
Всем привет!
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий. Но есть нюанс. Схема OpenAPI - внешний артефакт. Он лежит либо в git репозитории или API Studio от Swagger. Код по нему генерируется в каталоге сборки. Забыть обновится при выходе новой версии сложнее как раз из-за чёткого понимания того, что API - внешнее. Хотя конечно же можно )
Другое дело Java API. Это про сути ещё одна из десятков библиотек, подключенных к проекту. Версию библиотеки мы фиксируем как это принято при управлении зависимостями. Забыть о том, что это внешнее API, гораздо легче.
Я сейчас говорю не только про кейс, описанный в статье. Ещё есть вариант обмена данными через распределенный кэш, путём сериализации Java POJO объектов, встречал его на практике. А самый яркий антипаттерн при похожем подходе - обмен данными через БД. В этом случае как правило обмениваются скриптами БД, а не классами. Но идея похожа - зачем нам лишняя сущность в виде схемы, лишние преобразования, когда уже есть код. Или уже есть таблица в БД. Конечно, интеграция через БД стала антипаттерном в том числе и потому, что БД - это не только схема, но ещё и транзакции, блокировки, триггеры. Но главную причину я озвучил выше - каждая команда будет считать базу своей внутренней, забывая, что это API. Проблема психологическая, не техническая.
Итого: подход интересный, имеет права на жизнь (я про обмен jar-никами, не про интеграцию через БД), но требует дисциплины. Или автоматизации на этапе CI, позволяющей не надеятся на человеческий фактор.
P.S. Как говорится, не OpenAPI единым - есть ещё Protobuf, GraphQL, xsd наконец. Но самый распространённый - OpenAPI, поэтому везде упоминается он.
#api #OpenAPI #integration
Прочитал статью о том, как можно обойтись без OpenAPI при взаимодействии по REST API https://habr.com/ru/companies/magnit/articles/763952
Для тех кому лень читать - там предлагается использовать Java DTO. В целом подход интересный и рабочий. Но есть нюанс. Схема OpenAPI - внешний артефакт. Он лежит либо в git репозитории или API Studio от Swagger. Код по нему генерируется в каталоге сборки. Забыть обновится при выходе новой версии сложнее как раз из-за чёткого понимания того, что API - внешнее. Хотя конечно же можно )
Другое дело Java API. Это про сути ещё одна из десятков библиотек, подключенных к проекту. Версию библиотеки мы фиксируем как это принято при управлении зависимостями. Забыть о том, что это внешнее API, гораздо легче.
Я сейчас говорю не только про кейс, описанный в статье. Ещё есть вариант обмена данными через распределенный кэш, путём сериализации Java POJO объектов, встречал его на практике. А самый яркий антипаттерн при похожем подходе - обмен данными через БД. В этом случае как правило обмениваются скриптами БД, а не классами. Но идея похожа - зачем нам лишняя сущность в виде схемы, лишние преобразования, когда уже есть код. Или уже есть таблица в БД. Конечно, интеграция через БД стала антипаттерном в том числе и потому, что БД - это не только схема, но ещё и транзакции, блокировки, триггеры. Но главную причину я озвучил выше - каждая команда будет считать базу своей внутренней, забывая, что это API. Проблема психологическая, не техническая.
Итого: подход интересный, имеет права на жизнь (я про обмен jar-никами, не про интеграцию через БД), но требует дисциплины. Или автоматизации на этапе CI, позволяющей не надеятся на человеческий фактор.
P.S. Как говорится, не OpenAPI единым - есть ещё Protobuf, GraphQL, xsd наконец. Но самый распространённый - OpenAPI, поэтому везде упоминается он.
#api #OpenAPI #integration
Хабр
Объектно-ориентированный подход к созданию REST-клиентов, или возможна ли жизнь без Open API
Как-то в общении с моим другом-разработчиком из одной крупной софтверной компании у нас зашёл разговор о взаимодействии распределённых команд. В его компании было множество достаточно изолированных...
Всем привет!
Я уже писал про один особенный класс в Java - enum - https://t.me/javaKotlinDevOps/14
Вот ещё один - массив.
1) да, массив - тоже класс, хранится в куче, наследуется от Object.
2) Главная особенность этого объекта - его класс не определен заранее, JVM создаёт его динамически. Соответственно, его исходники нельзя посмотреть и от него нельзя наследоваться. Имя у него строится по принципу [X, где X - кодирует тип элементов массива, скобка - это скобка) Например, [I для массива int.
3) размер массива как известно фиксируется при создании и его можно получить вызвав array.length. Но интересно, что это не поле класса, значение хранится в заголовке объекта
4) исходя из сказанного выше массив - это особый класс, плохо вписывающийся в систему классов Java. Для него даже пришлось ввести 2 специальные инструкции байткода - для создания и получения длины
5) массив используется под капотом у ArrayList. Если массив статичен, то ArrayList - динамически растёт по мере его заполнения. Ну и является «нормальным» классом)
6) элементы массива расположены последовательно друг за другом в heap, что сильно ускоряет поиск\вставку по номеру элемента
7) массивы ковариантны и поэтому не типобезопасны. Пример кода, который скомпилируется, но упадет в runtime:
Integer[] a1 = new Integer[10];
Object[] a2 = a1;
a2[0] = "Привет ArrayStoreException"
ArrayList является generic и поэтому инвариантен - аналогичный код не скомпилируется:
List<Integer> a1 = new ArrayList()
List<Object> a2 = a1;
8) массивы могут содержать как примитивы, так и объекты, что выгодно отличает их от коллекций. Поэтому основное применение массива, которое я вижу, работа с большим количеством примитивных типов - это будет эффективно с точки зрения памяти и отсутствия операций boxing/unboxing. Зачем нужны массивы объектов - для использования в ArrayList, других применений не могу придумать)
P.S. На написание поста меня подтолкнула эта статья - https://habr.com/ru/articles/753638/, но она для совсем джунов-джунов, решил расширить и повысить концентрацию полезной информации)))
#java #arrays
Я уже писал про один особенный класс в Java - enum - https://t.me/javaKotlinDevOps/14
Вот ещё один - массив.
1) да, массив - тоже класс, хранится в куче, наследуется от Object.
2) Главная особенность этого объекта - его класс не определен заранее, JVM создаёт его динамически. Соответственно, его исходники нельзя посмотреть и от него нельзя наследоваться. Имя у него строится по принципу [X, где X - кодирует тип элементов массива, скобка - это скобка) Например, [I для массива int.
3) размер массива как известно фиксируется при создании и его можно получить вызвав array.length. Но интересно, что это не поле класса, значение хранится в заголовке объекта
4) исходя из сказанного выше массив - это особый класс, плохо вписывающийся в систему классов Java. Для него даже пришлось ввести 2 специальные инструкции байткода - для создания и получения длины
5) массив используется под капотом у ArrayList. Если массив статичен, то ArrayList - динамически растёт по мере его заполнения. Ну и является «нормальным» классом)
6) элементы массива расположены последовательно друг за другом в heap, что сильно ускоряет поиск\вставку по номеру элемента
7) массивы ковариантны и поэтому не типобезопасны. Пример кода, который скомпилируется, но упадет в runtime:
Integer[] a1 = new Integer[10];
Object[] a2 = a1;
a2[0] = "Привет ArrayStoreException"
ArrayList является generic и поэтому инвариантен - аналогичный код не скомпилируется:
List<Integer> a1 = new ArrayList()
List<Object> a2 = a1;
8) массивы могут содержать как примитивы, так и объекты, что выгодно отличает их от коллекций. Поэтому основное применение массива, которое я вижу, работа с большим количеством примитивных типов - это будет эффективно с точки зрения памяти и отсутствия операций boxing/unboxing. Зачем нужны массивы объектов - для использования в ArrayList, других применений не могу придумать)
P.S. На написание поста меня подтолкнула эта статья - https://habr.com/ru/articles/753638/, но она для совсем джунов-джунов, решил расширить и повысить концентрацию полезной информации)))
#java #arrays
Telegram
(java || kotlin) && devOps
Всем привет!
Хочу рассказать про ряд неочевидных особенностей enum в Java.
Поехали!
1) enum - это полноценный класс, у него могут быть поля, методы, обычные и статические
2) любой enum неявно (!) расширяет абстрактный класс Enum, поэтому наследовать enum…
Хочу рассказать про ряд неочевидных особенностей enum в Java.
Поехали!
1) enum - это полноценный класс, у него могут быть поля, методы, обычные и статические
2) любой enum неявно (!) расширяет абстрактный класс Enum, поэтому наследовать enum…
Всем привет!
Среди первых постов этого канала был пост про k8s - для чего он нужен https://t.me/javaKotlinDevOps/6
Но я забыл рассказать про Service Mesh - что же она добавляет к k8s. Если вы не понимаете, что за Service Mesh такой - самой известной реализацией является Istio https://istio.io/latest/docs/ На его примере хочу рассказать про Service Mesh.
Начал искать материалы и сразу наткнулся на серию отличных статей:
https://habr.com/ru/companies/flant/articles/438426/
https://habr.com/ru/companies/flant/articles/569612/
https://habr.com/ru/companies/oleg-bunin/articles/726958/
Рекомендую их почитать, там есть и про устройство Istio на сетевом уровне, и про решаемые им задачи, и про вносимые данной технологией риски.
Для тех, кому лень читать поработаю продвинутой версией Yandex GPT.
Основные "плюшки" Istio:
1) возможность аутентификации и авторизации запросов как по адресам, url-ам, так и с помощью OAuth
2) продвинутые возможности балансировки - например, привязка клиента к конкретному серверу или геопривязка: перенаправление только на экземпляры сервиса, находящиеся в том же гео-кластере
3) реализация паттерна Circuit Breaker, повторов и настройка таймаутов для запросов
4) продвинутые возможности маршрутизации: по URL и http заголовкам
5) реализация канареечного развертывания и зеркалирования траффика
6) TLS Termination и Origination - снятие и добавление TLS шифрования на входе\выходе из namespace, что позволяет полностью переложить работу с сертификатами с разработки на сопровождение
Вывод следующий: Service Mesh - новый уровень абстракции поверх обычного облака (k8s). Да, он добавляет сложность, особенно в части сопровождения. Вносит небольшие задержки, которые в определенных случаях могут быть критичны. Требует ресурсов, что также может быть важно. Но если его "плюшки" вам полезны - оно того стоит)
#istio #k8s #service_mesh #cloud
Среди первых постов этого канала был пост про k8s - для чего он нужен https://t.me/javaKotlinDevOps/6
Но я забыл рассказать про Service Mesh - что же она добавляет к k8s. Если вы не понимаете, что за Service Mesh такой - самой известной реализацией является Istio https://istio.io/latest/docs/ На его примере хочу рассказать про Service Mesh.
Начал искать материалы и сразу наткнулся на серию отличных статей:
https://habr.com/ru/companies/flant/articles/438426/
https://habr.com/ru/companies/flant/articles/569612/
https://habr.com/ru/companies/oleg-bunin/articles/726958/
Рекомендую их почитать, там есть и про устройство Istio на сетевом уровне, и про решаемые им задачи, и про вносимые данной технологией риски.
Для тех, кому лень читать поработаю продвинутой версией Yandex GPT.
Основные "плюшки" Istio:
1) возможность аутентификации и авторизации запросов как по адресам, url-ам, так и с помощью OAuth
2) продвинутые возможности балансировки - например, привязка клиента к конкретному серверу или геопривязка: перенаправление только на экземпляры сервиса, находящиеся в том же гео-кластере
3) реализация паттерна Circuit Breaker, повторов и настройка таймаутов для запросов
4) продвинутые возможности маршрутизации: по URL и http заголовкам
5) реализация канареечного развертывания и зеркалирования траффика
6) TLS Termination и Origination - снятие и добавление TLS шифрования на входе\выходе из namespace, что позволяет полностью переложить работу с сертификатами с разработки на сопровождение
Вывод следующий: Service Mesh - новый уровень абстракции поверх обычного облака (k8s). Да, он добавляет сложность, особенно в части сопровождения. Вносит небольшие задержки, которые в определенных случаях могут быть критичны. Требует ресурсов, что также может быть важно. Но если его "плюшки" вам полезны - оно того стоит)
#istio #k8s #service_mesh #cloud
Telegram
(java || kotlin) && devOps
Чем kubernetes, он же k8s лучше контейнера сервлетов или сервера приложений.
Во-первых под капотом k8s лежит Docker, а значит мы получаем все его плюшки. Не зря k8s называют оркестратором контейнеров. Чем занимается оркестратор?
1) планированиеи ресурсов.…
Во-первых под капотом k8s лежит Docker, а значит мы получаем все его плюшки. Не зря k8s называют оркестратором контейнеров. Чем занимается оркестратор?
1) планированиеи ресурсов.…
Всем привет!
К вопросу о кратком пересказе текста. Как вы наверное знаете, недавно такую фичу выкатил Яндекс - назвал ее YandexGPT.
Вот пример краткого пересказа двух статей из предыдущего поста.
Istio в разрезе: что умеет и не умеет самый популярный Service Mesh (обзор и видео доклада) / Хабр
• Istio - это система управления Service Mesh, которая позволяет реализовать разные паттерны по управлению TCP-трафиком в проекте.
• Istio предоставляет набор интерфейсов для настройки и управления компонентами Service Mesh.
• Istio может влиять на надежность приложения, но требует правильной настройки и использования.
• Istio также влияет на latency, безопасность и масштабирование.
• В Istio можно использовать протокол Delta xDS для сокращения нагрузки на Control Plane и сеть.
• Ожидается, что Ambient Mesh, новая функция Istio, упростит обновления и снизит нагрузку на Control Plane.
https://300.ya.ru/PxCuGmdO
Что ждать от внедрения Istio? (обзор и видео доклада) / Хабр
• Istio - частный случай «сервисной сетки» (Service Mesh), понятия, о котором наверняка все слышали.
• Istio влияет на трафик, возможности для его мониторинга, безопасность mTLS.
• Istio имеет свой декларативный язык для управления сетью.
• Istio интегрируется с сторонними инструментами для мониторинга, например, с дашбордом Kiali.
• Istio предоставляет возможности для внедрения трассировки на основе Jaeger.
• Безопасность mTLS в Istio считается безопасной.
• Вопросы к Istio: влияние на приложение, кластер, observability, безопасность mTLS.
https://300.ya.ru/4cNaxU0s
Что хочется отметить:
1) ИИ не умеет структурировать тезисы, идет сверху вниз
2) ИИ не умеет выбирать ключевые фичи и делать акценты
3) "Безопасность ... считается безопасной"
P.S. Что касается п.3 - а может ИИ уже научился шутить и нам стоит начинать бояться?)
#ai #yandexgpt #yandex
К вопросу о кратком пересказе текста. Как вы наверное знаете, недавно такую фичу выкатил Яндекс - назвал ее YandexGPT.
Вот пример краткого пересказа двух статей из предыдущего поста.
Istio в разрезе: что умеет и не умеет самый популярный Service Mesh (обзор и видео доклада) / Хабр
• Istio - это система управления Service Mesh, которая позволяет реализовать разные паттерны по управлению TCP-трафиком в проекте.
• Istio предоставляет набор интерфейсов для настройки и управления компонентами Service Mesh.
• Istio может влиять на надежность приложения, но требует правильной настройки и использования.
• Istio также влияет на latency, безопасность и масштабирование.
• В Istio можно использовать протокол Delta xDS для сокращения нагрузки на Control Plane и сеть.
• Ожидается, что Ambient Mesh, новая функция Istio, упростит обновления и снизит нагрузку на Control Plane.
https://300.ya.ru/PxCuGmdO
Что ждать от внедрения Istio? (обзор и видео доклада) / Хабр
• Istio - частный случай «сервисной сетки» (Service Mesh), понятия, о котором наверняка все слышали.
• Istio влияет на трафик, возможности для его мониторинга, безопасность mTLS.
• Istio имеет свой декларативный язык для управления сетью.
• Istio интегрируется с сторонними инструментами для мониторинга, например, с дашбордом Kiali.
• Istio предоставляет возможности для внедрения трассировки на основе Jaeger.
• Безопасность mTLS в Istio считается безопасной.
• Вопросы к Istio: влияние на приложение, кластер, observability, безопасность mTLS.
https://300.ya.ru/4cNaxU0s
Что хочется отметить:
1) ИИ не умеет структурировать тезисы, идет сверху вниз
2) ИИ не умеет выбирать ключевые фичи и делать акценты
3) "Безопасность ... считается безопасной"
P.S. Что касается п.3 - а может ИИ уже научился шутить и нам стоит начинать бояться?)
#ai #yandexgpt #yandex
300.ya.ru
Пересказ YandexGPT: Istio в разрезе: что умеет и не умеет самый популярный Service Mesh (обзор и видео доклада)
• Istio - это система управления Service Mesh, которая позволяет реализовать разные паттерны по управлению TCP-трафиком в проекте.
• Istio предоставляет набор интерфейсов для настройки и управления компонентами Service Mesh.
• Istio может влиять на надежность…
• Istio предоставляет набор интерфейсов для настройки и управления компонентами Service Mesh.
• Istio может влиять на надежность…
Всем привет!
Прочитал книгу Лемер "Масштабируемый рефакторинг". В целом понравилась, с важным дисклеймером.
С одной стороны основные мысли в книге вполне себе "капитанские". С другой - о них очень легко забыть)))
Еще важный момент - большинство правил из книжки применимо для скажем так большого рефакторинга: затрагивающего платформенный сервис, от которого зависят множество команд, ядро монолита, схему БД или что-то подобное. Если нужно отрефакторить метод или класс - данные рекомендации скорее всего будут излишними.
Тезисы:
1) т.к. рефакторинг займет длительное время - нужен план. План позволит:
а) видеть весь объем работ и правильно оценить: хватит ли выделенного бизнесом времени
б) найти забытые задачи либо самостоятельно - анализируя план - либо с помощью смежных команд, опубликовав его
2) рефакторинг нужно делать для кода в вашей области ответственности. Если за код отвечает другая - не надо его трогать без согласования
3) нужно понять - не является ли код deprecated или неиспользуемым. Часто код забывают удалять, все его использование ограничивается модульными тестами
4) нужно изучить - почему код стал таким. Зачем?
а) возможно выяснится, что "это не баг, а фича"
б) когда станет понятно, на почему возникли те или иные компромиссы в коде - это изменит отношение к коду. Все же приятнее улучшать сложный legacy код, а не "переписывать этот го..код"
5) нужно ответить себе на вопрос - почему код нужно рефакторить именно сейчас. А возможные ответы на этот вопрос приводят к необходимости метрик для бизнеса, о которых я уже писал https://t.me/javaKotlinDevOps/197
6) важно собрать команду с двумя типами участников: full time разработчики и эксперты. Для этого нужно договориться с руководителями о их полном или частичном подключении к задаче рефакторинга. Искать стоит людей, либо заинтересованных в результате рефакторинга, либо тех, кому надоела рутина и хочется, что-то поменять
7) нужен канал или страничка, где регулярно будут публиковаться прогресс рефакторинга. В случае, если прогресс будет - это может мотивировать на подключение к рефакторингу новых участников. Прогресс нужно сопоставлять с планом, при необходимости вносить корректировки. Также нужен митап или чат, где заинтересованные лица смогут задать вопросы.
8) прогресс нужно контролировать еще потому, что ближе к концу, когда основные изменения уже сделаны, есть риск снижения темпов. Из-за выгорания или расслабления - ведь основные изменения уже сделаны. Что тут можно сделать:
а) собираться командой в неформальной обстановке
б) рассказывать о своих достижениях для вливания "новой крови"
9) после окончания рефакторинга важно проконтролировать, что все потребители знают об изменениях и либо уже используют их, либо запланировали обновление. Речь может идти о переходе на новое API, новый фреймворк, новый DevOps, новую версию библиотеки. Для ускорения процесса перехода нужны:
а) рассылка
б) демонстрация
в) инструкция
г) чат, куда можно задать вопросы
д) возможно регулярный митап для ответов на сложные вопросы
#books #refactoring #book_review
Прочитал книгу Лемер "Масштабируемый рефакторинг". В целом понравилась, с важным дисклеймером.
С одной стороны основные мысли в книге вполне себе "капитанские". С другой - о них очень легко забыть)))
Еще важный момент - большинство правил из книжки применимо для скажем так большого рефакторинга: затрагивающего платформенный сервис, от которого зависят множество команд, ядро монолита, схему БД или что-то подобное. Если нужно отрефакторить метод или класс - данные рекомендации скорее всего будут излишними.
Тезисы:
1) т.к. рефакторинг займет длительное время - нужен план. План позволит:
а) видеть весь объем работ и правильно оценить: хватит ли выделенного бизнесом времени
б) найти забытые задачи либо самостоятельно - анализируя план - либо с помощью смежных команд, опубликовав его
2) рефакторинг нужно делать для кода в вашей области ответственности. Если за код отвечает другая - не надо его трогать без согласования
3) нужно понять - не является ли код deprecated или неиспользуемым. Часто код забывают удалять, все его использование ограничивается модульными тестами
4) нужно изучить - почему код стал таким. Зачем?
а) возможно выяснится, что "это не баг, а фича"
б) когда станет понятно, на почему возникли те или иные компромиссы в коде - это изменит отношение к коду. Все же приятнее улучшать сложный legacy код, а не "переписывать этот го..код"
5) нужно ответить себе на вопрос - почему код нужно рефакторить именно сейчас. А возможные ответы на этот вопрос приводят к необходимости метрик для бизнеса, о которых я уже писал https://t.me/javaKotlinDevOps/197
6) важно собрать команду с двумя типами участников: full time разработчики и эксперты. Для этого нужно договориться с руководителями о их полном или частичном подключении к задаче рефакторинга. Искать стоит людей, либо заинтересованных в результате рефакторинга, либо тех, кому надоела рутина и хочется, что-то поменять
7) нужен канал или страничка, где регулярно будут публиковаться прогресс рефакторинга. В случае, если прогресс будет - это может мотивировать на подключение к рефакторингу новых участников. Прогресс нужно сопоставлять с планом, при необходимости вносить корректировки. Также нужен митап или чат, где заинтересованные лица смогут задать вопросы.
8) прогресс нужно контролировать еще потому, что ближе к концу, когда основные изменения уже сделаны, есть риск снижения темпов. Из-за выгорания или расслабления - ведь основные изменения уже сделаны. Что тут можно сделать:
а) собираться командой в неформальной обстановке
б) рассказывать о своих достижениях для вливания "новой крови"
9) после окончания рефакторинга важно проконтролировать, что все потребители знают об изменениях и либо уже используют их, либо запланировали обновление. Речь может идти о переходе на новое API, новый фреймворк, новый DevOps, новую версию библиотеки. Для ускорения процесса перехода нужны:
а) рассылка
б) демонстрация
в) инструкция
г) чат, куда можно задать вопросы
д) возможно регулярный митап для ответов на сложные вопросы
#books #refactoring #book_review
Telegram
(java || kotlin) && devOps
Всем привет!
Я уже писал о важности рефакторинга.
Но как оценить, что рефакторинг достиг своих целей?
Можно экспертно. Но не всегда этот вариант годится для обоснования времени на рефакторинг у бизнеса.
Можно ли как-то подтвердить эффект цифрами?
Самый простой…
Я уже писал о важности рефакторинга.
Но как оценить, что рефакторинг достиг своих целей?
Можно экспертно. Но не всегда этот вариант годится для обоснования времени на рефакторинг у бизнеса.
Можно ли как-то подтвердить эффект цифрами?
Самый простой…
Всем привет!
Сегодня хочу поднять вопрос анемичной доменной модели. Давно холиварные вопросы не поднимал)
Одним из первых это понятие ввел Мартин Фаулер, см. https://martinfowler.com/bliki/AnemicDomainModel.html
Анемичной модели противопоставляется т.наз. "богатая" или, как я бы ее назвал, полноценная доменная модель.
В чем разница?
В анемичной доменной модели объекты по сути аналогичны DTO, их можно реализовать в виде Java records или Kotlin value object.
В полноценной - в объектах кроме данных есть бизнес-логика.
Вот аргументы сторонников полноценной модели:
https://www.baeldung.com/java-anemic-vs-rich-domain-objects
https://www.youtube.com/watch?v=lfdAwl3-X_c - особенно рекомендую, Егор как всегда подходит к теме "с огоньком")
Вот - сторонников анемичной модели: https://habr.com/ru/articles/346016/
Я в этом споре все же склоняюсь к полноценной модели.
Т.к. доменный объект - это не DTO, он должен содержать нечто большее. А именно - бизнес-логику. А вынося логику в отдельные сервисы легко так сильно ее размазать по коду, что это приведет к дублированию и ухудшению читаемости.
Более того: если модель становится анемичной - это может быть признаком, что модель не нужна, сервис является простым и можно вполне себе работать с DTO.
Особенно актуальна "богатая" доменная модель, если вы пытаетесь следовать практике DDD - Domain Driven Design. Собственно, ее автор, Эрик Эванс, сторонник этого подхода.
Да и есть смотреть определение класса в ООП - это не просто хранилище данных. Объект - это отражение сущности из реального мира. А в реальном мире объекты - кот, автомобиль, заказ - являются не только набором характеристик, но и могут что-то делать)
Но есть один нюанс.
Если логика не требует данных, не содержащихся в объекте - ей место в этом объекте.
Если требует данных извне, но не вызывает методы внешних объектов - аналогично.
А вот дальше простые правила заканчиваются и решения от сервиса к сервису могут отличаться. Как минимум стоит принять во внимание принцип SOLID, удобство переиспользования кода и удобство тестирования.
Да, и точно не стоит запихивать в модель инфраструктурный код - деление приложения на уровни никто не отменял.
Идея в том, что не надо боятся добавлять методы в объекты доменной модели. Более того, при проектировании стоит изначально думать о том, какими будут эти объекты.
Что касается нарушения принципов S и I из SOLID.
Не надо относится к этим принципам догматично. Если так делать - то у нас в итоге будет куча DTO с парой полей, куча интерфейсов с одним методом и взрыв мозга у людей, которые попытаются вникнуть в этом код с нуля) Важен баланс.
#anemic-vs-rich-domain-objects #holy_war #solid #oop
Сегодня хочу поднять вопрос анемичной доменной модели. Давно холиварные вопросы не поднимал)
Одним из первых это понятие ввел Мартин Фаулер, см. https://martinfowler.com/bliki/AnemicDomainModel.html
Анемичной модели противопоставляется т.наз. "богатая" или, как я бы ее назвал, полноценная доменная модель.
В чем разница?
В анемичной доменной модели объекты по сути аналогичны DTO, их можно реализовать в виде Java records или Kotlin value object.
В полноценной - в объектах кроме данных есть бизнес-логика.
Вот аргументы сторонников полноценной модели:
https://www.baeldung.com/java-anemic-vs-rich-domain-objects
https://www.youtube.com/watch?v=lfdAwl3-X_c - особенно рекомендую, Егор как всегда подходит к теме "с огоньком")
Вот - сторонников анемичной модели: https://habr.com/ru/articles/346016/
Я в этом споре все же склоняюсь к полноценной модели.
Т.к. доменный объект - это не DTO, он должен содержать нечто большее. А именно - бизнес-логику. А вынося логику в отдельные сервисы легко так сильно ее размазать по коду, что это приведет к дублированию и ухудшению читаемости.
Более того: если модель становится анемичной - это может быть признаком, что модель не нужна, сервис является простым и можно вполне себе работать с DTO.
Особенно актуальна "богатая" доменная модель, если вы пытаетесь следовать практике DDD - Domain Driven Design. Собственно, ее автор, Эрик Эванс, сторонник этого подхода.
Да и есть смотреть определение класса в ООП - это не просто хранилище данных. Объект - это отражение сущности из реального мира. А в реальном мире объекты - кот, автомобиль, заказ - являются не только набором характеристик, но и могут что-то делать)
Но есть один нюанс.
Если логика не требует данных, не содержащихся в объекте - ей место в этом объекте.
Если требует данных извне, но не вызывает методы внешних объектов - аналогично.
А вот дальше простые правила заканчиваются и решения от сервиса к сервису могут отличаться. Как минимум стоит принять во внимание принцип SOLID, удобство переиспользования кода и удобство тестирования.
Да, и точно не стоит запихивать в модель инфраструктурный код - деление приложения на уровни никто не отменял.
Идея в том, что не надо боятся добавлять методы в объекты доменной модели. Более того, при проектировании стоит изначально думать о том, какими будут эти объекты.
Что касается нарушения принципов S и I из SOLID.
Не надо относится к этим принципам догматично. Если так делать - то у нас в итоге будет куча DTO с парой полей, куча интерфейсов с одним методом и взрыв мозга у людей, которые попытаются вникнуть в этом код с нуля) Важен баланс.
#anemic-vs-rich-domain-objects #holy_war #solid #oop
martinfowler.com
bliki: Anemic Domain Model
If you use an object-oriented domain model, and you don't put behavior in your objects, you're missing out on most of the benefits of that pattern.
Всем привет!
Сегодня пятница, поговорим немного о магии.
Что я считаю одним из самых плохих качеств разработчика - веру в магию.
Симптомы магического мышления: фразы типа "ну вроде починил", "ну вроде работает". Или хаотичный перебор настроек в надежде, что все заработает. Или нежелание что-то менять в коде, из-за боязни поломать.
У любой проблемы при разработке ПО есть причины. Иногда они очевидны, иногда нужно потратить дни или недели, чтобы понять - почему оно так работает.
Бывает так, что не хватает времени, чтобы разобраться в причинах. Бывает так, что корни проблемы лежат в области, где не хватает компетенции - СУБД, внешняя система, pipeline. Это нужно понимать и признавать. Решение - искать специалиста или просить больше времени на разбор. Четыре лайфхака по самостоятельному разбору проблем:
1) посмотреть исходный код проблемного компонента, даже если он не ваш
2) погуглить)))
3) внимательнее читать логи. Часто вижу, что первая подозрительная запись в логах останавливает поиск. А если промотать еще десяток строк - лежит нормальное описание ошибки.
4) разбить проблему на части, т.к. часто самые загадочные случаи - это следствие череды ошибок.
Ну и прекрасная иллюстрация того, что любая магия имеет объяснение - вот эта статья: https://habr.com/ru/articles/759344/
#dev
Сегодня пятница, поговорим немного о магии.
Что я считаю одним из самых плохих качеств разработчика - веру в магию.
Симптомы магического мышления: фразы типа "ну вроде починил", "ну вроде работает". Или хаотичный перебор настроек в надежде, что все заработает. Или нежелание что-то менять в коде, из-за боязни поломать.
У любой проблемы при разработке ПО есть причины. Иногда они очевидны, иногда нужно потратить дни или недели, чтобы понять - почему оно так работает.
Бывает так, что не хватает времени, чтобы разобраться в причинах. Бывает так, что корни проблемы лежат в области, где не хватает компетенции - СУБД, внешняя система, pipeline. Это нужно понимать и признавать. Решение - искать специалиста или просить больше времени на разбор. Четыре лайфхака по самостоятельному разбору проблем:
1) посмотреть исходный код проблемного компонента, даже если он не ваш
2) погуглить)))
3) внимательнее читать логи. Часто вижу, что первая подозрительная запись в логах останавливает поиск. А если промотать еще десяток строк - лежит нормальное описание ошибки.
4) разбить проблему на части, т.к. часто самые загадочные случаи - это следствие череды ошибок.
Ну и прекрасная иллюстрация того, что любая магия имеет объяснение - вот эта статья: https://habr.com/ru/articles/759344/
#dev
Хабр
Высокие технологии или дешевые фокусы с двойным дном
Отлаживал я как-то тесты и параллельно размышлял о null-safety. Звезды сошлись и родилась довольно странная идея - замокать null . Искушения программиста смотрящего на Mockito.when().thenReturn() Ниже...