Всем привет!
Сегодня хочу поднять вопрос анемичной доменной модели. Давно холиварные вопросы не поднимал)
Одним из первых это понятие ввел Мартин Фаулер, см. 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() Ниже...
Всем привет!
Те, кто читал книжку Чистый код Мартина думаю помнят, что переменные должны иметь говорящие имена для повышения читаемости кода. Да и не только там эта мысль проходит. Я двумя руками за, писал уже об этом на канале.
Теперь внимание, вопрос - а можно ли тогда использовать переменные типа i или j в циклах? Откуда вообще взялись i и j, почему не a, b?
https://stackoverflow.com/questions/4137785/why-are-variables-i-and-j-used-for-counters
#java #math
Те, кто читал книжку Чистый код Мартина думаю помнят, что переменные должны иметь говорящие имена для повышения читаемости кода. Да и не только там эта мысль проходит. Я двумя руками за, писал уже об этом на канале.
Теперь внимание, вопрос - а можно ли тогда использовать переменные типа i или j в циклах? Откуда вообще взялись i и j, почему не a, b?
https://stackoverflow.com/questions/4137785/why-are-variables-i-and-j-used-for-counters
#java #math
Stack Overflow
Why are variables "i" and "j" used for counters?
I know this might seem like an absolutely silly question to ask, yet I am too curious not to ask...
Why did "i" and "j" become THE variables to use as counters in most control structures?
Although
Why did "i" and "j" become THE variables to use as counters in most control structures?
Although
Всем привет!
Что включает в себя понятие объекта?
1) объект может иметь данные
2) данные объекта можно менять
3) объект может иметь поведение - методы
4) от класса объекта можно наследоваться
5) объектов одного класса может быть несколько
6) каждый объект уникален - находится в heap по своему адресу. Т.е. имеет identity
Можно ли отобрать у объекта что-то из вышеперечисленного в Java?
1) final class - запрещаем наследование
2) sealed class - если полный запрет нам не подходит, то ограничиваем наследование https://habr.com/ru/companies/otus/articles/720044/
3) final поля - запрещаем менять данные класса после создания объекта - иммутабельность
4) records - запрещаем методы и изменение полей https://habr.com/ru/articles/487308/ Основое применение - DTO, где есть только данные и их нежелательно менять.
5) lambda - можно рассматривать как объект-функцию без данных, хотя технически это не так - JVM под капотом транслирует ее в статический метод https://javadungeon.wordpress.com/2017/08/02/java-8-lambdas-under-the-hood/
6) object в Kotlin - синлетона на уровне языка в Java нет, но такую конструкцию сделали в Kotlin
7) value class - еще не реализованная в Java концепция, которая по сути добавляет в язык что-то среднее между примитивным типом и объектом. Т.е. у нас будет объект, но в плане занимаемой памяти он будет почти также эффективен, как и примитив. Что важно: т.к. это объект - его можно будет использовать в generics. Ура-ура!. Детали: https://www.baeldung.com/java-valhalla-project Но ничего не бывает бесплатно - у такого объекта не будет identity, т.е. два объекта с одинаковыми полями считаются одинаковыми. Также, как это сейчас происходит с примитивными типами. Да, для объектов это уже сейчас можно реализовать на уровне кода. А тут идея сделать тоже самое на уровне JVM. Т.е. JVM может (обязана?) оставить один экземпляр для всех одинаковых объектов. Причем так, как это сделано сейчас со строками - вариант не очень, т.к. остается "дыра" с конструктором, который по определению всегда создает новый объект. Т.е. для value class нельзя использовать публичный конструктор, нужен какой-то фабричный метод - как элемент языка. Примеры, когда это полезно: те же классы-обвертки для чисел или географические объекты.
#java #oop #kotlin
Что включает в себя понятие объекта?
1) объект может иметь данные
2) данные объекта можно менять
3) объект может иметь поведение - методы
4) от класса объекта можно наследоваться
5) объектов одного класса может быть несколько
6) каждый объект уникален - находится в heap по своему адресу. Т.е. имеет identity
Можно ли отобрать у объекта что-то из вышеперечисленного в Java?
1) final class - запрещаем наследование
2) sealed class - если полный запрет нам не подходит, то ограничиваем наследование https://habr.com/ru/companies/otus/articles/720044/
3) final поля - запрещаем менять данные класса после создания объекта - иммутабельность
4) records - запрещаем методы и изменение полей https://habr.com/ru/articles/487308/ Основое применение - DTO, где есть только данные и их нежелательно менять.
5) lambda - можно рассматривать как объект-функцию без данных, хотя технически это не так - JVM под капотом транслирует ее в статический метод https://javadungeon.wordpress.com/2017/08/02/java-8-lambdas-under-the-hood/
6) object в Kotlin - синлетона на уровне языка в Java нет, но такую конструкцию сделали в Kotlin
7) value class - еще не реализованная в Java концепция, которая по сути добавляет в язык что-то среднее между примитивным типом и объектом. Т.е. у нас будет объект, но в плане занимаемой памяти он будет почти также эффективен, как и примитив. Что важно: т.к. это объект - его можно будет использовать в generics. Ура-ура!. Детали: https://www.baeldung.com/java-valhalla-project Но ничего не бывает бесплатно - у такого объекта не будет identity, т.е. два объекта с одинаковыми полями считаются одинаковыми. Также, как это сейчас происходит с примитивными типами. Да, для объектов это уже сейчас можно реализовать на уровне кода. А тут идея сделать тоже самое на уровне JVM. Т.е. JVM может (обязана?) оставить один экземпляр для всех одинаковых объектов. Причем так, как это сделано сейчас со строками - вариант не очень, т.к. остается "дыра" с конструктором, который по определению всегда создает новый объект. Т.е. для value class нельзя использовать публичный конструктор, нужен какой-то фабричный метод - как элемент языка. Примеры, когда это полезно: те же классы-обвертки для чисел или географические объекты.
#java #oop #kotlin
Хабр
Sealed классы Java в действии: создание надежных и безопасных приложений
Sealed (закрытые или запечатанные) классы были представлены в Java 15 в качестве способа ограничить иерархию наследования класса или интерфейса. Sealed класс...
Всем привет!
Минутка самообразования. В России есть две крупнейших конференции по Java разработке - JPoint и Joker. Они платные, с одним бесплатным днем, доступным после регистрации. Но главное - через какое-то время все доклады конференции, которые были записаны, становятся открытыми. Уже доступны доклады с JPoint 2023 - https://www.youtube.com/playlist?list=PLVe-2wcL84b9iHBMgj3Mjgr7Lg-FER8jP
Докладов целых 60 штук, тематика очень разнообразная, в отличие от прошлых лет. Я для себя нашел как минимум с десяток интересных.
Enjoy)
#conferences #jpoint
Минутка самообразования. В России есть две крупнейших конференции по Java разработке - JPoint и Joker. Они платные, с одним бесплатным днем, доступным после регистрации. Но главное - через какое-то время все доклады конференции, которые были записаны, становятся открытыми. Уже доступны доклады с JPoint 2023 - https://www.youtube.com/playlist?list=PLVe-2wcL84b9iHBMgj3Mjgr7Lg-FER8jP
Докладов целых 60 штук, тематика очень разнообразная, в отличие от прошлых лет. Я для себя нашел как минимум с десяток интересных.
Enjoy)
#conferences #jpoint
Всем привет!
К двум моим статьям про k8s (https://t.me/javaKotlinDevOps/6) и Istio (https://t.me/javaKotlinDevOps/210) прямо напрашивается третья - про Openshift.
Тут может возникнуть вопрос - а что это вообще такое и почему напрашивается?)
Ответ: это "допиленный напильником" k8s от компании Redhat для enterprise.
Поэтому если вы работаете в enterprise, особенно кровавом, то тема актуальная)
Второй вопрос, который может возникнуть - какой такой западный enterprise в России сейчас?
Ответ: есть opensource версия https://habr.com/ru/companies/redhatrussia/articles/511800/
Итак, что же добавляет Openshift к k8s.
1) Istio - включен в дистрибутив
2) встроенный Docker Registry
Небольшое уведомление. Основной пласт возможностей, которые предоставляет Openshift, реализован за счет кастомных ресурсов - CRD - и оператора, который их обрабатывает.
https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
https://habr.com/ru/companies/slurm/articles/556860/
Идем дальше.
3) настройки безопасности: ролевая модель https://docs.openshift.com/container-platform/4.8/rest_api/role_apis/role-apis-index.html, авторизация https://docs.openshift.com/container-platform/4.8/rest_api/authorization_apis/authorization-apis-index.html , OAuth https://docs.openshift.com/container-platform/4.8/rest_api/oauth_apis/oauth-apis-index.html
4) механизм шаблонов (ресурс типа Template) - позволяет в одном файле задать несколько ресурсов с параметрами. Значения параметров можно как задать в самом шаблоне (значения по умолчанию), так и передать в момент применения Template
https://docs.openshift.com/container-platform/4.8/rest_api/template_apis/template-apis-index.html
5) Имея механизм шаблонов, ролевую модель и настройку лимитов из k8s можно упростить создание новых namespace: для этого вводится проект - аналог namespace в Openshift. https://docs.openshift.com/container-platform/4.8/rest_api/project_apis/project-apis-index.html
6) самое интересное - концепция build-related ресурсов. Идея в том, что при изменении исходников или появлении нового образа в Docker происходит автоматическая сборка и установка новой версии приложения. Т.е. фактически мы получаем встроенный в кластер CI\CD.
https://docs.openshift.com/container-platform/4.10/cicd/index.html
https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/buildconfig-build-openshift-io-v1.html
Данная концепция приводит к тому, что стандартный ресурс Deployment в Openshift заменяется на очень похожий DeploymentConfig, поддерживающий пересоздание подов при появлении нового кода https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/deploymentconfig-apps-openshift-io-v1.html
7) само собой новая веб-консоль и новая CLI утилита (oc), поддерживающие все вышеописанные возможности.
Вот пожалуй и все основные отличия Openshift. В целом неплохо, хотя и не так революционно, как Istio
#openshift #istio #cloud #k8s
К двум моим статьям про k8s (https://t.me/javaKotlinDevOps/6) и Istio (https://t.me/javaKotlinDevOps/210) прямо напрашивается третья - про Openshift.
Тут может возникнуть вопрос - а что это вообще такое и почему напрашивается?)
Ответ: это "допиленный напильником" k8s от компании Redhat для enterprise.
Поэтому если вы работаете в enterprise, особенно кровавом, то тема актуальная)
Второй вопрос, который может возникнуть - какой такой западный enterprise в России сейчас?
Ответ: есть opensource версия https://habr.com/ru/companies/redhatrussia/articles/511800/
Итак, что же добавляет Openshift к k8s.
1) Istio - включен в дистрибутив
2) встроенный Docker Registry
Небольшое уведомление. Основной пласт возможностей, которые предоставляет Openshift, реализован за счет кастомных ресурсов - CRD - и оператора, который их обрабатывает.
https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
https://habr.com/ru/companies/slurm/articles/556860/
Идем дальше.
3) настройки безопасности: ролевая модель https://docs.openshift.com/container-platform/4.8/rest_api/role_apis/role-apis-index.html, авторизация https://docs.openshift.com/container-platform/4.8/rest_api/authorization_apis/authorization-apis-index.html , OAuth https://docs.openshift.com/container-platform/4.8/rest_api/oauth_apis/oauth-apis-index.html
4) механизм шаблонов (ресурс типа Template) - позволяет в одном файле задать несколько ресурсов с параметрами. Значения параметров можно как задать в самом шаблоне (значения по умолчанию), так и передать в момент применения Template
https://docs.openshift.com/container-platform/4.8/rest_api/template_apis/template-apis-index.html
5) Имея механизм шаблонов, ролевую модель и настройку лимитов из k8s можно упростить создание новых namespace: для этого вводится проект - аналог namespace в Openshift. https://docs.openshift.com/container-platform/4.8/rest_api/project_apis/project-apis-index.html
6) самое интересное - концепция build-related ресурсов. Идея в том, что при изменении исходников или появлении нового образа в Docker происходит автоматическая сборка и установка новой версии приложения. Т.е. фактически мы получаем встроенный в кластер CI\CD.
https://docs.openshift.com/container-platform/4.10/cicd/index.html
https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/buildconfig-build-openshift-io-v1.html
Данная концепция приводит к тому, что стандартный ресурс Deployment в Openshift заменяется на очень похожий DeploymentConfig, поддерживающий пересоздание подов при появлении нового кода https://docs.openshift.com/container-platform/4.8/rest_api/workloads_apis/deploymentconfig-apps-openshift-io-v1.html
7) само собой новая веб-консоль и новая CLI утилита (oc), поддерживающие все вышеописанные возможности.
Вот пожалуй и все основные отличия Openshift. В целом неплохо, хотя и не так революционно, как Istio
#openshift #istio #cloud #k8s
Telegram
(java || kotlin) && devOps
Чем kubernetes, он же k8s лучше контейнера сервлетов или сервера приложений.
Во-первых под капотом k8s лежит Docker, а значит мы получаем все его плюшки. Не зря k8s называют оркестратором контейнеров. Чем занимается оркестратор?
1) планированиеи ресурсов.…
Во-первых под капотом k8s лежит Docker, а значит мы получаем все его плюшки. Не зря k8s называют оркестратором контейнеров. Чем занимается оркестратор?
1) планированиеи ресурсов.…
Всем привет!
Вопрос на собесе для джуна - что будет, если в Java число разделить на ноль?
А если это число с плавающей точкой?
Или все-таки это вопрос не для джуна, а со звездочкой... )))
Детали: https://www.baeldung.com/java-division-by-zero
А если говорить про задачи на собес - то можно вот такую: https://habr.com/ru/articles/573080/
P.S. Обратите внимание на автора блога.
P.P.S. На самом деле мне не очень нравятся задачи такого рода, т.к. такие вещи нужно просто знать. А главный вопрос - а нужно ли знать? Подозреваю, что 80% разработчиков с таким кейсом не столкнется в своей работе.
#java #trics
Вопрос на собесе для джуна - что будет, если в Java число разделить на ноль?
А если это число с плавающей точкой?
Или все-таки это вопрос не для джуна, а со звездочкой... )))
Детали: https://www.baeldung.com/java-division-by-zero
А если говорить про задачи на собес - то можно вот такую: https://habr.com/ru/articles/573080/
P.S. Обратите внимание на автора блога.
P.P.S. На самом деле мне не очень нравятся задачи такого рода, т.к. такие вещи нужно просто знать. А главный вопрос - а нужно ли знать? Подозреваю, что 80% разработчиков с таким кейсом не столкнется в своей работе.
#java #trics
Baeldung
Division by Zero in Java: Exception, Infinity, or Not a Number | Baeldung
When dividing by zero, integer division always throws an Exception. This is not the case with floating-point numbers, however. Let's see why.
Всем привет!
Формат yaml все больше входит в нашу жизнь, самые очевидные примеры - k8s, Docker Compose и Ansible.
Его главным преимуществом я считаю ссылки - соблюдается принцип DRY.
Главным недостатком - зависимость от числа tab\пробелов как в Python.
А чтобы не дать лишнему пробелу все сломать - нужна валидация.
Для начала - валидация синтаксиса https://yamllint.readthedocs.io/en/stable/index.html
Хотя в списке ОС для скачивания нет Windows - он ставится на Win с помощью python + pip.
Также есть плагин для IDEA https://plugins.jetbrains.com/plugin/15349-yamllint
Да, подсветка синтаксиса хотя и не заменяет валидацию, но тоже полезна - IDEA, Notepad++ и Atom поддерживают его из коробки.
Далее можно прикрутить валидацию, специфичную для конкретной области применения.
Для k8s есть утилиты kubeval, kube-score и Polaris см. https://habr.com/ru/companies/flant/articles/511018/
Они проверяют манифесты на соответствие best practices.
В docker-compose валидация вызывается с помощью команды https://docs.docker.com/engine/reference/commandline/compose_config/
Для Ansible - базовые проверки встроены в Ansible, также есть ansible-lint, детали см. https://www.deploymastery.com/2023/03/31/how-to-verify-ansible-playbook-syntax/
Альтернатива - написать нужные проверки самому. Тут есть 4 библиотеки из уже приведенной выше статьи:
config-lint, copper, conftest, Polaris
https://habr.com/ru/companies/flant/articles/511018/ Основное различие - в языке, на котором будет ваш код проверки. Есть и декларативный yaml, есть и императивный JS.
#yaml #k8s #ansible #docker-compose #validation
Формат yaml все больше входит в нашу жизнь, самые очевидные примеры - k8s, Docker Compose и Ansible.
Его главным преимуществом я считаю ссылки - соблюдается принцип DRY.
Главным недостатком - зависимость от числа tab\пробелов как в Python.
А чтобы не дать лишнему пробелу все сломать - нужна валидация.
Для начала - валидация синтаксиса https://yamllint.readthedocs.io/en/stable/index.html
Хотя в списке ОС для скачивания нет Windows - он ставится на Win с помощью python + pip.
Также есть плагин для IDEA https://plugins.jetbrains.com/plugin/15349-yamllint
Да, подсветка синтаксиса хотя и не заменяет валидацию, но тоже полезна - IDEA, Notepad++ и Atom поддерживают его из коробки.
Далее можно прикрутить валидацию, специфичную для конкретной области применения.
Для k8s есть утилиты kubeval, kube-score и Polaris см. https://habr.com/ru/companies/flant/articles/511018/
Они проверяют манифесты на соответствие best practices.
В docker-compose валидация вызывается с помощью команды https://docs.docker.com/engine/reference/commandline/compose_config/
Для Ansible - базовые проверки встроены в Ansible, также есть ansible-lint, детали см. https://www.deploymastery.com/2023/03/31/how-to-verify-ansible-playbook-syntax/
Альтернатива - написать нужные проверки самому. Тут есть 4 библиотеки из уже приведенной выше статьи:
config-lint, copper, conftest, Polaris
https://habr.com/ru/companies/flant/articles/511018/ Основное различие - в языке, на котором будет ваш код проверки. Есть и декларативный yaml, есть и императивный JS.
#yaml #k8s #ansible #docker-compose #validation
JetBrains Marketplace
Yamllint - IntelliJ IDEs Plugin | Marketplace
Provides static code analysis of Yaml files through integration with Yamllint. Enable and configure it in the Preferences > Tools > Yamllint.
Всем привет!
С большой вероятностью не ошибусь, если скажу, что большинство разработчиков не любит работать с legacy. Вижу это в резюме, сталкиваюсь с этим периодически на собеседованиях.
Почему? Там много кода, код непонятный, разбираться долго, нет новых технологий, есть куча правил, которые так просто не нарушишь...
А есть ли плюсы в работе с legacy?
Я как человек, примерно половину своей карьеры плотно работавший с legacy, могу сказать - да, есть.
Плюсы такие:
1) если речь идет не про поддержку, а про глубокий рефакторинг, то распилить legacy на микросервисы - это сложная архитектурная задача. Решив ее, получаешь опыт проектирования возможно даже больший, чем при создании этих сервисов с нуля. И этот опыт можно хорошо продать
2) не все legacy = го...код. Возможно все начиналось с хорошо спроектированного небольшого приложения, которое вовремя не разделили на части. Либо не хватало времени, либо не было необходимости. В таком случае в legacy приложении, особенно если оно достаточно большое, можно подсмотреть доказавшие свою полезность паттерны и архитектурные решения. А именно умение проектировать и наработанные паттерны являются основным преимуществом разработчика. Технологии меняются и их всегда можно доучить.
3) я достаточно много писал и буду писать о том, как важна читаемость кода, его компактность и в конечном итоге снижение когнитивной нагрузки при работе с кодом. Казалось бы это не про типичный legacy. В целом да. Но если все же научится "переваривать" большие объемы кода - это будет еще одним плюсом в копилку полезных навыков разработчика. Т.к. есть теория про "чистый код", а, увы, есть суровая практика. И "бизнес" любит людей, которые могут решить любую проблему, в т.ч. и с legacy.
4) любой сервис становится legacy. Поэтому отказываясь работать с legacy - сужаешь список своих возможностей. На растущем рынке это не критично, но всегда ли он будет так расти?
#legacy #skills
С большой вероятностью не ошибусь, если скажу, что большинство разработчиков не любит работать с legacy. Вижу это в резюме, сталкиваюсь с этим периодически на собеседованиях.
Почему? Там много кода, код непонятный, разбираться долго, нет новых технологий, есть куча правил, которые так просто не нарушишь...
А есть ли плюсы в работе с legacy?
Я как человек, примерно половину своей карьеры плотно работавший с legacy, могу сказать - да, есть.
Плюсы такие:
1) если речь идет не про поддержку, а про глубокий рефакторинг, то распилить legacy на микросервисы - это сложная архитектурная задача. Решив ее, получаешь опыт проектирования возможно даже больший, чем при создании этих сервисов с нуля. И этот опыт можно хорошо продать
2) не все legacy = го...код. Возможно все начиналось с хорошо спроектированного небольшого приложения, которое вовремя не разделили на части. Либо не хватало времени, либо не было необходимости. В таком случае в legacy приложении, особенно если оно достаточно большое, можно подсмотреть доказавшие свою полезность паттерны и архитектурные решения. А именно умение проектировать и наработанные паттерны являются основным преимуществом разработчика. Технологии меняются и их всегда можно доучить.
3) я достаточно много писал и буду писать о том, как важна читаемость кода, его компактность и в конечном итоге снижение когнитивной нагрузки при работе с кодом. Казалось бы это не про типичный legacy. В целом да. Но если все же научится "переваривать" большие объемы кода - это будет еще одним плюсом в копилку полезных навыков разработчика. Т.к. есть теория про "чистый код", а, увы, есть суровая практика. И "бизнес" любит людей, которые могут решить любую проблему, в т.ч. и с legacy.
4) любой сервис становится legacy. Поэтому отказываясь работать с legacy - сужаешь список своих возможностей. На растущем рынке это не критично, но всегда ли он будет так расти?
#legacy #skills
Всем привет!
Пару слов про отладку тестов, на примере Maven проекта и IDEA.
Если речь про модульные тесты - там проблем нет, ставим breakpoint и запускаем нужный тест в IDEA.
Проблемы есть с интеграционными тестами. Т.к.
1) тесты и код, который тестируем, запускаются в разных процессах
2) обычно интеграционные тесты запускаются с помощью Maven (Gradle), т.к. нужно поднять окружение, и проще и правильнее эти настройки один раз сделать в Maven и забыть.
Какие у нас варианты с отладкой?
1) вариант, описанный тут https://stackoverflow.com/questions/49390110/how-to-debug-integration-test-in-intellij
Если вкратце - запускаем тесты с помощью Maven в специальном отладочном режиме плагина failsafe (или surefire), потом подключаемся к процессу из IDEA в режиме удаленной отладки. Отладка называется удаленной, т.к. нужно подключаться к другому процессу. В данном случае на localhost.
2) запускаем наш сервис в "DEV режиме" через Maven. Также, как это делается для отладки кода и проверки функционала локально вручную. Обычно под это дело в проекте есть отдельный профиль Maven. После этого запускаем нужный интеграционный тест в Debug режиме из IDEA, из окна с кодом теста. Как минимум, интеграционные тесты Cucumber и Spring Boot IDEA поддерживает.
3) а что, если нужно поставить точку прерывания в коде сервиса, а не тестов? Тогда настаиваем в IDEA Run configuration для нашего контейнера сервлетов \ сервера приложений. Запускаем ее в DEBUG режиме, после чего запускаем тесты также, как и в предыдущем варианте.
Варианты 2 и 3 мне нравятся больше, т.к. не нужно использовать консоль - все делается средствами IDEA.
#debug #java #tests #integration-tests
Пару слов про отладку тестов, на примере Maven проекта и IDEA.
Если речь про модульные тесты - там проблем нет, ставим breakpoint и запускаем нужный тест в IDEA.
Проблемы есть с интеграционными тестами. Т.к.
1) тесты и код, который тестируем, запускаются в разных процессах
2) обычно интеграционные тесты запускаются с помощью Maven (Gradle), т.к. нужно поднять окружение, и проще и правильнее эти настройки один раз сделать в Maven и забыть.
Какие у нас варианты с отладкой?
1) вариант, описанный тут https://stackoverflow.com/questions/49390110/how-to-debug-integration-test-in-intellij
Если вкратце - запускаем тесты с помощью Maven в специальном отладочном режиме плагина failsafe (или surefire), потом подключаемся к процессу из IDEA в режиме удаленной отладки. Отладка называется удаленной, т.к. нужно подключаться к другому процессу. В данном случае на localhost.
2) запускаем наш сервис в "DEV режиме" через Maven. Также, как это делается для отладки кода и проверки функционала локально вручную. Обычно под это дело в проекте есть отдельный профиль Maven. После этого запускаем нужный интеграционный тест в Debug режиме из IDEA, из окна с кодом теста. Как минимум, интеграционные тесты Cucumber и Spring Boot IDEA поддерживает.
3) а что, если нужно поставить точку прерывания в коде сервиса, а не тестов? Тогда настаиваем в IDEA Run configuration для нашего контейнера сервлетов \ сервера приложений. Запускаем ее в DEBUG режиме, после чего запускаем тесты также, как и в предыдущем варианте.
Варианты 2 и 3 мне нравятся больше, т.к. не нужно использовать консоль - все делается средствами IDEA.
#debug #java #tests #integration-tests
Stack Overflow
How to debug integration test in IntelliJ?
I have created run configuration in Maven Projects for
mvn -Dit.test=PredictionWorkflowTest verify
which looks like here
and then set breakpoint inside PredictionWorkflowTest. Unfortunately, whe...
mvn -Dit.test=PredictionWorkflowTest verify
which looks like here
and then set breakpoint inside PredictionWorkflowTest. Unfortunately, whe...
Всем привет!
Продолжая тему Maven. Когда я изучал документацию по Maven, то наткнулся такую несколько странную возможность, как отключение компиляции через опцию -Dmaven.main.skip.
Почему, зачем? На первый взгляд - бессмысленно.
Но недавно на практике понял зачем она нужна.
Предположим в вашем pom есть некий плагин с достаточно сложными нестандартными настройками. Есть процесс, в котором нужно выполнить его goal. Если мы просто запустим goal командой mvn plugin:version:goal, то настройки из pom будут проигнорированы. Предположим, задать их из командной строки невозможно, т.к. плагин это не поддерживает. А даже если возможно - это будет дублирование, нарушение DRY, т.е. тоже плохой вариант)
Хуже всего то, что наш плагин находится в build lifecycle https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference после фазы compile. Пусть проект уже собран, но как известно инкрементальная компиляция в Maven существует, но с ней есть нюансы: https://stackoverflow.com/questions/16963012/maven-compiler-recompile-all-files-instead-modified/19653164#19653164
К слову - именно по скорости компиляции Maven сильно проигрывает Gradle.
Так вот - именно тут опция -Dmaven.main.skip и выходит на сцену, сильно уменьшая время выполнения.
P.S. Да, по моему опыту - плагин для компиляции Kotlin, увы, ее не поддерживает.
#maven #java #kotlin
Продолжая тему Maven. Когда я изучал документацию по Maven, то наткнулся такую несколько странную возможность, как отключение компиляции через опцию -Dmaven.main.skip.
Почему, зачем? На первый взгляд - бессмысленно.
Но недавно на практике понял зачем она нужна.
Предположим в вашем pom есть некий плагин с достаточно сложными нестандартными настройками. Есть процесс, в котором нужно выполнить его goal. Если мы просто запустим goal командой mvn plugin:version:goal, то настройки из pom будут проигнорированы. Предположим, задать их из командной строки невозможно, т.к. плагин это не поддерживает. А даже если возможно - это будет дублирование, нарушение DRY, т.е. тоже плохой вариант)
Хуже всего то, что наш плагин находится в build lifecycle https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference после фазы compile. Пусть проект уже собран, но как известно инкрементальная компиляция в Maven существует, но с ней есть нюансы: https://stackoverflow.com/questions/16963012/maven-compiler-recompile-all-files-instead-modified/19653164#19653164
К слову - именно по скорости компиляции Maven сильно проигрывает Gradle.
Так вот - именно тут опция -Dmaven.main.skip и выходит на сцену, сильно уменьшая время выполнения.
P.S. Да, по моему опыту - плагин для компиляции Kotlin, увы, ее не поддерживает.
#maven #java #kotlin
maven.apache.org
Introduction to the Build Lifecycle – Maven
Всем привет! Мне нравится идея сделать пошаговый гайд по разбору ошибок при деплое в k8s - https://habr.com/ru/companies/flant/articles/484954/ Жаль, что тут чистый кубер, без Istio. Но представляю, во что превратится схема, если добавить туда Istio ))) #k8s #istio
Хабр
Визуальное руководство по диагностике неисправностей в Kubernetes
Прим. перев. : Эта статья входит в состав опубликованных в свободном доступе материалов проекта learnk8s , обучающего работе с Kubernetes компании и индивидуальных администраторов. В ней Daniele...
Всем привет!
Я периодически провожу код-ревью. И лично у меня ранее был страх - а вдруг я не замечу что-то важное. Смотришь PR, явных ошибок не видно, но апрув "не ставится". А когда Pull Request (PR) очень большой - даже не хочется его открывать, т.к. примерно понимаешь, какой объем информации придется "загрузить в голову", чтобы точно можно было сказать - да, здесь ошибок нет. Крайний случай слишком тщательного подхода к код-ревью, встреченный мной на практике - когда разработчик просит освободить его от других задач, чтобы он мог полностью погрузиться в ревью: прочитать аналитику, изучить архитектуру кода...
Но как я уже писал в https://t.me/javaKotlinDevOps/146 - скорость прохождения код-ревью очень важна для быстрого выявления ошибок и предотвращения merge конфликтов. Что же тут можно сделать?
Во-первых я предлагаю рассматривать код-ревью как еще одну из сетей для поиска проблем в коде. Есть и другие сети - валидация в IDEA, модульные и интеграционные тесты, CI pipeline, SonarQube и другие инструменты статистического анализа, включая сканирования на уязвимости. Это если говорить о тех, что работают до код-ревью. После - регресс, тесты нового функционала, нагрузочное тестирование, демо (приемо-сдаточные испытания), канареечное развертывание, chaos engineering... Т.е. код-ревью - полезно, но это не последний рубеж обороны.
Второй момент: когда я провожу ревью - я вижу те проблемы, которые считаю важным. Т.е. мой взгляд субъективен, на него влияет мой опыт, и особенно проблемы, с которыми я сталкивался ранее. Да, важно то, что мой взгляд отличается от взгляда автора кода. Это позволяет найти те ошибки, которые автор из-за замыленности не увидел. Но с другой стороны - что-то я в принципе увидеть не могу. В этом плане будет полезно иметь несколько ревьюверов, внутри и кросс командное ревью.
Итого: ручное код-ревью полезно, к нему не стоит подходить формально, но не надо забывать про время. Исключения - когда время не критично. Например, это ревью кода новичков. Там важно передать текущие практики и требования к проекту.
#code_review
Я периодически провожу код-ревью. И лично у меня ранее был страх - а вдруг я не замечу что-то важное. Смотришь PR, явных ошибок не видно, но апрув "не ставится". А когда Pull Request (PR) очень большой - даже не хочется его открывать, т.к. примерно понимаешь, какой объем информации придется "загрузить в голову", чтобы точно можно было сказать - да, здесь ошибок нет. Крайний случай слишком тщательного подхода к код-ревью, встреченный мной на практике - когда разработчик просит освободить его от других задач, чтобы он мог полностью погрузиться в ревью: прочитать аналитику, изучить архитектуру кода...
Но как я уже писал в https://t.me/javaKotlinDevOps/146 - скорость прохождения код-ревью очень важна для быстрого выявления ошибок и предотвращения merge конфликтов. Что же тут можно сделать?
Во-первых я предлагаю рассматривать код-ревью как еще одну из сетей для поиска проблем в коде. Есть и другие сети - валидация в IDEA, модульные и интеграционные тесты, CI pipeline, SonarQube и другие инструменты статистического анализа, включая сканирования на уязвимости. Это если говорить о тех, что работают до код-ревью. После - регресс, тесты нового функционала, нагрузочное тестирование, демо (приемо-сдаточные испытания), канареечное развертывание, chaos engineering... Т.е. код-ревью - полезно, но это не последний рубеж обороны.
Второй момент: когда я провожу ревью - я вижу те проблемы, которые считаю важным. Т.е. мой взгляд субъективен, на него влияет мой опыт, и особенно проблемы, с которыми я сталкивался ранее. Да, важно то, что мой взгляд отличается от взгляда автора кода. Это позволяет найти те ошибки, которые автор из-за замыленности не увидел. Но с другой стороны - что-то я в принципе увидеть не могу. В этом плане будет полезно иметь несколько ревьюверов, внутри и кросс командное ревью.
Итого: ручное код-ревью полезно, к нему не стоит подходить формально, но не надо забывать про время. Исключения - когда время не критично. Например, это ревью кода новичков. Там важно передать текущие практики и требования к проекту.
#code_review
Telegram
(java || kotlin) && devOps
Всем привет!
Продолжаю тему code review, поговорим про рекомендации ревьюверам.
1) работа с PR - это как правило текстовая коммуникация: Bitbucket, Gitlab, ... При таком общении теряется часть информации - тон, эмоциональная окраска... Следовательно, фразу…
Продолжаю тему code review, поговорим про рекомендации ревьюверам.
1) работа с PR - это как правило текстовая коммуникация: Bitbucket, Gitlab, ... При таком общении теряется часть информации - тон, эмоциональная окраска... Следовательно, фразу…
Всем привет!
Большинство Java разработчиков знают про Mockito - самый популярный фреймворк для создания заглушек. Но не ошибусь, если скажу, что большая часть разработчиков также не любит читать документацию) В т.ч. Mockito. А используемые инструменты надо знать.
Поэтому могу порекомендовать отличную статью про Mockito https://habr.com/ru/articles/444982/
Для затравки - из статьи можно узнать:
1) как определить - mock это или нет
2) в чем разница между when и do, когда все же нужен do
3) как одной лямбдой сделать сложную проверку входных параметров в конструкции when
4) как проверить порядок вызова методов
5) про сессии Mockito
и много других интересных особенностей фреймворка.
#mockito #java #unittests
Большинство Java разработчиков знают про Mockito - самый популярный фреймворк для создания заглушек. Но не ошибусь, если скажу, что большая часть разработчиков также не любит читать документацию) В т.ч. Mockito. А используемые инструменты надо знать.
Поэтому могу порекомендовать отличную статью про Mockito https://habr.com/ru/articles/444982/
Для затравки - из статьи можно узнать:
1) как определить - mock это или нет
2) в чем разница между when и do, когда все же нужен do
3) как одной лямбдой сделать сложную проверку входных параметров в конструкции when
4) как проверить порядок вызова методов
5) про сессии Mockito
и много других интересных особенностей фреймворка.
#mockito #java #unittests
Хабр
Mockito и как его готовить
О статье Перед вами очередное руководство по Mockito. В нём я, с одной стороны, попытался описать функционал этой библиотеки так, чтобы незнакомый с нею читатель сразу получил возможность полноценно...
Всем привет!
Уже был пост о том, как не надо использовать контекстные функции в Kotlin https://t.me/javaKotlinDevOps/189
Сразу может возникнуть вопрос - а когда их стоит использовать?
По ссылке уже был пример - для установки полей объекта, которые нельзя установить через конструктор. То ли потому, что подходящего конструктора\builder нет, то ли потому, что в момент создания объекта их значения еще не известны. Вот он:
val man = Person("Vasya").apply {
age = 20
city = "Moscow"
}
К слову - эту задачу можно было решить лет 20 назад в Delphi с помощью оператора with, мне его очень не хватало в Java))) И интересно, что в Kotlin with немного отличается по смыслу: https://kotlinlang.org/docs/scope-functions.html#function-selection
Еще кейс - выполнение какого-то нефункционального требования или вспомогательного кода, типа отбрасывания логов, метрик:
return claim.also {
log.info("Возвращаем $claim")
}
Ключевой момент здесь, о котором я буду постоянно говорить - код логично выстроен и легко читается: возвращаем объект заявки, а заодно его логируем.
И еще кейс - функция однострочник, без явного тела. Ключевой момент - это реально должна быть функция из одной или нескольких строк. Если сделать портянку из цепочки вызовов контекстных функций - читаемость только ухудшится, лучше бы были скобки.
Пример как надо:
fun main() = doSomething().also { doAnotherThing(it) }
Если подкинете еще хорошие примеры в комментариях - буду благодарен.
#kotlin #readability
Уже был пост о том, как не надо использовать контекстные функции в Kotlin https://t.me/javaKotlinDevOps/189
Сразу может возникнуть вопрос - а когда их стоит использовать?
По ссылке уже был пример - для установки полей объекта, которые нельзя установить через конструктор. То ли потому, что подходящего конструктора\builder нет, то ли потому, что в момент создания объекта их значения еще не известны. Вот он:
val man = Person("Vasya").apply {
age = 20
city = "Moscow"
}
К слову - эту задачу можно было решить лет 20 назад в Delphi с помощью оператора with, мне его очень не хватало в Java))) И интересно, что в Kotlin with немного отличается по смыслу: https://kotlinlang.org/docs/scope-functions.html#function-selection
Еще кейс - выполнение какого-то нефункционального требования или вспомогательного кода, типа отбрасывания логов, метрик:
return claim.also {
log.info("Возвращаем $claim")
}
Ключевой момент здесь, о котором я буду постоянно говорить - код логично выстроен и легко читается: возвращаем объект заявки, а заодно его логируем.
И еще кейс - функция однострочник, без явного тела. Ключевой момент - это реально должна быть функция из одной или нескольких строк. Если сделать портянку из цепочки вызовов контекстных функций - читаемость только ухудшится, лучше бы были скобки.
Пример как надо:
fun main() = doSomething().also { doAnotherThing(it) }
Если подкинете еще хорошие примеры в комментариях - буду благодарен.
#kotlin #readability
Telegram
(java || kotlin) && devOps
Всем привет!
Есть такая отличная штука в Kotlin, как контекстные функции.
Вот документация https://kotlinlang.org/docs/scope-functions.html
Вот пример, хорошо иллюстрирующий зачем они нужны:
val man = Person("Vasya").apply {
age = 20 …
Есть такая отличная штука в Kotlin, как контекстные функции.
Вот документация https://kotlinlang.org/docs/scope-functions.html
Вот пример, хорошо иллюстрирующий зачем они нужны:
val man = Person("Vasya").apply {
age = 20 …
Всем привет!
Нашел полезную штуку - калькулятор сайзинга для Kafka - https://eventsizer.io/
P.S. Новый тэг - #utils
Нашел полезную штуку - калькулятор сайзинга для Kafka - https://eventsizer.io/
P.S. Новый тэг - #utils
Всем привет!
Хочу рассказать про наверное самый способ улучшить читаемость. Например, у вас есть сложное условие из нескольких уровней, каждый из которых состоит из ряда проверок. Или длинный метод с кучей условий, который сложно понять и на который справедливо ругается SonarQube.
Решение такое - выделяем атомарные блоки кода или условия в отдельные private методы.
К слову, данный способ является одним из базовых рефакторингов под названием "extract method" из известной книжки Фаулера "Рефакторинг".
Может возникнуть вопрос - а если метод вызывается один раз?
Ответ - без разницы.
У нас есть умный компилятор, он должен такие методы заинлайнить. Сразу скажу, спецификации, подтверждающей этот факт я предоставить не могу)
Окей, но даже если вам не повезет, и ваш компилятор этого не сделает - нужно иметь RPS (request per second) сильно больше 1, чтобы лишние вызовы метода сыграли свою роль. Причем даже в таком случае длинная цепочка вызовов методов должна быть в основном сценарии. Кажется, что под эти три условия попадает не так много кода. И в любом случае у нас есть НТ.
Еще может возникнуть вопрос с unit tests - их число тоже нужно увеличивать? Ответ - не обязательно, нет жесткой связки 1 к 1 теста и метода. Тест можно написать на группу взаимосвязанных методов, главное закрыть все возможные пути выполнения кода. Да и не нужно тестировать private методы.
И еще важный момент - extract method позволяет решить еще один часто встречающийся кейс. Предположим у вас есть дублирующийся код, отличающийся только одним небольшим блоком. Решение навскидку (на Kotlin):
fun doSomething(booleanParam: Boolean): SomeResult {
if (booleanParam) {
doAnotherThing()
}
// some code
}
Но приходится вводить Boolean параметр, а это хоть и не общепризнанный антипаттерн, по этому вопросу идут hollywars, но приближается к этому статусу)
Поэтому можно сделать так:
fun doSomething(): SomeResult {
// some code
}
fun doSomethingExtended(): SomeResult {
doAnotherThing()
return doSomething()
}
Итог: не нужно боятся выделять новые методы.
#refactoring #readability #antipatterns
Хочу рассказать про наверное самый способ улучшить читаемость. Например, у вас есть сложное условие из нескольких уровней, каждый из которых состоит из ряда проверок. Или длинный метод с кучей условий, который сложно понять и на который справедливо ругается SonarQube.
Решение такое - выделяем атомарные блоки кода или условия в отдельные private методы.
К слову, данный способ является одним из базовых рефакторингов под названием "extract method" из известной книжки Фаулера "Рефакторинг".
Может возникнуть вопрос - а если метод вызывается один раз?
Ответ - без разницы.
У нас есть умный компилятор, он должен такие методы заинлайнить. Сразу скажу, спецификации, подтверждающей этот факт я предоставить не могу)
Окей, но даже если вам не повезет, и ваш компилятор этого не сделает - нужно иметь RPS (request per second) сильно больше 1, чтобы лишние вызовы метода сыграли свою роль. Причем даже в таком случае длинная цепочка вызовов методов должна быть в основном сценарии. Кажется, что под эти три условия попадает не так много кода. И в любом случае у нас есть НТ.
Еще может возникнуть вопрос с unit tests - их число тоже нужно увеличивать? Ответ - не обязательно, нет жесткой связки 1 к 1 теста и метода. Тест можно написать на группу взаимосвязанных методов, главное закрыть все возможные пути выполнения кода. Да и не нужно тестировать private методы.
И еще важный момент - extract method позволяет решить еще один часто встречающийся кейс. Предположим у вас есть дублирующийся код, отличающийся только одним небольшим блоком. Решение навскидку (на Kotlin):
fun doSomething(booleanParam: Boolean): SomeResult {
if (booleanParam) {
doAnotherThing()
}
// some code
}
Но приходится вводить Boolean параметр, а это хоть и не общепризнанный антипаттерн, по этому вопросу идут hollywars, но приближается к этому статусу)
Поэтому можно сделать так:
fun doSomething(): SomeResult {
// some code
}
fun doSomethingExtended(): SomeResult {
doAnotherThing()
return doSomething()
}
Итог: не нужно боятся выделять новые методы.
#refactoring #readability #antipatterns
Всем привет!
У каждого разработчика есть набор любимых инструментов. И на самом деле это важно - инструменты сильно облегчают нам жизнь. И если рассматривать разработку как ремесло, то правильные инструменты - это конкурентное преимущество.
Исторически так сложилось, что я работаю на Windows. Mac просто не зашел.
Поэтому решил поделится своим набором инструментов под Windows.
На первом месте безусловно IntelliJ IDEA. Я бы сказал, что ее хватает для 80% задач разработчика. Более того, хорошо видно, что разработчики IDEA работают над тем, чтобы эта цифра приблизилась к 100))))
Но на текущий момент IDEA - не только лишь наше все) Как я уже писал - кроме собственно написания кода, предположим на Java, разработчик сталкивается с рядом сопутствующих задач - https://t.me/javaKotlinDevOps/26 и https://t.me/javaKotlinDevOps/26.
И для них нужны свои инструменты, которых нет в IDEA.
Notepad++ - для работы с текстовыми файлами и файлами настроек. Намного круче редактора IDEA, особенно с плагинами.
Total Commander - работа с файловой системой. Альтернатива - Far, но лично я не люблю UI из DOS )))
KeePass - хранение и обмен паролями.
RegexBuddy - отладка RegEx выражений.
Официальный Git клиент - для работы с репозиториями, не содержащими код. Также для клонирования новых репозиториев. Если удобнее работать из контекстного меню - есть TortoiseGit.
Linux утилиты в Windows. Без Linux никак, да) Есть два порта утилит Linux для Windows - Cygwin и MinGw, последний входит в состав дистрибутива Git. Что как по мне удобно - два в одном.
WinSCP, Putty, MTPutty - доступ по ssh для настройки серверов и просмотра логов. Замечу, что после перехода на Docker уже не так актуально.
Postman, Insomnia, SoapUI - тестирование http. Встроенный в IDEA http client подходит для простых случаев - когда не требуются проверки, сложная настройка кук, сред, переменных...
JMeter - нагрузочное тестирование по http.
Keystore Explorer - работа с SSL сертификатами.
Beyond Compare - сравнение файлов и каталогов. Для простых случаев хватает инструментов, встроенных в Total Commander.
Docker Desktop или VirtualBox плюс WSL (Windows subsystem for Linux) - для запуска Docker.
DBeaver, EMS SQL Manager, Navicat - если вам не хватает IDEA Database tools. Мне сейчас хватает))) Но раньше использовал все три, все три нравятся.
Менеджер буфера обмена, например ArsClip. Для работы вне IDEA,в IDEA уже есть работа с буфером обмена.
Работа с заметками. Лично я пользуюсь Evernote. Как альтернатива - OneNote. Еще альтернатива - Telegram канал, куда можно сбрасывать все заметки и расставлять тэги)))
WinRar или 7Zip - архивирование. Сейчас уже не так актуально, диски у нас условно безразмерные, но для отправки по почте - бывает нужно.
Отладчик Google Chrome или Yandex Browser (по вкусу).
kubectl или oc - клиент для работы с k8s или Openshift
Работающий VPN - для работы с тем же ChatGPT.
P.S На самом деле эта заметка преследует скрытую цель - узнать что-то новое. Если вы используете что-то полезное для разработки, а я о нем забыл, не знал - напиши, плиз, в комментах.
#tools #windows
У каждого разработчика есть набор любимых инструментов. И на самом деле это важно - инструменты сильно облегчают нам жизнь. И если рассматривать разработку как ремесло, то правильные инструменты - это конкурентное преимущество.
Исторически так сложилось, что я работаю на Windows. Mac просто не зашел.
Поэтому решил поделится своим набором инструментов под Windows.
На первом месте безусловно IntelliJ IDEA. Я бы сказал, что ее хватает для 80% задач разработчика. Более того, хорошо видно, что разработчики IDEA работают над тем, чтобы эта цифра приблизилась к 100))))
Но на текущий момент IDEA - не только лишь наше все) Как я уже писал - кроме собственно написания кода, предположим на Java, разработчик сталкивается с рядом сопутствующих задач - https://t.me/javaKotlinDevOps/26 и https://t.me/javaKotlinDevOps/26.
И для них нужны свои инструменты, которых нет в IDEA.
Notepad++ - для работы с текстовыми файлами и файлами настроек. Намного круче редактора IDEA, особенно с плагинами.
Total Commander - работа с файловой системой. Альтернатива - Far, но лично я не люблю UI из DOS )))
KeePass - хранение и обмен паролями.
RegexBuddy - отладка RegEx выражений.
Официальный Git клиент - для работы с репозиториями, не содержащими код. Также для клонирования новых репозиториев. Если удобнее работать из контекстного меню - есть TortoiseGit.
Linux утилиты в Windows. Без Linux никак, да) Есть два порта утилит Linux для Windows - Cygwin и MinGw, последний входит в состав дистрибутива Git. Что как по мне удобно - два в одном.
WinSCP, Putty, MTPutty - доступ по ssh для настройки серверов и просмотра логов. Замечу, что после перехода на Docker уже не так актуально.
Postman, Insomnia, SoapUI - тестирование http. Встроенный в IDEA http client подходит для простых случаев - когда не требуются проверки, сложная настройка кук, сред, переменных...
JMeter - нагрузочное тестирование по http.
Keystore Explorer - работа с SSL сертификатами.
Beyond Compare - сравнение файлов и каталогов. Для простых случаев хватает инструментов, встроенных в Total Commander.
Docker Desktop или VirtualBox плюс WSL (Windows subsystem for Linux) - для запуска Docker.
DBeaver, EMS SQL Manager, Navicat - если вам не хватает IDEA Database tools. Мне сейчас хватает))) Но раньше использовал все три, все три нравятся.
Менеджер буфера обмена, например ArsClip. Для работы вне IDEA,в IDEA уже есть работа с буфером обмена.
Работа с заметками. Лично я пользуюсь Evernote. Как альтернатива - OneNote. Еще альтернатива - Telegram канал, куда можно сбрасывать все заметки и расставлять тэги)))
WinRar или 7Zip - архивирование. Сейчас уже не так актуально, диски у нас условно безразмерные, но для отправки по почте - бывает нужно.
Отладчик Google Chrome или Yandex Browser (по вкусу).
kubectl или oc - клиент для работы с k8s или Openshift
Работающий VPN - для работы с тем же ChatGPT.
P.S На самом деле эта заметка преследует скрытую цель - узнать что-то новое. Если вы используете что-то полезное для разработки, а я о нем забыл, не знал - напиши, плиз, в комментах.
#tools #windows
Telegram
(java || kotlin) && devOps
Продолжим с hard-skills, не связанными с основным языком программирования.
7) базовые навыки DevOps. DevOps есть в любой более менее современной компании. Любой разработчик с ним соприкасается. Понимать основы надо.
Что я понимаю под основами: зачем вообще…
7) базовые навыки DevOps. DevOps есть в любой более менее современной компании. Любой разработчик с ним соприкасается. Понимать основы надо.
Что я понимаю под основами: зачем вообще…
Всем привет!
Я уже поднимал тему boolean параметров как антипаттерна https://t.me/javaKotlinDevOps/229. Давайте расширим ее до вопроса - когда стоит использовать if?
Является ли if антипаттерном?
По мнению некоторых товарищей - да, является: https://www.antiifprogramming.com/about-the-anti-if.php
Как по мне - не всегда, зависит от ситуации.
Чем плох if? // да, switch - это по сути тот же if.
1) может нарушать принцип Single Responsibility. Почему - думаю объяснять не нужно.
2) может ухудшать читаемость кода, я которую я всегда "топлю") Т.е. нарушает принцип KISS. Усугубляет ситуацию тот факт, что код как правило не остается неизменным. И обычный if else со временем может превратится в многоуровневого нечитаемого монстра.
3) может нарушать принцип Don't Repeat Yourself. Тут два очевидных варианта - либо во всех ветках if выражения есть дублирующийся код, либо чтобы обработать возврат некого метода всегда нужен if.
4) если в коде слишком много if (x != null) - это признак того, что вы неправильно работаете с nullability. Тут могу посоветовать Kotlin, т.к. он может сообщать о null значениях на этапе компиляции. Optional и его альтернативы в Java избавляют от NPE, но не избавляет от проверок на null. Я видел советы - просто не пишите код, который возвращает null - тогда проверки будут не нужны. Но это надежда на человеческий фактор, и компилятор (я про Kotlin) работает лучше)))
Да, я специально пишу везде слово "может". Бывают if-ы, которые не нарушают ни один из принципов.
Когда стоит волноваться?
1) подключаем SonarQube или Checkstyle и не игнорируем ошибки, связанные с цикломатической сложностью методов, см. https://t.me/javaKotlinDevOps/197
2) код просто сложно становится читать. Особенно хорошо эта проверка проходит на новых разработчиках)
Идеально конечно не писать код, приводящий к лишним if. Но я уже писал про человеческий фактор выше)
Что можно сделать? // будет некоторый повтор написанного тут https://t.me/javaKotlinDevOps/229
1) выделяем сложный код условия в отдельный метод.
2) вместо двух или более веток оператора if делаем несколько методов. Помогает в случае, если условно метод А всегда вызывает метод С с значением true, а метод Б - с значением false. Иначе будет как на знаменитой картинке - проблема не на моей стороне)))
3) используем not null объекты и переходим Kotlin
4) перепроектируем код, чтобы проверки выполнялись в одном месте, а не дублировались по коду. Для этого их придется перенести из вызывающего кода в вызываемый. И придумать правильное значение по умолчанию.
5) при необходимости вводим иерархию классов, чтобы каждый класс отвечал за одну ветку switch
6) используем паттерн Стратегия - по сути частный случай введения иерархии классов
7) используем паттерн Состояние (State), который кроме хранения состояния выполняет обработку, связанную с различными состояниями, тем самым убирая if из вызывающего кода
#antipatterns #if_antipattern #java #kotlin #solid #patterns #dev_compromises
Я уже поднимал тему boolean параметров как антипаттерна https://t.me/javaKotlinDevOps/229. Давайте расширим ее до вопроса - когда стоит использовать if?
Является ли if антипаттерном?
По мнению некоторых товарищей - да, является: https://www.antiifprogramming.com/about-the-anti-if.php
Как по мне - не всегда, зависит от ситуации.
Чем плох if? // да, switch - это по сути тот же if.
1) может нарушать принцип Single Responsibility. Почему - думаю объяснять не нужно.
2) может ухудшать читаемость кода, я которую я всегда "топлю") Т.е. нарушает принцип KISS. Усугубляет ситуацию тот факт, что код как правило не остается неизменным. И обычный if else со временем может превратится в многоуровневого нечитаемого монстра.
3) может нарушать принцип Don't Repeat Yourself. Тут два очевидных варианта - либо во всех ветках if выражения есть дублирующийся код, либо чтобы обработать возврат некого метода всегда нужен if.
4) если в коде слишком много if (x != null) - это признак того, что вы неправильно работаете с nullability. Тут могу посоветовать Kotlin, т.к. он может сообщать о null значениях на этапе компиляции. Optional и его альтернативы в Java избавляют от NPE, но не избавляет от проверок на null. Я видел советы - просто не пишите код, который возвращает null - тогда проверки будут не нужны. Но это надежда на человеческий фактор, и компилятор (я про Kotlin) работает лучше)))
Да, я специально пишу везде слово "может". Бывают if-ы, которые не нарушают ни один из принципов.
Когда стоит волноваться?
1) подключаем SonarQube или Checkstyle и не игнорируем ошибки, связанные с цикломатической сложностью методов, см. https://t.me/javaKotlinDevOps/197
2) код просто сложно становится читать. Особенно хорошо эта проверка проходит на новых разработчиках)
Идеально конечно не писать код, приводящий к лишним if. Но я уже писал про человеческий фактор выше)
Что можно сделать? // будет некоторый повтор написанного тут https://t.me/javaKotlinDevOps/229
1) выделяем сложный код условия в отдельный метод.
2) вместо двух или более веток оператора if делаем несколько методов. Помогает в случае, если условно метод А всегда вызывает метод С с значением true, а метод Б - с значением false. Иначе будет как на знаменитой картинке - проблема не на моей стороне)))
3) используем not null объекты и переходим Kotlin
4) перепроектируем код, чтобы проверки выполнялись в одном месте, а не дублировались по коду. Для этого их придется перенести из вызывающего кода в вызываемый. И придумать правильное значение по умолчанию.
5) при необходимости вводим иерархию классов, чтобы каждый класс отвечал за одну ветку switch
6) используем паттерн Стратегия - по сути частный случай введения иерархии классов
7) используем паттерн Состояние (State), который кроме хранения состояния выполняет обработку, связанную с различными состояниями, тем самым убирая if из вызывающего кода
#antipatterns #if_antipattern #java #kotlin #solid #patterns #dev_compromises
Telegram
(java || kotlin) && devOps
Всем привет!
Хочу рассказать про наверное самый способ улучшить читаемость. Например, у вас есть сложное условие из нескольких уровней, каждый из которых состоит из ряда проверок. Или длинный метод с кучей условий, который сложно понять и на который справедливо…
Хочу рассказать про наверное самый способ улучшить читаемость. Например, у вас есть сложное условие из нескольких уровней, каждый из которых состоит из ряда проверок. Или длинный метод с кучей условий, который сложно понять и на который справедливо…
Всем привет!
Могу порекомендовать неплохую статью, объясняющую в чем принципиальная разница между классической архитектурой, основанной на слоях, и более современными и в целом похожими Onion Architecture (ну не привычно мне называть ее луковой :) ), и гексагональной, она же Порты и адаптеры.
Собственно статья https://habr.com/ru/articles/344164/
#arch
Могу порекомендовать неплохую статью, объясняющую в чем принципиальная разница между классической архитектурой, основанной на слоях, и более современными и в целом похожими Onion Architecture (ну не привычно мне называть ее луковой :) ), и гексагональной, она же Порты и адаптеры.
Собственно статья https://habr.com/ru/articles/344164/
#arch
Хабр
Слои, Луковицы, Гексогоны, Порты и Адаптеры — всё это об одном
Перевод статьи Mark Seemann о популярных архитектурах разработки ПО и о том, что между ними общего. Один из моих читателей спросил меня: Вернон, в своей книге «Implementing DDD» много говорит об...
Всем привет!
В этом посте хочу рассказать про несколько малоизвестных фактов про Docker.
На всякий случай напомню. Образ (image) - это шаблон, из которого создаются работающие контейнеры. Хост - система, на которой запускаются контейнеры Docker. Реестр - хранилище образов.
1) Docker - это компания, выпускающая набор инструментов с таким же именем. Компания Docker довела идею контейнеров до работающего состояния и популяризовала их использование. Но Docker - это не стандарт для контейнеров. Т.е. мы все зависим от пропиетарного ПО? Нет. Во-первых Docker Engine является open-source. Во-вторых, он разделен на части и те из них, которые касаются среды выполнения и формата образа, стандартизированы и есть альтернативные реализации - см. OCI. А когда появился k8s, в основе которого лежат контейнеры, то для работы с образами без завязки на Docker он создал стандарт CRI. Подробнее обо всем этом можно почитать вот тут https://habr.com/ru/companies/domclick/articles/566224/
К слову, для cli клиента Docker также есть альтернативы, хоть и не стандартизированные. Например, podman. И если смотреть бегло - он поддерживает те же самые команды, что и docker.
2) принцип хранения Docker образов схож с git-ом. Есть локальный реестр, хранится в папке /var/lib/docker/ и удаленные реестры. Локальный реестр нужен для ускорения, т.к. качать Мб или Гб с локального диска быстрее, чем по сети. Если нужно перенести куда-то локальный реестр, отдельные образы или сделать бэкап - это можно сделать командами docker save и docker load.
3) при построении нужного образа Docker есть одна потенциальная проблема - чем больше команд в Dockerfile, тем больше слоев в образе создается. Проблемой это становится, если в образ как-то попали лишние файлы - после их удаления в запущенном контейнере они пропадут, а вот в реестре содержащий их слой останется. Решить эту проблему помогут команды docker import и export. Их не нужно путать с save и load, т.к. они удаляют все метаданные из образа, сливая все слои в один. Важно: слои - это не обязательно зло, так как при правильном расположении слоев появляется возможность достаточно быстро и дешево обновлять приложение - обновляя только его последний слой.
Кстати, альтернативное решение по уменьшению числа слоев в Docker образе - использование Linux shell pipes, т.е. длинные команды типа cmd1 | cmd2 | .... | cmdN
4) Если нужно посмотреть, что происходит в файловой системе контейнера, т.е. что было изменено с момента старта - есть команда docker diff
5) Список запущенных локально контейнеров покажет docker ps. Linux shell tools рулят)))
6) Важно - файловая система внутри контейнера read only. Но часто контейнер должен что-то писать. Логи хотя бы. Тут два варианта - просто подключить volume, они будут лежать где-то в недрах /var/lib/docker/ на хосте или подключить конкретный каталог хоста. В первом случае volume автоматически удалится при удалении контейнера, во втором - останется на хосте включая все файлы, которые были в нем изначально или добавлены\изменены процессами в контейнере. Второй способ используют к примеру для работы СУБД. Также такой volume можно подключить к нескольким контейнерам и т.об. обмениваться данными через файловую систему. Лучше конечно REST или Kafka, но потребности бывают разные)
7) команды в Dockerfile по умолчанию запускаются под root. В т.ч. и команда, которая стартует главный процесс внутри контейнера. На это обычно ругаются безопасники. Но почему, ведь у нас изоляция??? Паранойя?) Частично)))
Первый кейс с уязвимостью - если контейнер запущен в privileged режиме, они имеет расширенный доступ к ядру Linux хоста. Кейс редкий, я знаю только про одно использование privileged - запуск Docker in Docker, он же dind, см. https://github.com/jpetazzo/dind
Второй кейс - какие-то уязвимости в Linux, которые могут привести к тому же результату.
Третий - окей, процесс внутри контейнера под root сможет делать все, что захочет. А если туда троян попал при сборке? Отправка всех проходящих сквозь контейнер данных злоумышленнику - да легко, спасет только firewall. Или не спасет(
В этом посте хочу рассказать про несколько малоизвестных фактов про Docker.
На всякий случай напомню. Образ (image) - это шаблон, из которого создаются работающие контейнеры. Хост - система, на которой запускаются контейнеры Docker. Реестр - хранилище образов.
1) Docker - это компания, выпускающая набор инструментов с таким же именем. Компания Docker довела идею контейнеров до работающего состояния и популяризовала их использование. Но Docker - это не стандарт для контейнеров. Т.е. мы все зависим от пропиетарного ПО? Нет. Во-первых Docker Engine является open-source. Во-вторых, он разделен на части и те из них, которые касаются среды выполнения и формата образа, стандартизированы и есть альтернативные реализации - см. OCI. А когда появился k8s, в основе которого лежат контейнеры, то для работы с образами без завязки на Docker он создал стандарт CRI. Подробнее обо всем этом можно почитать вот тут https://habr.com/ru/companies/domclick/articles/566224/
К слову, для cli клиента Docker также есть альтернативы, хоть и не стандартизированные. Например, podman. И если смотреть бегло - он поддерживает те же самые команды, что и docker.
2) принцип хранения Docker образов схож с git-ом. Есть локальный реестр, хранится в папке /var/lib/docker/ и удаленные реестры. Локальный реестр нужен для ускорения, т.к. качать Мб или Гб с локального диска быстрее, чем по сети. Если нужно перенести куда-то локальный реестр, отдельные образы или сделать бэкап - это можно сделать командами docker save и docker load.
3) при построении нужного образа Docker есть одна потенциальная проблема - чем больше команд в Dockerfile, тем больше слоев в образе создается. Проблемой это становится, если в образ как-то попали лишние файлы - после их удаления в запущенном контейнере они пропадут, а вот в реестре содержащий их слой останется. Решить эту проблему помогут команды docker import и export. Их не нужно путать с save и load, т.к. они удаляют все метаданные из образа, сливая все слои в один. Важно: слои - это не обязательно зло, так как при правильном расположении слоев появляется возможность достаточно быстро и дешево обновлять приложение - обновляя только его последний слой.
Кстати, альтернативное решение по уменьшению числа слоев в Docker образе - использование Linux shell pipes, т.е. длинные команды типа cmd1 | cmd2 | .... | cmdN
4) Если нужно посмотреть, что происходит в файловой системе контейнера, т.е. что было изменено с момента старта - есть команда docker diff
5) Список запущенных локально контейнеров покажет docker ps. Linux shell tools рулят)))
6) Важно - файловая система внутри контейнера read only. Но часто контейнер должен что-то писать. Логи хотя бы. Тут два варианта - просто подключить volume, они будут лежать где-то в недрах /var/lib/docker/ на хосте или подключить конкретный каталог хоста. В первом случае volume автоматически удалится при удалении контейнера, во втором - останется на хосте включая все файлы, которые были в нем изначально или добавлены\изменены процессами в контейнере. Второй способ используют к примеру для работы СУБД. Также такой volume можно подключить к нескольким контейнерам и т.об. обмениваться данными через файловую систему. Лучше конечно REST или Kafka, но потребности бывают разные)
7) команды в Dockerfile по умолчанию запускаются под root. В т.ч. и команда, которая стартует главный процесс внутри контейнера. На это обычно ругаются безопасники. Но почему, ведь у нас изоляция??? Паранойя?) Частично)))
Первый кейс с уязвимостью - если контейнер запущен в privileged режиме, они имеет расширенный доступ к ядру Linux хоста. Кейс редкий, я знаю только про одно использование privileged - запуск Docker in Docker, он же dind, см. https://github.com/jpetazzo/dind
Второй кейс - какие-то уязвимости в Linux, которые могут привести к тому же результату.
Третий - окей, процесс внутри контейнера под root сможет делать все, что захочет. А если туда троян попал при сборке? Отправка всех проходящих сквозь контейнер данных злоумышленнику - да легко, спасет только firewall. Или не спасет(