Всем привет!
Я вернулся из отпуска, значит настало время для нового поста.
Сегодня хотел бы рассказать о об одном своем провальном проекте. Ведь далеко не все проекты попадают в ПРОМ.
И это нормально, главное - делать выводы из ошибок.
Поехали.
Задача стояла такая. Есть две БД с одинаковой схемой - структурой таблиц.
Данные в БД - пользователь + связанная с ним информация. А это еще порядка сотни таблиц, причем их число растет с каждым релизом.
Требуется периодически переносить часть пользователей из одной БД в другую. Назовем утилиту, которая будет это делать - мигратор.
Навскидку видится три варианта:
1) ETL
2) самописный скрипт БД
3) Java мигратор, работающий на основании метаданных из Hibernate. Да, забыл уточнить, есть Java приложение, работающее со всеми таблицами пользователя через Hibernate.
Наша команда занималась третьим вариантом. Какие я сейчас вижу проблемы у этого варианта:
1) Java мигратор самый сложный и непрозрачный из всех вариантов. Главный его плюс - он практически убирает необходимость ручной доработки мигратора с выходом новых релизов. И убирает двойную работу - другие варианты требуют сначала обновления скриптов версионирования БД, а потом обновления мигратора. Где может выстрелить сложность Java мигратора? БД сопровождают специально обученные люди - DBA. Они достаточно консервативны, т.к. во-первых они сопровождение, а во-вторых - DBA) В нашем случае на ПРОМ скрипты накатывались вручную, хотя разработка предоставляла Liquibase скрипты. Изначально со стороны DBA было заметно недоверие к Java мигратору. Чтобы его снизить решили, что мигратор будет реконструировать схему БД, создавать список таблиц, связанных с пользователем, а DBA всегда будут иметь возможность отфильтровать этот список. Т.е. миграция данных идет по "белому списку". Сопровождение предварительно одобрило такой. При этом активно в процессе выставления требований и тестирования не участвовало.
2) отсутствие внятной процедуры приемки скриптов. Снизить непрозрачность мигратора можно с помощью создания набора тест-кейсов со 100% покрытием на ПРОМ like обезличенных данных. С согласованием процедуры у DBA. Мы этого не сделали. Т.е. тестирование конечно было, но оно проводилось на одном тестовом клиенте, нормального плана не было, консультации с DBA были фрагментарными.
3) растянутость разработки во времени из-за недостатка времени. Задача была экспериментальной, разработка шла больше года, с переодическим переключением на другие задачи. Это привело к падению качества кода. Ни я как тимлид, ни разработчики не дошли до нормального рефакторинга. Модульных тестов было мало. Плюс использовалась рефлексия, что еще больше усложнило код. Когда к моменту принятия решения о внедрении или не внедрении Java мигратора когда я смотрел на код - мне было страшновато(((
4) задача не была вовремя закрыта. На задачу спалили больше человекогода. В результате на ПРОМ использовался самописный SQL мигратор. Сейчас я бы попробовал получить от заказчика четкое ОК на внедрение, создав совместно с ним план тестирования и приемки. Agile и все такое) А если бы этого ОК не было - прекратил бы разработку.
#projects #JPA #fuckup
Я вернулся из отпуска, значит настало время для нового поста.
Сегодня хотел бы рассказать о об одном своем провальном проекте. Ведь далеко не все проекты попадают в ПРОМ.
И это нормально, главное - делать выводы из ошибок.
Поехали.
Задача стояла такая. Есть две БД с одинаковой схемой - структурой таблиц.
Данные в БД - пользователь + связанная с ним информация. А это еще порядка сотни таблиц, причем их число растет с каждым релизом.
Требуется периодически переносить часть пользователей из одной БД в другую. Назовем утилиту, которая будет это делать - мигратор.
Навскидку видится три варианта:
1) ETL
2) самописный скрипт БД
3) Java мигратор, работающий на основании метаданных из Hibernate. Да, забыл уточнить, есть Java приложение, работающее со всеми таблицами пользователя через Hibernate.
Наша команда занималась третьим вариантом. Какие я сейчас вижу проблемы у этого варианта:
1) Java мигратор самый сложный и непрозрачный из всех вариантов. Главный его плюс - он практически убирает необходимость ручной доработки мигратора с выходом новых релизов. И убирает двойную работу - другие варианты требуют сначала обновления скриптов версионирования БД, а потом обновления мигратора. Где может выстрелить сложность Java мигратора? БД сопровождают специально обученные люди - DBA. Они достаточно консервативны, т.к. во-первых они сопровождение, а во-вторых - DBA) В нашем случае на ПРОМ скрипты накатывались вручную, хотя разработка предоставляла Liquibase скрипты. Изначально со стороны DBA было заметно недоверие к Java мигратору. Чтобы его снизить решили, что мигратор будет реконструировать схему БД, создавать список таблиц, связанных с пользователем, а DBA всегда будут иметь возможность отфильтровать этот список. Т.е. миграция данных идет по "белому списку". Сопровождение предварительно одобрило такой. При этом активно в процессе выставления требований и тестирования не участвовало.
2) отсутствие внятной процедуры приемки скриптов. Снизить непрозрачность мигратора можно с помощью создания набора тест-кейсов со 100% покрытием на ПРОМ like обезличенных данных. С согласованием процедуры у DBA. Мы этого не сделали. Т.е. тестирование конечно было, но оно проводилось на одном тестовом клиенте, нормального плана не было, консультации с DBA были фрагментарными.
3) растянутость разработки во времени из-за недостатка времени. Задача была экспериментальной, разработка шла больше года, с переодическим переключением на другие задачи. Это привело к падению качества кода. Ни я как тимлид, ни разработчики не дошли до нормального рефакторинга. Модульных тестов было мало. Плюс использовалась рефлексия, что еще больше усложнило код. Когда к моменту принятия решения о внедрении или не внедрении Java мигратора когда я смотрел на код - мне было страшновато(((
4) задача не была вовремя закрыта. На задачу спалили больше человекогода. В результате на ПРОМ использовался самописный SQL мигратор. Сейчас я бы попробовал получить от заказчика четкое ОК на внедрение, создав совместно с ним план тестирования и приемки. Agile и все такое) А если бы этого ОК не было - прекратил бы разработку.
#projects #JPA #fuckup
Всем привет!
Я довольно часто провожу собесы Java разработчиков. Хотел бы написать про свои "черные метки", сильно снижающие шанс получить предложение о работе.
Ясно, что оценка будет комплексная - по теории, практике, софт-скилам, соответствию знаний и запрашиваемого "золота", но перечисленные ниже вещи сильно влияют на результат.
Поехали.
1) нет понимания основ Java, которые я ожидаю даже от джуна. Пример: переменную нельзя инициализировать результатом метода, обязательно должна быть инициализация через конструктор, а уже потом вызов метода с присвоением.
Для сравнения - не относится к основам незнание, когда можно не инициализировать переменную, а когда нет. Это приходит с опытом.
Еще примеры: непонимание иммутабельности строк или разницы между == и equals. Подчеркну - именно незнание. Можно не заметить этот баг в коде, такое к сожалению бывает, лечится подсказками IDEA и опытом
2) непонимание или отсутствие опыта работы со Spring Core, он же Spring Ioc. Spring сейчас - это наше все. Говорим Java приложение, подразумеваем Spring) Можно его не использовать: знаю компанию, где это запрещено по причине того, что Spring под капотом сложный и многие его используют не разбираясь в деталях. Это допустимый, хотя и спорный подход. Но он не отменяет того, что основы Spring нужно знать.
3) незнание модульных тестов. На мой взгляд это базовая практика, в отличие от более сложных вещей типа TDD, DDD, паттернов и ее нужно изучать вместе с Java и Spring
4) отсутсвие навыков работы с чужим кодом. На собес я предлагаю задачку типа код-ревью. Хотя бы 25% заложенных туда багов надо найти) Отдельный момент - есть баги логические, есть неоптимальный код, есть плохой код-стайл. Первые выглядят как более важные, но как правило их находят при тестировании - модульном или функциональном. Естественно, избавившись от них раньше, мы уменьшим время тестирования, Shift Left, Lead Time и все такое) Но вторые и третьи тоже важны, потому что практически любой код не является одноразовым. Его будут править - исправлять баги, добавлять новые фичи, рефакторить. Возможно даже другие люди. И разбираться в неоптимальном коде, где много boiler plate, отсутствует code стайл - то еще удовольствие. И куча потраченного времени, желание выкинуть все нафиг и переписать с нуля, а это еще куча потраченного времени...
5) Возвращаясь к задачке с код-ревью на собесе. В ней есть работа с данными, содержащимися в локальных переменных. Данные не передаются в метод через параметры - создаются в методе или читаются из файла. Но есть соискатели, которые начинают беспокоится за сохранность этих данных при многоточном вызове метода. Предлагают использовать StringBuffer для манипуляция со строками, или отказаться от static метода и хранить все в полях. Незачет) Локальные объекты хранятся в куче вместе со всеми, но ссылка на них есть только у одного потока, беспокоится незачем. Вообще это основы Java, но вынес в отдельный пункт, т.к. прямо бесит)
6) Для Middle + обязательно знание принципов SOLID. Можно не знать все паттерны или скептически относится к их практическому применению. Тут можно обсудить, поспорить. Но SOLID - это как аксиомы в математике. Основа разработки. Для джуна тоже будет огромным плюсом.
7) односложные ответы без попыток рассуждения. Все знать нельзя, да и не нужно, но рассуждая ты показываешь, на что способен. Сюда же я бы отнес проблемы с логикой. Например: "я первый раз вижу конструкцию do .. while, значит код работать не будет". Чтобы утверждать, что код не работает, нужно хорошо знать Java. Подход - я этого не знаю, поэтому оно работать не будет - плохой))) Везде, не только в Java. Правильно: я этого не знаю, поэтому я бы использовал другую конструкцию.
8) ну и очевидное - уход от прямых ответов, разливание воды ведрами, явная ложь.
#java #interview #solid
Я довольно часто провожу собесы Java разработчиков. Хотел бы написать про свои "черные метки", сильно снижающие шанс получить предложение о работе.
Ясно, что оценка будет комплексная - по теории, практике, софт-скилам, соответствию знаний и запрашиваемого "золота", но перечисленные ниже вещи сильно влияют на результат.
Поехали.
1) нет понимания основ Java, которые я ожидаю даже от джуна. Пример: переменную нельзя инициализировать результатом метода, обязательно должна быть инициализация через конструктор, а уже потом вызов метода с присвоением.
Для сравнения - не относится к основам незнание, когда можно не инициализировать переменную, а когда нет. Это приходит с опытом.
Еще примеры: непонимание иммутабельности строк или разницы между == и equals. Подчеркну - именно незнание. Можно не заметить этот баг в коде, такое к сожалению бывает, лечится подсказками IDEA и опытом
2) непонимание или отсутствие опыта работы со Spring Core, он же Spring Ioc. Spring сейчас - это наше все. Говорим Java приложение, подразумеваем Spring) Можно его не использовать: знаю компанию, где это запрещено по причине того, что Spring под капотом сложный и многие его используют не разбираясь в деталях. Это допустимый, хотя и спорный подход. Но он не отменяет того, что основы Spring нужно знать.
3) незнание модульных тестов. На мой взгляд это базовая практика, в отличие от более сложных вещей типа TDD, DDD, паттернов и ее нужно изучать вместе с Java и Spring
4) отсутсвие навыков работы с чужим кодом. На собес я предлагаю задачку типа код-ревью. Хотя бы 25% заложенных туда багов надо найти) Отдельный момент - есть баги логические, есть неоптимальный код, есть плохой код-стайл. Первые выглядят как более важные, но как правило их находят при тестировании - модульном или функциональном. Естественно, избавившись от них раньше, мы уменьшим время тестирования, Shift Left, Lead Time и все такое) Но вторые и третьи тоже важны, потому что практически любой код не является одноразовым. Его будут править - исправлять баги, добавлять новые фичи, рефакторить. Возможно даже другие люди. И разбираться в неоптимальном коде, где много boiler plate, отсутствует code стайл - то еще удовольствие. И куча потраченного времени, желание выкинуть все нафиг и переписать с нуля, а это еще куча потраченного времени...
5) Возвращаясь к задачке с код-ревью на собесе. В ней есть работа с данными, содержащимися в локальных переменных. Данные не передаются в метод через параметры - создаются в методе или читаются из файла. Но есть соискатели, которые начинают беспокоится за сохранность этих данных при многоточном вызове метода. Предлагают использовать StringBuffer для манипуляция со строками, или отказаться от static метода и хранить все в полях. Незачет) Локальные объекты хранятся в куче вместе со всеми, но ссылка на них есть только у одного потока, беспокоится незачем. Вообще это основы Java, но вынес в отдельный пункт, т.к. прямо бесит)
6) Для Middle + обязательно знание принципов SOLID. Можно не знать все паттерны или скептически относится к их практическому применению. Тут можно обсудить, поспорить. Но SOLID - это как аксиомы в математике. Основа разработки. Для джуна тоже будет огромным плюсом.
7) односложные ответы без попыток рассуждения. Все знать нельзя, да и не нужно, но рассуждая ты показываешь, на что способен. Сюда же я бы отнес проблемы с логикой. Например: "я первый раз вижу конструкцию do .. while, значит код работать не будет". Чтобы утверждать, что код не работает, нужно хорошо знать Java. Подход - я этого не знаю, поэтому оно работать не будет - плохой))) Везде, не только в Java. Правильно: я этого не знаю, поэтому я бы использовал другую конструкцию.
8) ну и очевидное - уход от прямых ответов, разливание воды ведрами, явная ложь.
#java #interview #solid
Всем привет!
Сегодня хочу рассказать про один интересный алгоритм - фильтр Блума.
Для начала ссылка на вики или хабр - по вкусу)
https://ru.wikipedia.org/wiki/Фильтр_Блума
https://habr.com/ru/company/otus/blog/541378/
Ссылки сразу можно не читать, там много теории, расскажу в чем суть на примере.
Есть два микросервиса. Первый предварительно обрабатывает запросы клиента, назовем его web controller. Второй - оркестратор, выполняет длительные операции. web controller выполняет авторизацию, валидацию, кэширование...
Предположим, мы разрешаем выполнение некой операции по черному списку. Или белому - не суть. Это может быть список клиентов, телефонов, диапазонов IP. Список большой, миллионы элементов. Выглядит логично использовать controller для фильтрации, чтобы снять лишнюю нагрузку со оркестратора. Но список динамический, он хранится в отдельном микросервисе.
Какие есть варианты:
1) вызывать микросервис черного списка. Получаем задержку обработки клиентского запроса
2) закэшировать данные в controller с неким TTL. Уже лучше, но так мы потеряем сотни Мб ОЗУ. А это лишь часть функционала controller.
3) закэшировать хэши значений списка. Размер данных скорее всего уменьшится, зависит от выбора хэш-функции и размера данных. Но все равно - десятки Мб.
4) использовать фильтр Блума. Вот калькулятор, показывающий сколько займут данные в фильтре Блума - https://hur.st/bloomfilter/?n=1000000&p=0.01&m=&k=. Как правило, объем меньше раз в 10 благодаря хитрой математике.
Но чудес не бывает, есть подводный камень - фильтр допускает ложноположительные ответы. Т.е. ответ false на запрос входит ли значение в список - это всегда false, а true - с некой вероятностью не true. Вероятность - входной параметр фильтра.
Чем меньше % ошибок - тем больше объем данных.
Соответственно, в нашем примере проверка по черному списку должна быть и в оркестраторе. Но при этом 99.99% "левых" запросов будет отбито в controller.
Может возникнуть вопрос: дублирование - это же плохо? Увы, в микросервисной архитектуре дублирование проверок - это нормально. Главное, не допускать дублирования реализации алгоритма проверки, иначе при его изменении возможен рассинхрон и неприятные баги.
Реализовывать алгоритм самому не нужно, все-таки под капотом у него довольно сложная математика. Есть готовая реализация в Google Guava: https://www.baeldung.com/guava-bloom-filter
#algorithm #java #cache
Сегодня хочу рассказать про один интересный алгоритм - фильтр Блума.
Для начала ссылка на вики или хабр - по вкусу)
https://ru.wikipedia.org/wiki/Фильтр_Блума
https://habr.com/ru/company/otus/blog/541378/
Ссылки сразу можно не читать, там много теории, расскажу в чем суть на примере.
Есть два микросервиса. Первый предварительно обрабатывает запросы клиента, назовем его web controller. Второй - оркестратор, выполняет длительные операции. web controller выполняет авторизацию, валидацию, кэширование...
Предположим, мы разрешаем выполнение некой операции по черному списку. Или белому - не суть. Это может быть список клиентов, телефонов, диапазонов IP. Список большой, миллионы элементов. Выглядит логично использовать controller для фильтрации, чтобы снять лишнюю нагрузку со оркестратора. Но список динамический, он хранится в отдельном микросервисе.
Какие есть варианты:
1) вызывать микросервис черного списка. Получаем задержку обработки клиентского запроса
2) закэшировать данные в controller с неким TTL. Уже лучше, но так мы потеряем сотни Мб ОЗУ. А это лишь часть функционала controller.
3) закэшировать хэши значений списка. Размер данных скорее всего уменьшится, зависит от выбора хэш-функции и размера данных. Но все равно - десятки Мб.
4) использовать фильтр Блума. Вот калькулятор, показывающий сколько займут данные в фильтре Блума - https://hur.st/bloomfilter/?n=1000000&p=0.01&m=&k=. Как правило, объем меньше раз в 10 благодаря хитрой математике.
Но чудес не бывает, есть подводный камень - фильтр допускает ложноположительные ответы. Т.е. ответ false на запрос входит ли значение в список - это всегда false, а true - с некой вероятностью не true. Вероятность - входной параметр фильтра.
Чем меньше % ошибок - тем больше объем данных.
Соответственно, в нашем примере проверка по черному списку должна быть и в оркестраторе. Но при этом 99.99% "левых" запросов будет отбито в controller.
Может возникнуть вопрос: дублирование - это же плохо? Увы, в микросервисной архитектуре дублирование проверок - это нормально. Главное, не допускать дублирования реализации алгоритма проверки, иначе при его изменении возможен рассинхрон и неприятные баги.
Реализовывать алгоритм самому не нужно, все-таки под капотом у него довольно сложная математика. Есть готовая реализация в Google Guava: https://www.baeldung.com/guava-bloom-filter
#algorithm #java #cache
Wikipedia
Фильтр Блума
Фи́льтр Блу́ма (англ. Bloom filter) — вероятностная структура данных, сконструированная Бёртоном Блумом в 1970 году, позволяющая проверять принадлежность элемента к множеству. При этом существует возможность получить ложноположительное срабатывание (элемента…
Всем привет!
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые типы потребителей. О версионировании нужно подумать заранее.
2) Сервер и клиенты поддерживают работу с несколькими версиями API. Это позволит избежать синхронных внедрений двух и более микросервисов. Синхронное внедрение - это сложно и повышает вероятность нарушить все наши "девятки" (SLA)
3) API описано схемой. Король горы для REST запросов - OpenAPI. Отмечу, что в отличие от JSON Schema или XSD OpenAPI описывает не модель данных, а web сервис целиком: поддерживаемые HTTP методы - GET, POST,..., коды ответов HTTP, параметры запроса, заголовки.
4) CDC тестирование - https://martinfowler.com/articles/consumerDrivenContracts.html#Consumer-drivenContracts
В чем суть: создается контракт - человеко и машиночитаемое описание тест-кейсов для API, на основании которых генерируются API тесты для поставщика и потребителя. Примеры реализаций:
Spring Cloud Contract https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/getting-started.html#getting-started-three-second-tour
Pact https://docs.pact.io/5-minute-getting-started-guide
Надо отметить, что OpenAPI и CDS в ряде моментов дублируют информацию, об этой проблеме и возможном решении для Spring можно почитать тут: https://springframework.guru/defining-spring-cloud-contracts-in-open-api/
5) API должно предусматривать уникальный идентификатор запроса, обеспечивающий идемпотентность - возможность повторного вызова метода API, не приводящего к дублированию данных на сервере. В сети и на сервере случаются сбои, повтор вызова в этом случае - естественный выход из ситуации. При получении второго и последующего запросов сервер, определив по уникальному идентификатору, что он уже получал этот запрос, должен вернуть текущий статус операции
6) API должно содержать trace_id - уникальный идентификатор операции. trace_id генерируется на клиенте и копируется в каждый последующий запрос по всем микросервисам. Потом с помощью таких инструментов, как Jaeger дерево запросов визуализируется, что упрощает отлавливание ошибок
7) в API не должно быть ничего лишнего. Добавляем то, что нужно клиенту, если появляется новые требования - версионируем API. Иначе получим аналог "божественного объекта" - https://ru.wikipedia.org/wiki/Божественный_объект
#API #arch #tracing
Современная разработка - это микросервисы, микросервисы - это много внешних взаимодействий, а внешние взаимодействия - это API.
Каким должно быть хорошее API?
1) API должно быть версионировано. Все течет, все меняется: бизнес-требования, новые типы потребителей. О версионировании нужно подумать заранее.
2) Сервер и клиенты поддерживают работу с несколькими версиями API. Это позволит избежать синхронных внедрений двух и более микросервисов. Синхронное внедрение - это сложно и повышает вероятность нарушить все наши "девятки" (SLA)
3) API описано схемой. Король горы для REST запросов - OpenAPI. Отмечу, что в отличие от JSON Schema или XSD OpenAPI описывает не модель данных, а web сервис целиком: поддерживаемые HTTP методы - GET, POST,..., коды ответов HTTP, параметры запроса, заголовки.
4) CDC тестирование - https://martinfowler.com/articles/consumerDrivenContracts.html#Consumer-drivenContracts
В чем суть: создается контракт - человеко и машиночитаемое описание тест-кейсов для API, на основании которых генерируются API тесты для поставщика и потребителя. Примеры реализаций:
Spring Cloud Contract https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/getting-started.html#getting-started-three-second-tour
Pact https://docs.pact.io/5-minute-getting-started-guide
Надо отметить, что OpenAPI и CDS в ряде моментов дублируют информацию, об этой проблеме и возможном решении для Spring можно почитать тут: https://springframework.guru/defining-spring-cloud-contracts-in-open-api/
5) API должно предусматривать уникальный идентификатор запроса, обеспечивающий идемпотентность - возможность повторного вызова метода API, не приводящего к дублированию данных на сервере. В сети и на сервере случаются сбои, повтор вызова в этом случае - естественный выход из ситуации. При получении второго и последующего запросов сервер, определив по уникальному идентификатору, что он уже получал этот запрос, должен вернуть текущий статус операции
6) API должно содержать trace_id - уникальный идентификатор операции. trace_id генерируется на клиенте и копируется в каждый последующий запрос по всем микросервисам. Потом с помощью таких инструментов, как Jaeger дерево запросов визуализируется, что упрощает отлавливание ошибок
7) в API не должно быть ничего лишнего. Добавляем то, что нужно клиенту, если появляется новые требования - версионируем API. Иначе получим аналог "божественного объекта" - https://ru.wikipedia.org/wiki/Божественный_объект
#API #arch #tracing
martinfowler.com
Consumer-Driven Contracts: A Service Evolution
Pattern
Pattern
Consumers should drive the definition of service contracts, while limiting to their individual needs. Suppliers should then validate against the union of their consumers' contracts.
Всем привет!
Что должен знать разработчик кроме своего основного языка, в нашем случае Java. Или Kotlin. Паттерны, основы архитектуры, фреймворки - это я включаю в знание Java.
1) git. На самом деле систем хранения исходников много - svn, mercurial, darcs, git, но последний победил всех. Да, многое можно сделать в IDEA или графических клиентах типа TortoiseGit. Но часто возникают задачи автоматизации набора повторящих команд или разные нетривиальные вещи типа смены автора коммита по всей истории. Кроме базовых команд надо знать основные модели ветвления - gitflow, githab flow, gitlab flow, trunk-based и условия их применимости
2) SQL. Почему - большинство сервисов имеет хранилище, очень часто оно реляционное. Даже если noSQL - к нему может быть прикручен слой SQL-подобного API. Даже если ORM - там есть JQL или HQL.
Объем знаний: DML, DDL, PK, FK, sequences, индексы, партиционирование, неплохо понимать план выполнения запроса
3) shell scripts. Частно приходится выполнять какие-то повторяющиеся действия на рабочей машине или на сервере. Сервера на 90% это Linux, рабочие машины по разному, но для Windows есть несколько реализаций Linux shell. На N-ом повторе возникает мысль про автоматизацию. Часто готовые скрипты можно найти на просторах сети, но в любом случае нужно понимать, что они делают. Чтобы случайно не отформатировать диск C)))
Набор команд, примерный: cd, cp, grep, cat, tail, less, echo, ps, top, tar, gz, sudo, chmod, wget, curl, apt-get или его аналог. Сюда же уметь сгенерировать ssh ключи и сертификаты. Также неплохо бы знать vi. Уточнение - учить наизусть все ключи не нужно, важно понимать что можно сделать в shell, принцип pipeline и какие команды что делают.
4) RegExp. Потребность возникает как при кодирование, так и при отладке - например, для поиска по логам. Опять же есть готовые выражения, есть крутой, хотя небесплатный редактор RegExp Buddy, но читать этот язык надо уметь
5) build tool. На данный момент это Maven и\или Gradle. Опять же IDEA умеет компилировать проекты сама, но на любом более менее сложном нужна утилита для сборки.
Объем: build lifecycle, управление зависимостями, многомодульные проекты, управление настройками сборки, плагины и их прикручивание к нужному шагу сборки
6) docker. Мы идем в светлое облачное будущее, Docker - это его основа.
Что важно: зачем нужен Docker, Docker Registry, слоистость образов, структура Docker файла
to be continued
#java #tools #обучение
Что должен знать разработчик кроме своего основного языка, в нашем случае Java. Или Kotlin. Паттерны, основы архитектуры, фреймворки - это я включаю в знание Java.
1) git. На самом деле систем хранения исходников много - svn, mercurial, darcs, git, но последний победил всех. Да, многое можно сделать в IDEA или графических клиентах типа TortoiseGit. Но часто возникают задачи автоматизации набора повторящих команд или разные нетривиальные вещи типа смены автора коммита по всей истории. Кроме базовых команд надо знать основные модели ветвления - gitflow, githab flow, gitlab flow, trunk-based и условия их применимости
2) SQL. Почему - большинство сервисов имеет хранилище, очень часто оно реляционное. Даже если noSQL - к нему может быть прикручен слой SQL-подобного API. Даже если ORM - там есть JQL или HQL.
Объем знаний: DML, DDL, PK, FK, sequences, индексы, партиционирование, неплохо понимать план выполнения запроса
3) shell scripts. Частно приходится выполнять какие-то повторяющиеся действия на рабочей машине или на сервере. Сервера на 90% это Linux, рабочие машины по разному, но для Windows есть несколько реализаций Linux shell. На N-ом повторе возникает мысль про автоматизацию. Часто готовые скрипты можно найти на просторах сети, но в любом случае нужно понимать, что они делают. Чтобы случайно не отформатировать диск C)))
Набор команд, примерный: cd, cp, grep, cat, tail, less, echo, ps, top, tar, gz, sudo, chmod, wget, curl, apt-get или его аналог. Сюда же уметь сгенерировать ssh ключи и сертификаты. Также неплохо бы знать vi. Уточнение - учить наизусть все ключи не нужно, важно понимать что можно сделать в shell, принцип pipeline и какие команды что делают.
4) RegExp. Потребность возникает как при кодирование, так и при отладке - например, для поиска по логам. Опять же есть готовые выражения, есть крутой, хотя небесплатный редактор RegExp Buddy, но читать этот язык надо уметь
5) build tool. На данный момент это Maven и\или Gradle. Опять же IDEA умеет компилировать проекты сама, но на любом более менее сложном нужна утилита для сборки.
Объем: build lifecycle, управление зависимостями, многомодульные проекты, управление настройками сборки, плагины и их прикручивание к нужному шагу сборки
6) docker. Мы идем в светлое облачное будущее, Docker - это его основа.
Что важно: зачем нужен Docker, Docker Registry, слоистость образов, структура Docker файла
to be continued
#java #tools #обучение
Продолжим с hard-skills, не связанными с основным языком программирования.
7) базовые навыки DevOps. DevOps есть в любой более менее современной компании. Любой разработчик с ним соприкасается. Понимать основы надо.
Что я понимаю под основами: зачем вообще нужен DevOps, подсказка - см. мем "Это работает на моей машине", различие между CI и CD, Infrastructure As Code, опыт работы с каким-то оркестратором, например Jenkins, опыт работы со утилитой версионирования БД, например, Liquibase, опыт работы с SonarQube. Вообще круто, если можешь писать джобы сборки или знаешь что-то из Сonfiguration management software, например, Ansible. Вообще полный список DevOps инструментов огромен, вот наверное самый известный - периодическая таблица https://digital.ai/devops-tools-periodic-table
8) k8s, он же kubernates. Выделил отдельно, хотя тоже можно считать его DevOps инструментом. Почему надо знать - см. пункт про Docker и облака. Как говорится - все там будем)
Что надо знать: что k8s нам дает: https://t.me/javaKotlinDevOps/6, Deployment\ReplicaSet\Pod и их отличия, labels и selectors, request\limits, liveness\readyness\startup probes, ConfigMap, Secret и их различия, Service, Ingress, облачная DNS, Storage, основы работы с kubectl. Если знаешь Istio или Openshift - плюс в карму)
9) HTTP. По факту основной протокол для интеграции сейчас. Что нужно знать: методы HTPP, коды ошибок, заголовки, cookie, HTTP keep-alive, изменения в HTTP/2, Basic Auth и ее альтернативы, основные принципы кэширования контента и используемые для этого заголовки, редиректы. Основные коды ошибок полезно помнить наизусть. Сюда же я бы отнес "маппинг" REST на HTTP: HTTP методы, коды ошибок, заголовки. Для Middle + ожидается понимание, как проходит TLS Handshake https://habr.com/ru/post/258285/
10) Security. Понимание основных типов уязвимостей и способов защиты от них:
а) XSS\CSRF https://habr.com/ru/company/oleg-bunin/blog/412855/
б) SQL Injection и другие типы Injection https://habr.com/ru/company/simplepay/blog/259047/ Вспомним недавний Log4Shell https://t.me/javaKotlinDevOps/4, принцип тот же.
в) DOS атаки и что можно сделать в коде и в архитектуре приложения для защиты от них: https://pvs-studio.com/en/blog/terms/6585/
Также рекомендую проект OWASP, в частности TOP10 уязвимостей https://owasp.org/Top10/
Пожалуй все, хватит)
Пишите если что забыл или наоборот - слишком много требований
#java #обучение
7) базовые навыки DevOps. DevOps есть в любой более менее современной компании. Любой разработчик с ним соприкасается. Понимать основы надо.
Что я понимаю под основами: зачем вообще нужен DevOps, подсказка - см. мем "Это работает на моей машине", различие между CI и CD, Infrastructure As Code, опыт работы с каким-то оркестратором, например Jenkins, опыт работы со утилитой версионирования БД, например, Liquibase, опыт работы с SonarQube. Вообще круто, если можешь писать джобы сборки или знаешь что-то из Сonfiguration management software, например, Ansible. Вообще полный список DevOps инструментов огромен, вот наверное самый известный - периодическая таблица https://digital.ai/devops-tools-periodic-table
8) k8s, он же kubernates. Выделил отдельно, хотя тоже можно считать его DevOps инструментом. Почему надо знать - см. пункт про Docker и облака. Как говорится - все там будем)
Что надо знать: что k8s нам дает: https://t.me/javaKotlinDevOps/6, Deployment\ReplicaSet\Pod и их отличия, labels и selectors, request\limits, liveness\readyness\startup probes, ConfigMap, Secret и их различия, Service, Ingress, облачная DNS, Storage, основы работы с kubectl. Если знаешь Istio или Openshift - плюс в карму)
9) HTTP. По факту основной протокол для интеграции сейчас. Что нужно знать: методы HTPP, коды ошибок, заголовки, cookie, HTTP keep-alive, изменения в HTTP/2, Basic Auth и ее альтернативы, основные принципы кэширования контента и используемые для этого заголовки, редиректы. Основные коды ошибок полезно помнить наизусть. Сюда же я бы отнес "маппинг" REST на HTTP: HTTP методы, коды ошибок, заголовки. Для Middle + ожидается понимание, как проходит TLS Handshake https://habr.com/ru/post/258285/
10) Security. Понимание основных типов уязвимостей и способов защиты от них:
а) XSS\CSRF https://habr.com/ru/company/oleg-bunin/blog/412855/
б) SQL Injection и другие типы Injection https://habr.com/ru/company/simplepay/blog/259047/ Вспомним недавний Log4Shell https://t.me/javaKotlinDevOps/4, принцип тот же.
в) DOS атаки и что можно сделать в коде и в архитектуре приложения для защиты от них: https://pvs-studio.com/en/blog/terms/6585/
Также рекомендую проект OWASP, в частности TOP10 уязвимостей https://owasp.org/Top10/
Пожалуй все, хватит)
Пишите если что забыл или наоборот - слишком много требований
#java #обучение
Digital.ai
Periodic Table of DevSecOps Tools | Digital.ai
The Periodic Table of DevSecOps Tools is the industry's go-to resource for identifying best-of-breed tools across the software delivery lifecycle.
Всем привет!
В предыдущем посте я упомянул про защиту от DOS аттак в коде. Раскрою тему.
Для начала стоит различать DDOS и DOS - (Distribted) Denial of Service.
Первый - это когда злоумышленник долбит миллионами запросов в секунду. Такое не выдержит ни один сервис, не поможет даже k8s, т.к. ресурсы кластера не резиновые - https://kubernetes.io/docs/setup/best-practices/cluster-large/ да и подымаются новые ноды не мгновенно. Следовательно, от DDOS должна защищать сетевая инфраструктура, прикладной разработчик тут ничего сделать не может.
Другое дело DOS - RPS на порядки меньше, эксплуатируются уязвимости в коде. Вопрос - откуда злоумышленники про них узнают?
Во-первых они могут действовать наугад, во-вторых - всегда могут быть болтливые сотрудники, а главное - защита типа "об этом никто никогда не узнает" - плохая защиты.
Суть всех уязвимостией при DOS одна - поднять на сервере столько потоков одновременно, чтобы закончилась память или загрузка процессора ушла под 100%
Итак, как можно улучшить код для защиты от DOS.
1) проводить нагрузочное тестирование (НТ). НТ позволяет точно определеить сколько нужно серверов, чтобы держать расчетную и пиковую нагрузку. Пиковую нагрузку можно взять как расчетная умножить на два. Утечки памяти, неоптимальный код - все это с большой вероятностью можно увидеть на НТ
2) нет бесконечным и большим таймаутам. Если смежник упал, а у нас бесконечный таймаут - потоки и память кончатся быстро. Что касается больших таймаутов - это минуты, или таймауты необоснованные с точки зрения бизнес-задачи.
2) таймауты должны быть согласованы. Если мы обрабатываем запрос с таймутом 5 секунд, он синхронный, а вызываем смежника с таймутом 10 секунд - мы зря тратим его и свои ресурсы. Согласование может быть ручным, либо можно слать, например в заголовках, свой таймаут смежнику, чтобы он не ждал зря.
3) использовать circuit breaker, он же предохранитель, он же техперерыв. Если известно, что смежная система прилегла - не надо ее добивать и тратить на это свои ресурсы. Берем данные из кэша если это возможно или возвращаем клиенту ошибку. Принцип fail fast. Стоит отметить, что настройку таймаутов, предохранителя, и числа повторов можно делать либо в коде, либо отдать на откуп Istio или аналогичной системе если мы в облаке. Что лучше - это отдельная тема
4) защищаться от уязвимостей типа Injection. Суть их в том, что злоумышленник передает в параметрах входящего запроса что-то, что приводит к нелинейному потреблению ресуросов или тяжелым запросам в БД. Примеры первого вида DTD схемы https://habr.com/ru/post/170333/, регулярки - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS, второго - SQL Injection со сложными JOIN. Решение: валидация параметров, регулярно сканировать библиотеки на наличие уязвимостей, регулярно обновляться в части хотфиксов
5) логика сервиса не должна линейно зависеть от числа входных параметров либо число параметров должно ограничено. Чем-то похоже на предыдущий пункт, но тут приложение спроектировано криво, поэтому никакие уязвимости не нужны)
6) использовать пулы потоков. Во многих случаях они уже используются - обработка входящих веб-запросов, JDBC запросы к БД. Но есть потоки, которые создаем мы сами. Если на каждый входной запрос мы будем создавать дополнительно хотя бы +1 поток, то это примерно удвоит потребление ресурсов. А если больше одного... Пул потоков защищает от такой ситуации
7) не забывать закрывать ресурсы - файлы, коннекты к БД. Все что java.io.Closeable. И делать это правильно - try with resources. В отличие от памяти в куче ресурсы никто за вас не закроет. А они жрут память и часто ограничены: максимальное число открытых файлов в Linux, максимальное число запросов, которое может обрабатывать СУБД
8) не использовать тяжелые JOIN и GROUP BY запросы к БД. Создавать индексы, смотреть план выполнения запроса. Об этом должен позаботиться ваш DBA, но, увы, не всегда он есть
9) не использовать излишне сильные уровни блокировки в БД, не использовать блокировки файлов без явной необходимости
#code_quality #security #patterns
В предыдущем посте я упомянул про защиту от DOS аттак в коде. Раскрою тему.
Для начала стоит различать DDOS и DOS - (Distribted) Denial of Service.
Первый - это когда злоумышленник долбит миллионами запросов в секунду. Такое не выдержит ни один сервис, не поможет даже k8s, т.к. ресурсы кластера не резиновые - https://kubernetes.io/docs/setup/best-practices/cluster-large/ да и подымаются новые ноды не мгновенно. Следовательно, от DDOS должна защищать сетевая инфраструктура, прикладной разработчик тут ничего сделать не может.
Другое дело DOS - RPS на порядки меньше, эксплуатируются уязвимости в коде. Вопрос - откуда злоумышленники про них узнают?
Во-первых они могут действовать наугад, во-вторых - всегда могут быть болтливые сотрудники, а главное - защита типа "об этом никто никогда не узнает" - плохая защиты.
Суть всех уязвимостией при DOS одна - поднять на сервере столько потоков одновременно, чтобы закончилась память или загрузка процессора ушла под 100%
Итак, как можно улучшить код для защиты от DOS.
1) проводить нагрузочное тестирование (НТ). НТ позволяет точно определеить сколько нужно серверов, чтобы держать расчетную и пиковую нагрузку. Пиковую нагрузку можно взять как расчетная умножить на два. Утечки памяти, неоптимальный код - все это с большой вероятностью можно увидеть на НТ
2) нет бесконечным и большим таймаутам. Если смежник упал, а у нас бесконечный таймаут - потоки и память кончатся быстро. Что касается больших таймаутов - это минуты, или таймауты необоснованные с точки зрения бизнес-задачи.
2) таймауты должны быть согласованы. Если мы обрабатываем запрос с таймутом 5 секунд, он синхронный, а вызываем смежника с таймутом 10 секунд - мы зря тратим его и свои ресурсы. Согласование может быть ручным, либо можно слать, например в заголовках, свой таймаут смежнику, чтобы он не ждал зря.
3) использовать circuit breaker, он же предохранитель, он же техперерыв. Если известно, что смежная система прилегла - не надо ее добивать и тратить на это свои ресурсы. Берем данные из кэша если это возможно или возвращаем клиенту ошибку. Принцип fail fast. Стоит отметить, что настройку таймаутов, предохранителя, и числа повторов можно делать либо в коде, либо отдать на откуп Istio или аналогичной системе если мы в облаке. Что лучше - это отдельная тема
4) защищаться от уязвимостей типа Injection. Суть их в том, что злоумышленник передает в параметрах входящего запроса что-то, что приводит к нелинейному потреблению ресуросов или тяжелым запросам в БД. Примеры первого вида DTD схемы https://habr.com/ru/post/170333/, регулярки - https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS, второго - SQL Injection со сложными JOIN. Решение: валидация параметров, регулярно сканировать библиотеки на наличие уязвимостей, регулярно обновляться в части хотфиксов
5) логика сервиса не должна линейно зависеть от числа входных параметров либо число параметров должно ограничено. Чем-то похоже на предыдущий пункт, но тут приложение спроектировано криво, поэтому никакие уязвимости не нужны)
6) использовать пулы потоков. Во многих случаях они уже используются - обработка входящих веб-запросов, JDBC запросы к БД. Но есть потоки, которые создаем мы сами. Если на каждый входной запрос мы будем создавать дополнительно хотя бы +1 поток, то это примерно удвоит потребление ресурсов. А если больше одного... Пул потоков защищает от такой ситуации
7) не забывать закрывать ресурсы - файлы, коннекты к БД. Все что java.io.Closeable. И делать это правильно - try with resources. В отличие от памяти в куче ресурсы никто за вас не закроет. А они жрут память и часто ограничены: максимальное число открытых файлов в Linux, максимальное число запросов, которое может обрабатывать СУБД
8) не использовать тяжелые JOIN и GROUP BY запросы к БД. Создавать индексы, смотреть план выполнения запроса. Об этом должен позаботиться ваш DBA, но, увы, не всегда он есть
9) не использовать излишне сильные уровни блокировки в БД, не использовать блокировки файлов без явной необходимости
#code_quality #security #patterns
Kubernetes
Considerations for large clusters
A cluster is a set of nodes (physical or virtual machines) running Kubernetes agents, managed by the control plane. Kubernetes v1.33 supports clusters with up to 5,000 nodes. More specifically, Kubernetes is designed to accommodate configurations that meet…
Всем привет!
Помимо знания языка программирования и инструментов, о которых я писал в предыдущих постах, есть еще один важный навык, который часто недооценивают. Я про знание среды разработки, она же IDE. Это инструмент, с которым мы работаем каждый день. Позволяет автоматизировать большое количество рутинных действий и съэкономить кучу времени.
Предположу, что у большинства Java разработчиков IDE - это IntelliJ IDEA. Бесплатная Community или платная Ultimate.
Да, конечно, существуют Netbeans и Eclipse. У первой сложная судьба - начинала как "придворная" IDE в Sun\Oracle, а заканчивает как OpenSource в Apache Foundation.
Вторая - изначально OpenSource, с акцентом на расширяемость плагинами, довольно активно развивается. Еще Eclipse - живой пример использования OSGi. Но есть нюанс. На мой взгляд любой успешный (!) коммерческий продукт, создатели которого не продали душу богу маркетинга (!) - т.е. не соблазнились свистелками, а вместо этого думают о пользователе - будет бить OpenSource за счет возможности координации усилий. Приведу примеры. Вышла новая версия Java - оперативно добавили поддержку. Популярен сейчас Kotlin или новый фреймворк - наняли людей, перебросили команду и добавили поддержку. Поняли, что можно упростить жизнь разработчику готовыми инструментами для рефакторинга - составили список и автоматизировали. Скоордировать сообщество разработчиков, для которых OpenSource - хобби, для быстрого решения подобных задач сложнее. Хотя наверное при определенном количестве commiters - возможно.
Но я отвлекся. Сегодня речь про IDEA. IDEA может многое. Пречисленные ниже фичи в разное время меня впечатлили, и я считаю на них стоит обратить внимание:
- автодополнение: по идущим не подряд символам из названия метода набранным в нужном порядке, по символам в неверной раскладке, с сортировкой исходя из машинного обучения. Да, да ИИ уже с нами)
https://www.jetbrains.com/help/idea/auto-completing-code.html
- автогенерация: тесты к классу, override, конструкторы, getter и setter https://www.jetbrains.com/help/idea/generating-code.html
- огромное число рефакторингов, причем достаточно умных. Пример умного рефакторинга: при переименовании IDEA отдельно спрашивает подтверждение на совпадения в комментариях. https://www.jetbrains.com/help/idea/refactoring-source-code.html
- всеобъемлющий поиск: по настройкам, по классам, файлам, действиям в IDE, и по всему сразу, поиск использования класса\метода, по коду проекта и поиск внутри файла, в т.ч с регуляркой, структурный поиск - найти все enum в проекте, поиск по методам класса.
Даже перечисление видов поиска заняло кучу места, а мой список не полон) А еще есть вкладки с предыдущими результатами поиска, самобновляющиеся после редактирования кода.
https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-file.html
- отличная интеграция с Git. И скорее всего с другими VCS, но я тестировал только Git. Фичи: удобно выбирать файлы и даже строки для коммита, на коммит можно повесить проверки, простые Revert, Merge, Amend commit, сравнения файлов. В целом для 99% процентов задач можно забыть про сторонние клиенты Git.
https://www.jetbrains.com/help/idea/version-control-integration.html
- рендеринг кода в редакторе: отображение "лямбд" еще до их появления в Java 7))), упрощенное представление лямбд, компактный JavaDoc, работа с секциями
- подсказки по коду: краткая и полная информация о классе или методе, всплывающий JavaDoc, подкачивание исходников при их наличии. https://www.jetbrains.com/help/idea/viewing-reference-information.html
- анализ зависимостей между классами, в т.ч в виде матрицы. Позволяет распутывать клубки в больших проектах. https://www.jetbrains.com/help/idea/dependencies-analysis.html
- возможность скачивания JDK разных версий и вендоров прямо из IDE
- HTTP client
- Code with Me - возможность совместной работы, хотя я ее так и не оттестировал(
- анализ стектрейсов, полученных от тестировщиков или сопровождения, переход к коду из стэктрейса https://www.jetbrains.com/help/idea/analyzing-external-stacktraces.html
Помимо знания языка программирования и инструментов, о которых я писал в предыдущих постах, есть еще один важный навык, который часто недооценивают. Я про знание среды разработки, она же IDE. Это инструмент, с которым мы работаем каждый день. Позволяет автоматизировать большое количество рутинных действий и съэкономить кучу времени.
Предположу, что у большинства Java разработчиков IDE - это IntelliJ IDEA. Бесплатная Community или платная Ultimate.
Да, конечно, существуют Netbeans и Eclipse. У первой сложная судьба - начинала как "придворная" IDE в Sun\Oracle, а заканчивает как OpenSource в Apache Foundation.
Вторая - изначально OpenSource, с акцентом на расширяемость плагинами, довольно активно развивается. Еще Eclipse - живой пример использования OSGi. Но есть нюанс. На мой взгляд любой успешный (!) коммерческий продукт, создатели которого не продали душу богу маркетинга (!) - т.е. не соблазнились свистелками, а вместо этого думают о пользователе - будет бить OpenSource за счет возможности координации усилий. Приведу примеры. Вышла новая версия Java - оперативно добавили поддержку. Популярен сейчас Kotlin или новый фреймворк - наняли людей, перебросили команду и добавили поддержку. Поняли, что можно упростить жизнь разработчику готовыми инструментами для рефакторинга - составили список и автоматизировали. Скоордировать сообщество разработчиков, для которых OpenSource - хобби, для быстрого решения подобных задач сложнее. Хотя наверное при определенном количестве commiters - возможно.
Но я отвлекся. Сегодня речь про IDEA. IDEA может многое. Пречисленные ниже фичи в разное время меня впечатлили, и я считаю на них стоит обратить внимание:
- автодополнение: по идущим не подряд символам из названия метода набранным в нужном порядке, по символам в неверной раскладке, с сортировкой исходя из машинного обучения. Да, да ИИ уже с нами)
https://www.jetbrains.com/help/idea/auto-completing-code.html
- автогенерация: тесты к классу, override, конструкторы, getter и setter https://www.jetbrains.com/help/idea/generating-code.html
- огромное число рефакторингов, причем достаточно умных. Пример умного рефакторинга: при переименовании IDEA отдельно спрашивает подтверждение на совпадения в комментариях. https://www.jetbrains.com/help/idea/refactoring-source-code.html
- всеобъемлющий поиск: по настройкам, по классам, файлам, действиям в IDE, и по всему сразу, поиск использования класса\метода, по коду проекта и поиск внутри файла, в т.ч с регуляркой, структурный поиск - найти все enum в проекте, поиск по методам класса.
Даже перечисление видов поиска заняло кучу места, а мой список не полон) А еще есть вкладки с предыдущими результатами поиска, самобновляющиеся после редактирования кода.
https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-file.html
- отличная интеграция с Git. И скорее всего с другими VCS, но я тестировал только Git. Фичи: удобно выбирать файлы и даже строки для коммита, на коммит можно повесить проверки, простые Revert, Merge, Amend commit, сравнения файлов. В целом для 99% процентов задач можно забыть про сторонние клиенты Git.
https://www.jetbrains.com/help/idea/version-control-integration.html
- рендеринг кода в редакторе: отображение "лямбд" еще до их появления в Java 7))), упрощенное представление лямбд, компактный JavaDoc, работа с секциями
- подсказки по коду: краткая и полная информация о классе или методе, всплывающий JavaDoc, подкачивание исходников при их наличии. https://www.jetbrains.com/help/idea/viewing-reference-information.html
- анализ зависимостей между классами, в т.ч в виде матрицы. Позволяет распутывать клубки в больших проектах. https://www.jetbrains.com/help/idea/dependencies-analysis.html
- возможность скачивания JDK разных версий и вендоров прямо из IDE
- HTTP client
- Code with Me - возможность совместной работы, хотя я ее так и не оттестировал(
- анализ стектрейсов, полученных от тестировщиков или сопровождения, переход к коду из стэктрейса https://www.jetbrains.com/help/idea/analyzing-external-stacktraces.html
IntelliJ IDEA Help
Code completion | IntelliJ IDEA
Techniques to speed up the editing process in IntelliJ IDEA using code completion (basic completion, smart
completion based on a type, hippie expand, and so on).
completion based on a type, hippie expand, and so on).
- быстрое получение ссылки на код: сopy path или сopy reference, а с внешними плагинами и Copy Bitbucket Link
- shortcuts практически для всего: https://www.jetbrains.com/help/idea/reference-keymap-win-default.html А для действий без стандартных shortcuts можно назначить свои, причем не только клавиатурные, но и мышинные)
Рекомендую начинать учить, если еще не сделали.
Начать можно с https://blog.jetbrains.com/idea/2020/03/top-15-intellij-idea-shortcuts/
Также не стоит выключать обучающий режим, когда при открытии проекта IDEA показывает полезные советы, в т.ч. shortcuts.
- разнообразие внешних плагинов, рекомендую заглянуть в соответствующий раздел настроек.
В общем IDEA - это целый мир, в который можно и нужно погрузится с головой.
Возможно я что-то упустил из крутых или важных фичей, напишите об этом.
#IDEA #IDE #tools #обучение
- shortcuts практически для всего: https://www.jetbrains.com/help/idea/reference-keymap-win-default.html А для действий без стандартных shortcuts можно назначить свои, причем не только клавиатурные, но и мышинные)
Рекомендую начинать учить, если еще не сделали.
Начать можно с https://blog.jetbrains.com/idea/2020/03/top-15-intellij-idea-shortcuts/
Также не стоит выключать обучающий режим, когда при открытии проекта IDEA показывает полезные советы, в т.ч. shortcuts.
- разнообразие внешних плагинов, рекомендую заглянуть в соответствующий раздел настроек.
В общем IDEA - это целый мир, в который можно и нужно погрузится с головой.
Возможно я что-то упустил из крутых или важных фичей, напишите об этом.
#IDEA #IDE #tools #обучение
IntelliJ IDEA Help
Predefined Windows keymap | IntelliJ IDEA
Всем привет!
Наверняка многие слышали про практику TDD - Test Driven Development. У которой есть некие сложности с применением. Напомню, ее суть не только и не столько в том, что тест должен предшествовать коду, а в сокращении врени итерации - тест-код. Т.е. в идеальном случае надо делать так:
1) простейший тест
2) код с заглушкой, позволяющий пройти тест
3) новый тест
4) усложнение заглушки
...
N) финальный работающий код
И коммитить желательно почаще.
Самое сложное здесь - заставить себя не писать сразу кучу тестов или весь метод сразу. Или даже весь класс + ряд зависимых классов, а идти мелкими шагами.
Сам пробовал - сложно)
И от одного из создателей XP Кента Бека есть решение - TCR https://medium.com/@kentbeck_7670/test-commit-revert-870bbd756864
Расшифровывается как test && commit | | revert.
Суть в следующем:
1) к запуску тестов привязывается команда git
2) если тесты успешные - git commit
3) если тесты упали, то коммитить неработающий код нельзя, потому делаем revert в виде git reset --hard
Только хардкор!)
4) в паралльном потоке работает цикл
while (true) {
git pull --rebase
git push
}
синхронизируя изменения других разработчиков.
Итог: переписав несколько раз большие куски кода из-за падения теста рано или поздно длина итераций станет минимально возможной.
Второй возможный кейс - кусок кода небольшой, но commit вовремя не сделан, и кто-то что-то параллельно закоммитил в develop и поломал ваши тесты.
Пример использования на практике с реализацией shell скрипта "test && commit | | revert":
https://medium.com/@tdeniffel/tcr-test-commit-revert-a-test-alternative-to-tdd-6e6b03c22bec
Что думаете?
#Agile #XP #TDD #TCR
Наверняка многие слышали про практику TDD - Test Driven Development. У которой есть некие сложности с применением. Напомню, ее суть не только и не столько в том, что тест должен предшествовать коду, а в сокращении врени итерации - тест-код. Т.е. в идеальном случае надо делать так:
1) простейший тест
2) код с заглушкой, позволяющий пройти тест
3) новый тест
4) усложнение заглушки
...
N) финальный работающий код
И коммитить желательно почаще.
Самое сложное здесь - заставить себя не писать сразу кучу тестов или весь метод сразу. Или даже весь класс + ряд зависимых классов, а идти мелкими шагами.
Сам пробовал - сложно)
И от одного из создателей XP Кента Бека есть решение - TCR https://medium.com/@kentbeck_7670/test-commit-revert-870bbd756864
Расшифровывается как test && commit | | revert.
Суть в следующем:
1) к запуску тестов привязывается команда git
2) если тесты успешные - git commit
3) если тесты упали, то коммитить неработающий код нельзя, потому делаем revert в виде git reset --hard
Только хардкор!)
4) в паралльном потоке работает цикл
while (true) {
git pull --rebase
git push
}
синхронизируя изменения других разработчиков.
Итог: переписав несколько раз большие куски кода из-за падения теста рано или поздно длина итераций станет минимально возможной.
Второй возможный кейс - кусок кода небольшой, но commit вовремя не сделан, и кто-то что-то параллельно закоммитил в develop и поломал ваши тесты.
Пример использования на практике с реализацией shell скрипта "test && commit | | revert":
https://medium.com/@tdeniffel/tcr-test-commit-revert-a-test-alternative-to-tdd-6e6b03c22bec
Что думаете?
#Agile #XP #TDD #TCR
Medium
test && commit || revert
As part of Limbo on the Cheap, we invented a new programming workflow. I introduced “test && commit”, where every time the tests run…
Всем привет!
Чтобы закончить тему с TDD, ну хотя бы на ближайшее время закончить, хочу подчеркнуть его плюсы и порекомендовать книгу.
Плюсы:
1) точно достигните требуемого покрытия кода тестами. Мне сложно представить откуда может взяться непокрытый тестами код если приложение создано по TDD начиная с первой строчки
2) писать тесты будет не так тяжело, как при типичном подходе. Когда код написан, отлажен, возможно даже прошел функциональное тестирование, а вместо создания чего-то нового или обучения приходится удовлетворять SonarQube и требования организации\тимлида - это не весело))) А тут еще выясняется, что код плохо приспособлен для тестирования. И кто знает, возможно с TDD даже появятся позитивные эмоциии, особенно когда тесты зеленеют)
3) меньше шансов, что приложение, даже если оно изначально разрабатывалось как микросервис, превратится в монолит(ик), который страшно трогать руками. Железо не гибкое, процессы и люди .. ну под вопросом. А ПО должно быть гибким.
4) не нужно объяснять PO что такое рефакторинг и почему для него выделяется столько много storypoins или человекодней. Т.к. рефакторинг станет неотрывной частью процесса разработки и затраты на него войдут в трудоемкость разработки фичи
5) полученные тесты - хороший аргумент, чтобы оставить в JavaDoc и аналитике только вещи, касающиеся описания бизнес-процесса, e2e, интеграций, т.к. все остальное будет в тестах. Причем документация с помощью тестов может разойтись с кодом только в одном случае - если на тесты забить) В отличие от.
6) возможно реализация логики улучшится. Как это может произойти. Часто в коде реализуется первая пришедшая в голову идея. А уже по результатам функционального тестирования она переписывается или что хуже запиливаюстя костыли. Это плохой подход - брать первую попавшуюся идею, но психологически бороться с ним сложно. Если же эволюционно писать тесты-код-тесты-код.. то быстрее можно прийти к пониманию, что первая реализация - не лучшая. А переписывание кода и тестов в TDD - это ок
Ну и книга. Это не Кент Бек "Экстремальное программирование: разработка через тестирование" https://habr.com/ru/company/piter/blog/326662/ как можно было подумать. Хотя и ее тоже можно порекомендовать, классика как никак.
Но недавно вышла новая книга Боба Мартина, он же «дядюшка» Боб "Идеальная работа. Программирование без прикрас" https://habr.com/ru/company/piter/blog/679378/. Первая часть книги как раз рассказывает как влится в TDD. Даже видосы есть с реализацией разных простых алгоритмов по TDD подходу.
Мне очень зашло, рекомендую, книгу вместе с видосами. Да, если вступление к книге покажется слишком официозным - переходите сразу к первой части.
Если книжки, статьи на разные темы в рамках Java\Kotlin\DevOps интересны - пишите, буду рекомендовать.
#books #tdd
Чтобы закончить тему с TDD, ну хотя бы на ближайшее время закончить, хочу подчеркнуть его плюсы и порекомендовать книгу.
Плюсы:
1) точно достигните требуемого покрытия кода тестами. Мне сложно представить откуда может взяться непокрытый тестами код если приложение создано по TDD начиная с первой строчки
2) писать тесты будет не так тяжело, как при типичном подходе. Когда код написан, отлажен, возможно даже прошел функциональное тестирование, а вместо создания чего-то нового или обучения приходится удовлетворять SonarQube и требования организации\тимлида - это не весело))) А тут еще выясняется, что код плохо приспособлен для тестирования. И кто знает, возможно с TDD даже появятся позитивные эмоциии, особенно когда тесты зеленеют)
3) меньше шансов, что приложение, даже если оно изначально разрабатывалось как микросервис, превратится в монолит(ик), который страшно трогать руками. Железо не гибкое, процессы и люди .. ну под вопросом. А ПО должно быть гибким.
4) не нужно объяснять PO что такое рефакторинг и почему для него выделяется столько много storypoins или человекодней. Т.к. рефакторинг станет неотрывной частью процесса разработки и затраты на него войдут в трудоемкость разработки фичи
5) полученные тесты - хороший аргумент, чтобы оставить в JavaDoc и аналитике только вещи, касающиеся описания бизнес-процесса, e2e, интеграций, т.к. все остальное будет в тестах. Причем документация с помощью тестов может разойтись с кодом только в одном случае - если на тесты забить) В отличие от.
6) возможно реализация логики улучшится. Как это может произойти. Часто в коде реализуется первая пришедшая в голову идея. А уже по результатам функционального тестирования она переписывается или что хуже запиливаюстя костыли. Это плохой подход - брать первую попавшуюся идею, но психологически бороться с ним сложно. Если же эволюционно писать тесты-код-тесты-код.. то быстрее можно прийти к пониманию, что первая реализация - не лучшая. А переписывание кода и тестов в TDD - это ок
Ну и книга. Это не Кент Бек "Экстремальное программирование: разработка через тестирование" https://habr.com/ru/company/piter/blog/326662/ как можно было подумать. Хотя и ее тоже можно порекомендовать, классика как никак.
Но недавно вышла новая книга Боба Мартина, он же «дядюшка» Боб "Идеальная работа. Программирование без прикрас" https://habr.com/ru/company/piter/blog/679378/. Первая часть книги как раз рассказывает как влится в TDD. Даже видосы есть с реализацией разных простых алгоритмов по TDD подходу.
Мне очень зашло, рекомендую, книгу вместе с видосами. Да, если вступление к книге покажется слишком официозным - переходите сразу к первой части.
Если книжки, статьи на разные темы в рамках Java\Kotlin\DevOps интересны - пишите, буду рекомендовать.
#books #tdd
Хабр
Книга «Экстремальное программирование: разработка через тестирование»
Возвращение знаменитого бестселлера. Изящный, гибкий и понятный код, который легко модифицировать, который корректно работает и который не подкидывает своим создателям неприятных сюрпризов. Неужели...
Всем привет!
Каким должен быть хороший тест?
Я в первую очередь про модульные (unit), но в принципе правила применимы к любым.
Основные моменты:
1) правило Arrange, Act, Assert https://xp123.com/articles/3a-arrange-act-assert/
Тест делится на три части: подготовка тестовых данных, вызов тестового метода и проверка. Часто забывают про последнюю.
Тест должен что-то проверить: выброшенное исключение, сколько и каких было вызвано методов, состояние объекта.
Тест проверяющий только тот факт, что вызов прошел без исключения, добавляет покрытия, но по сути является недотестом. Его успех показывает, что что-то там выполнилось) Выполнено ли то, что должен делать метод - не ясно. Если API не позволяет проверить результат выполнения кода - это плохое API. Если же код legacy и рефакторить его сложно - можно воспользоваться Mockito.spy или рефлексией.
2) тестовый код - такой же код, как и боевой. К нему должны быть применены все практики написания чистого кода - https://www.litres.ru/robert-s-martin/chistyy-kod-sozdanie-analiz-i-refaktoring-6444478
Я вижу одно исключение - в тестовом коде норм использовать System.out.println
3) тест должен проверять одну операцию с одним или несколькими связанными наборами входных параметров, это удобно делать через параметризацию. При этом допустимо в тесте использовать несколько Assert. Хотя можно их вынести в один assert метод. Или использовать Soft Assert http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#soft-assertions. Как по мне - все три варианта норм, дело вкуса.
4) все внешние объекты, требуемые тестируемому методу, должны быть заглушены. Наиболее удобно использовать Mockito.mock или Mockito.spy, но если надо - можно наследоваться от интерфейса и сделать тестовый двойник самому. Если глушить приходится слишком много - повод задуматься про архитектуру кода
5) если стандартного API Mockito или самописных заглушек не хватает, и руки тянутся к включить "секретные" опции Mockito для того, чтобы заглушить private, static или наследоваться от final класса - тоже повод задуматься про архитектуру. Хотя как быстрое решение для legacy допустимо.
6) в поставке для ПРОМа не должно быть тестового кода, боевой код не должен использовать тестовые зависимости и Helpers. В боевом коде не должно быть "ловушек" для успешного выполнения тестов - т.е. выражений типа
if (isTestRun()) {
7) тесты - это документация к коду. Для этого тест должен легко читаться. А чтобы этого добиться - нужно выносить все лишние во вспомогательные методы для Arrange и Assert, передавая как параметры в эти методы только то, что непосредственно влияет на конкретный тест. В этом плане при выборе между @ BeforeEach методом и обычным нужно выбирать обычный - так замысел теста легче читается.
А при возникновении вопроса чтобы бы добавить в тесты, или может уже хватит, стоит в первую очередь думать о закрытии всех основных комбинаций входных параметров, а не о покрытии. Требуемый процент покрытия можно подкрутить, главное как и у тестировщиков - полнота тестовой модели. И читаемость тестов
8) тесты должны быть антихрупкими. Т.е. тест не должен падать при любых правках кода, а тем более - при правках кода, который на первый взгляд никак не связан с тестом. Задача теста - облегчить рефакторинг и доработки, а не усложнить их) Готовых рецептов тут нет, но если данные для assert меняются каждый релиз, значить проверять надо что-то еще. Пример: если речь про API - атрибуты JSON, а не полный JSON
9) тесты не должны зависеть от результата других тестов, от порядка выполнения и от среды
10) из логов запуска упавшего теста должно быть понятно, в чем ошибка. Для этого тест должен выполняться быстро, чтобы запускать его после каждого изменения, тестовые методы должны быть названы осознано, и самое сложное - в assert-ах должны быть сообщения об ошибках. И \ или использовать power asserts, которые подробно выводят в лог что пришло в Assert метод https://github.com/bnorm/kotlin-power-assert
P.S. Женя Осмаковский, спасибо за подсказку по п.8
#unittests #cleancode
Каким должен быть хороший тест?
Я в первую очередь про модульные (unit), но в принципе правила применимы к любым.
Основные моменты:
1) правило Arrange, Act, Assert https://xp123.com/articles/3a-arrange-act-assert/
Тест делится на три части: подготовка тестовых данных, вызов тестового метода и проверка. Часто забывают про последнюю.
Тест должен что-то проверить: выброшенное исключение, сколько и каких было вызвано методов, состояние объекта.
Тест проверяющий только тот факт, что вызов прошел без исключения, добавляет покрытия, но по сути является недотестом. Его успех показывает, что что-то там выполнилось) Выполнено ли то, что должен делать метод - не ясно. Если API не позволяет проверить результат выполнения кода - это плохое API. Если же код legacy и рефакторить его сложно - можно воспользоваться Mockito.spy или рефлексией.
2) тестовый код - такой же код, как и боевой. К нему должны быть применены все практики написания чистого кода - https://www.litres.ru/robert-s-martin/chistyy-kod-sozdanie-analiz-i-refaktoring-6444478
Я вижу одно исключение - в тестовом коде норм использовать System.out.println
3) тест должен проверять одну операцию с одним или несколькими связанными наборами входных параметров, это удобно делать через параметризацию. При этом допустимо в тесте использовать несколько Assert. Хотя можно их вынести в один assert метод. Или использовать Soft Assert http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#soft-assertions. Как по мне - все три варианта норм, дело вкуса.
4) все внешние объекты, требуемые тестируемому методу, должны быть заглушены. Наиболее удобно использовать Mockito.mock или Mockito.spy, но если надо - можно наследоваться от интерфейса и сделать тестовый двойник самому. Если глушить приходится слишком много - повод задуматься про архитектуру кода
5) если стандартного API Mockito или самописных заглушек не хватает, и руки тянутся к включить "секретные" опции Mockito для того, чтобы заглушить private, static или наследоваться от final класса - тоже повод задуматься про архитектуру. Хотя как быстрое решение для legacy допустимо.
6) в поставке для ПРОМа не должно быть тестового кода, боевой код не должен использовать тестовые зависимости и Helpers. В боевом коде не должно быть "ловушек" для успешного выполнения тестов - т.е. выражений типа
if (isTestRun()) {
7) тесты - это документация к коду. Для этого тест должен легко читаться. А чтобы этого добиться - нужно выносить все лишние во вспомогательные методы для Arrange и Assert, передавая как параметры в эти методы только то, что непосредственно влияет на конкретный тест. В этом плане при выборе между @ BeforeEach методом и обычным нужно выбирать обычный - так замысел теста легче читается.
А при возникновении вопроса чтобы бы добавить в тесты, или может уже хватит, стоит в первую очередь думать о закрытии всех основных комбинаций входных параметров, а не о покрытии. Требуемый процент покрытия можно подкрутить, главное как и у тестировщиков - полнота тестовой модели. И читаемость тестов
8) тесты должны быть антихрупкими. Т.е. тест не должен падать при любых правках кода, а тем более - при правках кода, который на первый взгляд никак не связан с тестом. Задача теста - облегчить рефакторинг и доработки, а не усложнить их) Готовых рецептов тут нет, но если данные для assert меняются каждый релиз, значить проверять надо что-то еще. Пример: если речь про API - атрибуты JSON, а не полный JSON
9) тесты не должны зависеть от результата других тестов, от порядка выполнения и от среды
10) из логов запуска упавшего теста должно быть понятно, в чем ошибка. Для этого тест должен выполняться быстро, чтобы запускать его после каждого изменения, тестовые методы должны быть названы осознано, и самое сложное - в assert-ах должны быть сообщения об ошибках. И \ или использовать power asserts, которые подробно выводят в лог что пришло в Assert метод https://github.com/bnorm/kotlin-power-assert
P.S. Женя Осмаковский, спасибо за подсказку по п.8
#unittests #cleancode
Xp123
3A - Arrange, Act, Assert - XP123
Arrange-Act-Assert is a way to structure microtests - to make sure they clearly do one thing and aren't like a run-on-sentence.
Всем привет!
Пару слов о том, на что не нужно писать модульные тесты.
Женя, спасибо за вопросы к предыдущему посту!
Для начала очевидные кейсы:
1) getter и setter. Во-первый - логики там нет, точнее не должно быть. Более того эти методы скорее всего будут вызываны из других тестов. Более того, методы вообще говоря можно не писать руками, а сгенерировать с помощью Lombook @Getter и @Setter, или использовать Kotlin. Что касается покрытия, то как я уже писал ранее - покрытие не главная цель, скорее следствие. А кроме того Jacoco -как самый распространенный инструмент - не считает покрытие по сгенерированным методам Lombook. Детальнее про то, что не учитывается в покрытии и что можно донастроить см. https://www.baeldung.com/jacoco-report-exclude и https://github.com/jacoco/jacoco/wiki/filtering-JAVAC.SYNTHMETH
2) сгенерированный код. Причины те же, как исключить см. выше.
3) код внешних библиотек. Как первая версия теста при TDD подходе, чтобы проверить, что код вообще компилируется - да, можно. Чтобы убедиться, что JDK правильная в проекте, все библиотеки подключены. Проверить что новая библиотека работает как ожидаешь. Но потом такой тест или должен быть дополнен тестированием вашей логики, или удален. Код поднятия внешних библиотек при этом может быть вынесен в отдельный метод для переиспользования.
4) любой тривиальный код, типа конструкторы Entity\DTO или число элементов в Enum. В первом случае этот код должен быть вызван из других тестов. Во втором - не понятно, что доказывает этот тест.
Неоднозначные случаи:
5) корректноть инфраструктурного кода, типа создания контекста Spring. В идеале ее должен тестировать компилятор. Что он и сделает при использовании JavaConfig + Annotations. Если у вас XML Config - может помочь IDEA https://www.jetbrains.com/help/idea/spring-projects.html, ну или поднятие Spring контекста в других тестах.
6) методы-интеграторы: методы, единственная цель которых - вызывать другие методы. Как правило находятся в сервисах. Во-первых код теста получается хрупким, т.к. с новыми релизами добавляются новые вызовы. А во-вторых приходится писать кучу моков. А главное логики особо нет, кроме правильной последовательности вызовов и передачи данных по цепочке. Если появляется более сложная логика - валидация данных, проверка прав - тест будет иметь смысл. Иначе можно пропустить, а лучше написать интеграционный тест, включающий вызов такого метода-интегратора.
7) методы, конструирующие DTO для слоя API. DTO использовать нужно, чтобы развязать доменные сущности и API. Но такой код часто представляет просто mapping. С одной стороны какая-то практическая польза в такой проверке есть: данные должны быть в нужном формате - JSON, должны быть какие-то обязательные поля, нужно убедится, что данные из модели попали в ответ. С другой стороны если валидировать сравнением с эталонным JSON - тест получается хрупким. Решение - метод тестировать, но проверять результат преобразования точечно, фокусироваться на том, что скорее всего не изменится в будущем.
В заключение вот хорошая статья на тему написания правльных тестов https://habr.com/ru/company/jugru/blog/323920/
#unittests #Java
Пару слов о том, на что не нужно писать модульные тесты.
Женя, спасибо за вопросы к предыдущему посту!
Для начала очевидные кейсы:
1) getter и setter. Во-первый - логики там нет, точнее не должно быть. Более того эти методы скорее всего будут вызываны из других тестов. Более того, методы вообще говоря можно не писать руками, а сгенерировать с помощью Lombook @Getter и @Setter, или использовать Kotlin. Что касается покрытия, то как я уже писал ранее - покрытие не главная цель, скорее следствие. А кроме того Jacoco -как самый распространенный инструмент - не считает покрытие по сгенерированным методам Lombook. Детальнее про то, что не учитывается в покрытии и что можно донастроить см. https://www.baeldung.com/jacoco-report-exclude и https://github.com/jacoco/jacoco/wiki/filtering-JAVAC.SYNTHMETH
2) сгенерированный код. Причины те же, как исключить см. выше.
3) код внешних библиотек. Как первая версия теста при TDD подходе, чтобы проверить, что код вообще компилируется - да, можно. Чтобы убедиться, что JDK правильная в проекте, все библиотеки подключены. Проверить что новая библиотека работает как ожидаешь. Но потом такой тест или должен быть дополнен тестированием вашей логики, или удален. Код поднятия внешних библиотек при этом может быть вынесен в отдельный метод для переиспользования.
4) любой тривиальный код, типа конструкторы Entity\DTO или число элементов в Enum. В первом случае этот код должен быть вызван из других тестов. Во втором - не понятно, что доказывает этот тест.
Неоднозначные случаи:
5) корректноть инфраструктурного кода, типа создания контекста Spring. В идеале ее должен тестировать компилятор. Что он и сделает при использовании JavaConfig + Annotations. Если у вас XML Config - может помочь IDEA https://www.jetbrains.com/help/idea/spring-projects.html, ну или поднятие Spring контекста в других тестах.
6) методы-интеграторы: методы, единственная цель которых - вызывать другие методы. Как правило находятся в сервисах. Во-первых код теста получается хрупким, т.к. с новыми релизами добавляются новые вызовы. А во-вторых приходится писать кучу моков. А главное логики особо нет, кроме правильной последовательности вызовов и передачи данных по цепочке. Если появляется более сложная логика - валидация данных, проверка прав - тест будет иметь смысл. Иначе можно пропустить, а лучше написать интеграционный тест, включающий вызов такого метода-интегратора.
7) методы, конструирующие DTO для слоя API. DTO использовать нужно, чтобы развязать доменные сущности и API. Но такой код часто представляет просто mapping. С одной стороны какая-то практическая польза в такой проверке есть: данные должны быть в нужном формате - JSON, должны быть какие-то обязательные поля, нужно убедится, что данные из модели попали в ответ. С другой стороны если валидировать сравнением с эталонным JSON - тест получается хрупким. Решение - метод тестировать, но проверять результат преобразования точечно, фокусироваться на том, что скорее всего не изменится в будущем.
В заключение вот хорошая статья на тему написания правльных тестов https://habr.com/ru/company/jugru/blog/323920/
#unittests #Java
GitHub
filtering JAVAC.SYNTHMETH
:microscope: Java Code Coverage Library. Contribute to jacoco/jacoco development by creating an account on GitHub.
Всем привет!
Раз уж заговорили про тесты расскажу про отладку и тестирование Jenkins pipeline. Для начала: отладка и тестирование Jenkins pipeline - это боль(((
Почему?
1) pipeline пишется на Groovy, а Groovy - это язык с динамической типизацией. Динамическая типизация хорошо подходит для небольших скриптов, но как только кода становится много - код сыпется, править его становится страшно.
Да, есть аннотация @groovy.transform.CompileStatic, но см. п.2
2) pipeline пишется не просто на Groovy, а на Groovy DSL. Стандартный Jenkins предоставляет ряд команд, они же шаги, плюс их число расширяется плагинами. Список см. https://www.jenkins.io/doc/pipeline/steps/
Т.е классов, описывающих синтаксис pipeline просто нет.
3) чтобы протестировать pipeline вживую нужно время. На ожидание свободного Jenkins slave, на скачивание кода пайплайн. Т.е. цикл обратной связи получается большим.
Что же можно сделать.
1) как только пайплайн перестает быть элементарным или появляется общий код - выносим его в shared library: https://www.jenkins.io/doc/book/pipeline/shared-libraries/
Она может содержать как DSL - в папке vars, так и обычные Groovy классы в папке src. А на обычные классы можно и нужно писать модульные тесты.
Как вариант - пайплайн и библиотека могут быть в одном репозитории, тогда библиотеку из pipeline можно загрузить так:
library identifier: "selflib@${scm.branches[0]}", retriever: legacySCM(scm)
В скрипте pipeline, который указан в джобе, оставляем минимум кода. Почему это полезно кроме упрощения тестирования - код в pipeline по сути является статическим инициализатором и выполняется одновременно с загрузкой в память скрипта pipeline.
2) Максимум кода выносим в src, т.к. его легко тестировать и код можно писать как будто это не скрипт сборки, а приложение для CI\CD.
Собственно именно так к коду и нужно относится.
3) создаем проект. Логичным выглядит использование Gradle, т.к у нас все-таки Groovy.
Вы можете вызывать в своем коде Java и Groovy стандартные библиотеки, следовательно, чтобы подсветка синтаксиса и автоподстановка работали, надо соответствующим образом настроить проект.
Кроме того стоит добавить в проект зависимости Jenkins Core и плагины. Я говорил, что для шагов pipeline нет соответствующих классов, но кроме шагов у Jenkins есть открытое и полузакрытое API, которое можно вызвать из PIpeline.
Примеры:
com.cloudbees.groovy.cps.NonCPS
hudson.AbortException
Полный список библиотек в сети я не нашел, да и не нужен он, я гуглил по нужным мне классам. Если нужен моя заготовка - обращайтесь.
4) подключаем в проект GDSL https://www.tothenew.com/blog/gdsl-awesomeness-introduction-to-gdsl-in-intellij-idea/
Это механизм, позволяющий объявить контекст, это может быть контекст Jenkins scripts, контекст определенного класса, контекст Groovy closure, контекст Closure внутри другого Closure в определенным именем... и объявить какие методы и свойства доступны в этом контексте.
IDEA умеет подсвечивать синтактсис и автодополнять код по GDSL https://st-g.de/2016/08/jenkins-pipeline-autocompletion-in-intellij
Есть одна тонкость - файл нужно скачивать из своего Jenkins, чтобы файл с описанием DSL включал методы из ваших плагинов Jenkins.
При этом гарантии, что полученный GDSL будет включать все нет, это не так, т.к. зависит от добросовестности авторов плагинов. Я файл дописывал, добавляя недостающее и корректируя типы.
4) с GDSL есть одна засада. Он работает в скриптах с DSL кодом, но не в исходниках из папки src. Т.к контест другой. А часто ваши классы будут обвертками над вызовами pipeline DSL.
Решение есть - из скрипта передаем this, это контекст скрипта, он содержит все доступные DSL методы, в классе объявляем поле groovy.lang.Script script и модифицируем GDSL файл, добавляя все методы и свойства DSL в контекст класса groovy.lang.Script.
vars/process.groovy
...
def processor = new Processor(this)
...
src/Processor.groovy
@TupleConstructor
class Processor {
Script script
}
Раз уж заговорили про тесты расскажу про отладку и тестирование Jenkins pipeline. Для начала: отладка и тестирование Jenkins pipeline - это боль(((
Почему?
1) pipeline пишется на Groovy, а Groovy - это язык с динамической типизацией. Динамическая типизация хорошо подходит для небольших скриптов, но как только кода становится много - код сыпется, править его становится страшно.
Да, есть аннотация @groovy.transform.CompileStatic, но см. п.2
2) pipeline пишется не просто на Groovy, а на Groovy DSL. Стандартный Jenkins предоставляет ряд команд, они же шаги, плюс их число расширяется плагинами. Список см. https://www.jenkins.io/doc/pipeline/steps/
Т.е классов, описывающих синтаксис pipeline просто нет.
3) чтобы протестировать pipeline вживую нужно время. На ожидание свободного Jenkins slave, на скачивание кода пайплайн. Т.е. цикл обратной связи получается большим.
Что же можно сделать.
1) как только пайплайн перестает быть элементарным или появляется общий код - выносим его в shared library: https://www.jenkins.io/doc/book/pipeline/shared-libraries/
Она может содержать как DSL - в папке vars, так и обычные Groovy классы в папке src. А на обычные классы можно и нужно писать модульные тесты.
Как вариант - пайплайн и библиотека могут быть в одном репозитории, тогда библиотеку из pipeline можно загрузить так:
library identifier: "selflib@${scm.branches[0]}", retriever: legacySCM(scm)
В скрипте pipeline, который указан в джобе, оставляем минимум кода. Почему это полезно кроме упрощения тестирования - код в pipeline по сути является статическим инициализатором и выполняется одновременно с загрузкой в память скрипта pipeline.
2) Максимум кода выносим в src, т.к. его легко тестировать и код можно писать как будто это не скрипт сборки, а приложение для CI\CD.
Собственно именно так к коду и нужно относится.
3) создаем проект. Логичным выглядит использование Gradle, т.к у нас все-таки Groovy.
Вы можете вызывать в своем коде Java и Groovy стандартные библиотеки, следовательно, чтобы подсветка синтаксиса и автоподстановка работали, надо соответствующим образом настроить проект.
Кроме того стоит добавить в проект зависимости Jenkins Core и плагины. Я говорил, что для шагов pipeline нет соответствующих классов, но кроме шагов у Jenkins есть открытое и полузакрытое API, которое можно вызвать из PIpeline.
Примеры:
com.cloudbees.groovy.cps.NonCPS
hudson.AbortException
Полный список библиотек в сети я не нашел, да и не нужен он, я гуглил по нужным мне классам. Если нужен моя заготовка - обращайтесь.
4) подключаем в проект GDSL https://www.tothenew.com/blog/gdsl-awesomeness-introduction-to-gdsl-in-intellij-idea/
Это механизм, позволяющий объявить контекст, это может быть контекст Jenkins scripts, контекст определенного класса, контекст Groovy closure, контекст Closure внутри другого Closure в определенным именем... и объявить какие методы и свойства доступны в этом контексте.
IDEA умеет подсвечивать синтактсис и автодополнять код по GDSL https://st-g.de/2016/08/jenkins-pipeline-autocompletion-in-intellij
Есть одна тонкость - файл нужно скачивать из своего Jenkins, чтобы файл с описанием DSL включал методы из ваших плагинов Jenkins.
При этом гарантии, что полученный GDSL будет включать все нет, это не так, т.к. зависит от добросовестности авторов плагинов. Я файл дописывал, добавляя недостающее и корректируя типы.
4) с GDSL есть одна засада. Он работает в скриптах с DSL кодом, но не в исходниках из папки src. Т.к контест другой. А часто ваши классы будут обвертками над вызовами pipeline DSL.
Решение есть - из скрипта передаем this, это контекст скрипта, он содержит все доступные DSL методы, в классе объявляем поле groovy.lang.Script script и модифицируем GDSL файл, добавляя все методы и свойства DSL в контекст класса groovy.lang.Script.
vars/process.groovy
...
def processor = new Processor(this)
...
src/Processor.groovy
@TupleConstructor
class Processor {
Script script
}
Pipeline Steps Reference
Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software
Может возникнуть вопрос - что такое groovy.lang.Script? По сути это аналог Object для Groovy скриптов. Да, в Groovy код может быть не только в классах, но и в скриптах https://docs.groovy-lang.org/latest/html/documentation/#_scripts_versus_classes
5) В API своих классов не используем def, всегда объявляем типы явно.
def - это как var в Java, но опаснее, т.к в отличие от Java его можно использовать везде вместо указания типа. Как по мне - использовать def можно только для локальных переменных, т.е по сути я за подход Java.
6) кроме подсветки синтаксиса рекомендую периодически вызывать Inspect Code в IDEA, а лучше повесить его на commit. Не все проверки по умолчанию актуальны для Jenkins pipeline кода, лишние можно отключить.
7) ну и возвращаясь к тестам - по максимуму покрываем код в src тестами. Можно использовать JUnit и Mockito. Тесты при этом пишем на Groovy, чтобы воспользоваться преимуществом компактного синтаксиса Groovy.
to be continued
#devops #ci #unittests #jenkins #groovy
5) В API своих классов не используем def, всегда объявляем типы явно.
def - это как var в Java, но опаснее, т.к в отличие от Java его можно использовать везде вместо указания типа. Как по мне - использовать def можно только для локальных переменных, т.е по сути я за подход Java.
6) кроме подсветки синтаксиса рекомендую периодически вызывать Inspect Code в IDEA, а лучше повесить его на commit. Не все проверки по умолчанию актуальны для Jenkins pipeline кода, лишние можно отключить.
7) ну и возвращаясь к тестам - по максимуму покрываем код в src тестами. Можно использовать JUnit и Mockito. Тесты при этом пишем на Groovy, чтобы воспользоваться преимуществом компактного синтаксиса Groovy.
to be continued
#devops #ci #unittests #jenkins #groovy
Продолжим про тестирование кода джобов Jenkins.
Что еще у нас есть для тестирования.
8) JenkinsPipelineUnit - https://github.com/jenkinsci/JenkinsPipelineUnit По сути набор моков для запуска кода pipeline.
Что может:
а) запуск пайплайн из файла и из строки
б) передача параметров и переменных среды
в) проверка статуса выполнения джобы
г) моки для ряда методов pipeline
д) загрузка shared library
е) возможность добавлять свои моки на команды pipeline или конкретные вызовы sh
ж) печать стектрейса выполнения pipeline
з) сравнение стректрейсов, поиск по вхождению - можно искать были ли выполнена та или иная команда
Из мелких косяков - требует наследования тестового класса от BasePipelineTest, что вышло из моды с появлением Unit 4)))
Из более крупных косяков - по умолчанию многие команды Jenkins DSL не замоканы, при появлении такой команды джоба падает.
То что падает - это правильно, мы же тестируем pipeline. Но часто приходится писать свои mock, примеры: readYaml, readProperties, findFiles.
Mock по умолчанию - ничего не делать. echo выводит данные в лог на машине разработчика.
Могу рекомендовать с ремаркой - моки придется дописывать.
9) Jenkins Test Harness - https://www.jenkins.io/doc/developer/testing/,
Это интеграционное тестирование pipeline. В документации фреймворк предлагается для тех, кто разрабатывает Jenkins или плагины для него.
Можно ли использовать для тестирования своего pipeline и shared libraries - вопрос, дам на него ответ позже.
Коммиты в репозитории есть с 2016 года, но в документации по ссылке выше до сих пор встречаются TODO.
Подключение к тестам в примерах происходит через Rule из JUnit 4 - что тоже намекает.
Что он может:
а) б) в) из списка выше
г) мок для загрузки из SCM
д) проверка записей в логе - как я понял, это в большинстве случаев будет заменой Assert
е) загрузка файлов из среды разработки в workspace
Пока рекомендовать не могу, буду исследовать.
10) com.mkobit.jenkins.pipelines.shared-library - https://github.com/mkobit/jenkins-pipeline-shared-libraries-gradle-plugin,
Это плагин Gradle для разработки shared libraries. Включает в себя два предыдущих фреймворка. Есть тестовый репо https://github.com/mkobit/jenkins-pipeline-shared-library-example, если взять его как основу для своего проекта - получите из коробки подключение ряда библиотек Jenkins для declarative pipeline, некую версию gdsl и готовый проект, который содержит модульные и интеграционные тесты и проходит build.
Выглядит интересно для начала разработки, я к сожалению в свое время его упустил, по сути сделав аналогичный каркас)
Причем для разработки scripted pipeline мой каркас подходит лучше)
Пока рекомендовать не могу, учитывая комментарии выше.
11) любые тесты не на 100% заменяют запуск с реальными интеграциями. Как организовать интеграционное и функциональное тестирование pipeline, что для этого нужно?
а) создаем или копируем тестовый Java проект, который будем собирать. Ключевое требование - небольшой размер кода, чтобы сборка была быстрой и максимальное использование фичей pipeline. Использование настоящих проектов - плохо, т.к. создаются левые tags, build statuses, что может вводить разработчиков в заблуждение
б) тестовые джобы на Jenkins для всех созданных вами pipeline. Можно даже создать джобу, запускающую в параллель все эти джобы
в) тестовый проект SonarQube
г) тестовые репозитории в Nexus\Artifactory
д) тестовый проект на вашем Git сервере если джобы что-то делают в Git
е) важно: описываем в документации чек-лист - что и когда нужно тестировать при внесении изменений в pipeline
ж) придеживаемся описанных нами правил, это важно)
#devops #ci #unittests #jenkins #groovy
Что еще у нас есть для тестирования.
8) JenkinsPipelineUnit - https://github.com/jenkinsci/JenkinsPipelineUnit По сути набор моков для запуска кода pipeline.
Что может:
а) запуск пайплайн из файла и из строки
б) передача параметров и переменных среды
в) проверка статуса выполнения джобы
г) моки для ряда методов pipeline
д) загрузка shared library
е) возможность добавлять свои моки на команды pipeline или конкретные вызовы sh
ж) печать стектрейса выполнения pipeline
з) сравнение стректрейсов, поиск по вхождению - можно искать были ли выполнена та или иная команда
Из мелких косяков - требует наследования тестового класса от BasePipelineTest, что вышло из моды с появлением Unit 4)))
Из более крупных косяков - по умолчанию многие команды Jenkins DSL не замоканы, при появлении такой команды джоба падает.
То что падает - это правильно, мы же тестируем pipeline. Но часто приходится писать свои mock, примеры: readYaml, readProperties, findFiles.
Mock по умолчанию - ничего не делать. echo выводит данные в лог на машине разработчика.
Могу рекомендовать с ремаркой - моки придется дописывать.
9) Jenkins Test Harness - https://www.jenkins.io/doc/developer/testing/,
Это интеграционное тестирование pipeline. В документации фреймворк предлагается для тех, кто разрабатывает Jenkins или плагины для него.
Можно ли использовать для тестирования своего pipeline и shared libraries - вопрос, дам на него ответ позже.
Коммиты в репозитории есть с 2016 года, но в документации по ссылке выше до сих пор встречаются TODO.
Подключение к тестам в примерах происходит через Rule из JUnit 4 - что тоже намекает.
Что он может:
а) б) в) из списка выше
г) мок для загрузки из SCM
д) проверка записей в логе - как я понял, это в большинстве случаев будет заменой Assert
е) загрузка файлов из среды разработки в workspace
Пока рекомендовать не могу, буду исследовать.
10) com.mkobit.jenkins.pipelines.shared-library - https://github.com/mkobit/jenkins-pipeline-shared-libraries-gradle-plugin,
Это плагин Gradle для разработки shared libraries. Включает в себя два предыдущих фреймворка. Есть тестовый репо https://github.com/mkobit/jenkins-pipeline-shared-library-example, если взять его как основу для своего проекта - получите из коробки подключение ряда библиотек Jenkins для declarative pipeline, некую версию gdsl и готовый проект, который содержит модульные и интеграционные тесты и проходит build.
Выглядит интересно для начала разработки, я к сожалению в свое время его упустил, по сути сделав аналогичный каркас)
Причем для разработки scripted pipeline мой каркас подходит лучше)
Пока рекомендовать не могу, учитывая комментарии выше.
11) любые тесты не на 100% заменяют запуск с реальными интеграциями. Как организовать интеграционное и функциональное тестирование pipeline, что для этого нужно?
а) создаем или копируем тестовый Java проект, который будем собирать. Ключевое требование - небольшой размер кода, чтобы сборка была быстрой и максимальное использование фичей pipeline. Использование настоящих проектов - плохо, т.к. создаются левые tags, build statuses, что может вводить разработчиков в заблуждение
б) тестовые джобы на Jenkins для всех созданных вами pipeline. Можно даже создать джобу, запускающую в параллель все эти джобы
в) тестовый проект SonarQube
г) тестовые репозитории в Nexus\Artifactory
д) тестовый проект на вашем Git сервере если джобы что-то делают в Git
е) важно: описываем в документации чек-лист - что и когда нужно тестировать при внесении изменений в pipeline
ж) придеживаемся описанных нами правил, это важно)
#devops #ci #unittests #jenkins #groovy
GitHub
GitHub - jenkinsci/JenkinsPipelineUnit: Framework for unit testing Jenkins pipelines
Framework for unit testing Jenkins pipelines . Contribute to jenkinsci/JenkinsPipelineUnit development by creating an account on GitHub.
Всем привет!
Практически не писал про Kotlin, хотя он есть в названии канала. Надо исправляться.
Первый вопрос, который возникает при упоминании Kotlin - зачем он нужен, есть же Java?
Отвечаю:
1) Null safety - на уровне объявления типа мы говорим, допускает поле null или нет. Т.об. можно избежать NPE в Kotlin коде. Почему оговорка про Kotlin код - если передать значение в Java код - там работают правила Java
https://kotlinlang.org/docs/null-safety.html
2) встроенная в язык иммутабельность - var и val. При объявлении свойства или локальной переменной мы обязаны указать может ли оно меняться. В отличие от Java где объевление const опционально и его можно забыть
https://kotlinlang.org/docs/properties.html#delegated-properties
3) гора синтаксического сахара. Многие относятся к сахару пренебрежительно, ну типа и без него можно написать хороший код, это баловство. Да, можно написать хороший код практически на любом языке. Но я бы сместил акцент на читаемость. В основном мы код читаем, а не пишем - свой или чужой. И при чтении краткость помогает. Конечно, при условии что синтаксис языка тебе понятен) Тут я бы противопоставил Kotlin и Scala, т.к. Scala исходя из моего опыта подталкивает разработчика к тому, чтобы написать такую одну строчку кода, чтобы с первого раза никто не понял - что она делает. Этот подход - зло, если надо проектом работает более одного человека. А т.к. все меняется - даже один человек может уволится или забросить код, то такие строчки - всегда зло.
Ссылку на спецификацию языка давать не буду - можно ссылаться на все разделы: свойства классов, отсутствие ;, можно опускать {} для простых классов, упрощенный синтаксис primary конструктора, отсутствие new, single expression functions, data классы (хотя тут Java 17 подтянулась), elvis оператор, ranges, функции области видимости, repeat, алиасы для import, print, функция main без класса ...
Часть этих фичей дает Lombok, по некоторым Java потихоньку догоняет Kotlin. Но плюс Kotlin в том, что у него их больше и они предоставляются на чистом JDK 8+
4) корутины - как альтернативный подход к многопоточности, когда код выглядит однопоточным, но выполняется параллельно. Корутины - отдельная большая тема, я к ней вернусь. Для начала могу сказать только одно - сначала изучите, потом применяйте. Это везде важно, но с корутинами особенно)
https://kotlinlang.org/docs/coroutines-overview.html
5) единообразие в конструкциях языка. Примеры: все есть классы, нет неявных преобразований, можно переопределять операции (т.е. плюсовать не только String), функция всегда возвращает ответ, var\val сюда же. Это упрощает обучение языку с нуля, сообственно такую цель ставили авторы языка. Ну и еще упростить работу коллегам, отвечающим за статический анализ кода в IDEA)
6) легкость создания DSL на Kotlin. Фактически за счет двух кусков синтаксического сахара: - возможность опустить круглые скобки у метода и возможность inline передать одну функцию в другую мы получаем вот такой код
func1 {
code of func 2
}
#kotlin #java
Практически не писал про Kotlin, хотя он есть в названии канала. Надо исправляться.
Первый вопрос, который возникает при упоминании Kotlin - зачем он нужен, есть же Java?
Отвечаю:
1) Null safety - на уровне объявления типа мы говорим, допускает поле null или нет. Т.об. можно избежать NPE в Kotlin коде. Почему оговорка про Kotlin код - если передать значение в Java код - там работают правила Java
https://kotlinlang.org/docs/null-safety.html
2) встроенная в язык иммутабельность - var и val. При объявлении свойства или локальной переменной мы обязаны указать может ли оно меняться. В отличие от Java где объевление const опционально и его можно забыть
https://kotlinlang.org/docs/properties.html#delegated-properties
3) гора синтаксического сахара. Многие относятся к сахару пренебрежительно, ну типа и без него можно написать хороший код, это баловство. Да, можно написать хороший код практически на любом языке. Но я бы сместил акцент на читаемость. В основном мы код читаем, а не пишем - свой или чужой. И при чтении краткость помогает. Конечно, при условии что синтаксис языка тебе понятен) Тут я бы противопоставил Kotlin и Scala, т.к. Scala исходя из моего опыта подталкивает разработчика к тому, чтобы написать такую одну строчку кода, чтобы с первого раза никто не понял - что она делает. Этот подход - зло, если надо проектом работает более одного человека. А т.к. все меняется - даже один человек может уволится или забросить код, то такие строчки - всегда зло.
Ссылку на спецификацию языка давать не буду - можно ссылаться на все разделы: свойства классов, отсутствие ;, можно опускать {} для простых классов, упрощенный синтаксис primary конструктора, отсутствие new, single expression functions, data классы (хотя тут Java 17 подтянулась), elvis оператор, ranges, функции области видимости, repeat, алиасы для import, print, функция main без класса ...
Часть этих фичей дает Lombok, по некоторым Java потихоньку догоняет Kotlin. Но плюс Kotlin в том, что у него их больше и они предоставляются на чистом JDK 8+
4) корутины - как альтернативный подход к многопоточности, когда код выглядит однопоточным, но выполняется параллельно. Корутины - отдельная большая тема, я к ней вернусь. Для начала могу сказать только одно - сначала изучите, потом применяйте. Это везде важно, но с корутинами особенно)
https://kotlinlang.org/docs/coroutines-overview.html
5) единообразие в конструкциях языка. Примеры: все есть классы, нет неявных преобразований, можно переопределять операции (т.е. плюсовать не только String), функция всегда возвращает ответ, var\val сюда же. Это упрощает обучение языку с нуля, сообственно такую цель ставили авторы языка. Ну и еще упростить работу коллегам, отвечающим за статический анализ кода в IDEA)
6) легкость создания DSL на Kotlin. Фактически за счет двух кусков синтаксического сахара: - возможность опустить круглые скобки у метода и возможность inline передать одну функцию в другую мы получаем вот такой код
func1 {
code of func 2
}
#kotlin #java
Kotlin Help
Null safety | Kotlin
Всем привет!
Продолжим про Kotlin.
Есть ли у него минусы? А точнее какие могут быть косяки в коде Kotlin, вызванные в том числе неправильным использованием языка.
Немного накину по своему опыту.
1) злоупотребление контекстными функциями типа also.
https://kotlinlang.org/docs/scope-functions.html
На примере also - он нужен если в коде используются поля и методы объекта контекста - it. Если можно просто две написать последовательные строчки кода - лучше так и сделать.
obj.doSomething().also { doAnotherImportantBusinessLogic() } - плохо
obj.doSomething()
doAnotherImportantBusinessLogic()
- хорошо
2) злоупотребление Extension functions
https://kotlinlang.org/docs/extensions.html
Extension functions конечно крутая штука, но она ухудшает читаемость кода, т.к. код класса размазывается по нескольким файлам. Т.е. использовать ее нужно только если очень нужно)
И если очень нужно и это extension библиотечного типа - поместить его в класс, а не как top level функцию с пакетной видимостью.
3) использование упрощенного синтаксиса для объявления метода + контекстные функции приводят к тому, что Single expression function превращается в Very Big Expression Function и, соответственно, ухудшается читаемость кода метода.
fun transform(x: String): Result<Type1, Type2> = Result(doSomething()).also {
code
other code
another code
more code
....
}
Собственно похожая проблема будет если злоупотреблять method chaining
obj.prepare(...).recieve().handleSuccees(..).log(...).postHandle(..)...
Хочу обратить внимание на два момента - злоупотребление=применение ради применения и читаемость кода. Я думаю это два хороших критерия для ответа на вопрос - стоит ли применять ту или иную фичу.
#kotlin #cleancode
Продолжим про Kotlin.
Есть ли у него минусы? А точнее какие могут быть косяки в коде Kotlin, вызванные в том числе неправильным использованием языка.
Немного накину по своему опыту.
1) злоупотребление контекстными функциями типа also.
https://kotlinlang.org/docs/scope-functions.html
На примере also - он нужен если в коде используются поля и методы объекта контекста - it. Если можно просто две написать последовательные строчки кода - лучше так и сделать.
obj.doSomething().also { doAnotherImportantBusinessLogic() } - плохо
obj.doSomething()
doAnotherImportantBusinessLogic()
- хорошо
2) злоупотребление Extension functions
https://kotlinlang.org/docs/extensions.html
Extension functions конечно крутая штука, но она ухудшает читаемость кода, т.к. код класса размазывается по нескольким файлам. Т.е. использовать ее нужно только если очень нужно)
И если очень нужно и это extension библиотечного типа - поместить его в класс, а не как top level функцию с пакетной видимостью.
3) использование упрощенного синтаксиса для объявления метода + контекстные функции приводят к тому, что Single expression function превращается в Very Big Expression Function и, соответственно, ухудшается читаемость кода метода.
fun transform(x: String): Result<Type1, Type2> = Result(doSomething()).also {
code
other code
another code
more code
....
}
Собственно похожая проблема будет если злоупотреблять method chaining
obj.prepare(...).recieve().handleSuccees(..).log(...).postHandle(..)...
Хочу обратить внимание на два момента - злоупотребление=применение ради применения и читаемость кода. Я думаю это два хороших критерия для ответа на вопрос - стоит ли применять ту или иную фичу.
#kotlin #cleancode
Привет!
Большинство DevOps pipeline, что я видел, мягко говоря не быстрые. Даже в теории чтобы просто докатить commit до ПРОМа нужны часы. Возможно у компаний с лучшими практиками DevOps это десятки минут. Можно ли быстрее?
Теоретически - да, и существует даже действующая модель:
https://medium.com/darklang/how-dark-deploys-code-in-50ms-771c6dd60671
https://docs.darklang.com/tutorials/first-dark-application#open-the-editor
В чем суть: ребята объединили язык, среду разработки, среду выполнения, хранилище данных и DevOps включая запуск тестов в одном продукте. В язык и среду встроены feature toggles, т.е. любое несовместимое изменение должно включаться по своему feature toggle. Естественно в выключенном состоянии. Это касается кода, таблиц в БД, новых библиотек. Таблицы и библиотеки получают новые версии, использование которых нужно явно включать. Сохранение срочки кода = commit. Невалидный код сохранить нельзя. Коммит идет сразу на ПРОМ после прогона тестов. Возможности языка ограничены, т.к. среда управляет инфраструктурой. По сути получаем serverless. Среда хранит логи и трасировки запросов, в т.ч. невалидные запросы, для последних можно быстро создать обработчик, т.е. получаем trace based development.
Мои выводы по результатам краткого знакомства.
1) концепт интересный, я бы даже сказал крутой
2) разработка в браузере смущает
3) возможности языка ограничены, но возможно спасают библиотеки
4) и главное - непонятно как с этим работать более чем одному разработчику и\или если число строк кода более 100. Если разработчики где-то будут пересекаться по коду - есть риск, что они не будут знать про чужие feature toggles и проверять их не будут. Или если фича большая, включает десятки функций и обработчиков, а у каждого свой feature toggle, спроектировать и проверить их в нужном порядке не совсем элементарная задача. В обоих случаях получаем feature toggle hell.
Но концепт красивый)
#devops #lang #concepts
Большинство DevOps pipeline, что я видел, мягко говоря не быстрые. Даже в теории чтобы просто докатить commit до ПРОМа нужны часы. Возможно у компаний с лучшими практиками DevOps это десятки минут. Можно ли быстрее?
Теоретически - да, и существует даже действующая модель:
https://medium.com/darklang/how-dark-deploys-code-in-50ms-771c6dd60671
https://docs.darklang.com/tutorials/first-dark-application#open-the-editor
В чем суть: ребята объединили язык, среду разработки, среду выполнения, хранилище данных и DevOps включая запуск тестов в одном продукте. В язык и среду встроены feature toggles, т.е. любое несовместимое изменение должно включаться по своему feature toggle. Естественно в выключенном состоянии. Это касается кода, таблиц в БД, новых библиотек. Таблицы и библиотеки получают новые версии, использование которых нужно явно включать. Сохранение срочки кода = commit. Невалидный код сохранить нельзя. Коммит идет сразу на ПРОМ после прогона тестов. Возможности языка ограничены, т.к. среда управляет инфраструктурой. По сути получаем serverless. Среда хранит логи и трасировки запросов, в т.ч. невалидные запросы, для последних можно быстро создать обработчик, т.е. получаем trace based development.
Мои выводы по результатам краткого знакомства.
1) концепт интересный, я бы даже сказал крутой
2) разработка в браузере смущает
3) возможности языка ограничены, но возможно спасают библиотеки
4) и главное - непонятно как с этим работать более чем одному разработчику и\или если число строк кода более 100. Если разработчики где-то будут пересекаться по коду - есть риск, что они не будут знать про чужие feature toggles и проверять их не будут. Или если фича большая, включает десятки функций и обработчиков, а у каждого свой feature toggle, спроектировать и проверить их в нужном порядке не совсем элементарная задача. В обоих случаях получаем feature toggle hell.
Но концепт красивый)
#devops #lang #concepts
Medium
How Dark deploys code in 50ms
Speed of developer iteration is the single most important factor in how quickly a technology company can move. In Dark, deploys take 50ms!