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

Сегодня побуду немного вашим кэпом, он же капитан очевидность))))
Не так давно писал про то, как важна "гигиена" в настройках с точки зрения сопровождения - неочевидные названия, дублирование, неиспользуемые настройки могут ввести в заблуждение и привести к ошибкам на ПРОМе.
Хочется развить эту тему.
На самом деле "костыли" и "мусор" вредны не только в настройках, но и в коде, в документации, в тестах. Даже если единственный потребитель - это сам разработчик, который их написал.
Представьте, что код, написанный сегодня, вы не будете трогать полгода. А через полгода прилетит большая задача, требующая этот код серьезно отрефакторить. Разберетесь в своем коде?))) Или проще сразу выкинуть и переписать?)
Ясно, что задача поддерживать код в чистоте, нелегка. Но в отличии от природы, сам код не очистится)))
Нужно выделять время на чистку. Нужно, чтобы "причесывание" кода вошло в привычку.
Небольшое отступление - выделять фиксированное время. "Причесывание", которое занимает больше времени, чем написание кода - не айс.
На какие вещи стоит обратить особое внимание:
1) неиспользуемый код и настройки, ненужные зависимости. IDEA вам в помощь в их поиске.
2) дублирование кода. Тут поможет SonarQube
3) неочевидные названия классов, полей, методов, настроек
4) уже не актуальные названия: класс изменил свой функционал, к классу добавился функционал и название его не отражает
5) код, по которому не непонятно, что он делает. Здесь конечно важен взгляд со стороны. Но если код непонятен внешнему наблюдателю, то через полгода он будет непонятен и вам. Ну и обычно это огромные методы, при просмотре сложно в голове удержать весь алгоритм.
6) рассинхрон кода и документации. Лучше всего, если документации будет мало или она будет генерироваться по коду. Имеет смысл описывать или общие вещи, например, как использовать и собирать ваш сервис, или код, назначение которого неочевидно, например, из-за бизнес-требований.
7) хардкод. Иногда можно, особенно как временное решение, главное не забывать о рефакторинге.

Что я забыл?

А так как я люблю читать и советовать книги - не могу не вспомнить и не порекомендовать классику: Чистый код Роберта Мартина https://www.litres.ru/book/chistyy-kod-sozdanie-analiz-i-refaktoring-6444478
Конспект по книге: https://habr.com/ru/post/485118/

#clean_code
Всем привет!

Есть типичный пример плохого кода - большие процедуры, десятки или даже сотня строк каждая, неговорящие имена переменных, клубок вызовов, также известный как спагетти код. А тут прилетает задача - сервис нужно доработать, добавив какую-то важную проверку.
Есть техники для борьбы с плохим кодом. В первую очередь это собственно ООП - разделение кода по классам. Потом можно применить принцип единственной ответственности - каждый класс и метод отвечает за что-то одно. Далее идут принципы, описанные в книге "Чистый код" - понятные наименования, небольшие методы. Можно еще заполировать все это DDD - выделив ограниченный контекст. И разделить код по слоям, например, используя гексагональную архитектуру. Или даже разделить на микросервисы)
В результате получим десятки маленьких объектов, с четкой областью ответственности, хорошо читаемый код в каждом методе.
Но можно упустить важный момент - после выполнения всех доработок понять как работает система в целом (!) все равно будет сложно. Т.к. система стала слишком большой и сложной. И тут на приходит на помощь принцип KISS - Keep it simple. Перед тем, как начинать проектировать и кодить стоит задать вопрос - нужна ли еще одна валидация в коде? Может она уже есть в микросервисе, из которого мы получаем данные? Может вероятность появления таких данных в ПРОМ (PROD) стремится к нулю? Может можно подключить внешнюю библиотеку, где все уже сделано до нас?
В общем не забывайте про KISS)

#arch #clean_code #principles
Всем привет!

В продолжение темы функциональности IDEA и подготовки кода к code review, см. https://t.me/javaKotlinDevOps/148
Некоторые проверки и исправления можно подвесить на одно из двух событий:
1) на сохранение файла: Alt-Alt - Actions on Save. Рекомендую включить Reformat code и Optimize import.
2) перед commit на Git сервер - открыть окно Commit (Ctrl-K) и нажать там шестеренку. Рекомендую включить Analyze code, Check TODO и если выполнение тестов занимает приемлемое время - то еще и прогон тестов.
Легко заметить, что набор опций в обоих случаях похож, но на сохранении можно включить только те, где фиксы применяются без участия человека. В частности и Cleanup, и Analyze выполняют правила из набора инспекций (Inspections), только в первом случае включаются только те правила, где есть quick fixes, которые можно применить автоматически.
Насчет Cleanup - IMHO его вполне можно включить на commit, главное перепроверить набор активных правил: Shift-Shift - Inspections, а там включить фильтр Cleanup only. К слову - там еще есть профили с набором правил, можно добавить свой.
И еще важный момент - инспекции из IDEA можно запустить из командной строки, и т.об. включить в CI процесс: https://www.jetbrains.com/help/idea/command-line-code-inspector.html
Они частично повторяют проверки SonarQube, но не идентичны им.

#idea #code_review #clean_code #git
Всем привет!

Я часто пишу о важности такой характеристике кода, как читаемость. И надеюсь, что все понимают, почему она важна) Но понимать и делать - это разные вещи. Поэтому вот ещё один довод задуматься о читаемости кода. У разработчиков есть одна интересная особенность - если код им кажется непонятным - возникает сильное желание его переписать.
Если хотите, чтобы ваш код прожил подольше - подумайте о читаемости заранее)

P.S. Этот же аргумент говорит о важности код-ревью - как внешнего взгляда на ваш код

#clean_code
Всем привет!

Я часто вижу в проектах лишние настройки. Как правило, они попадают в проект следующими путями:
1) скопировали из каркаса\образца\соседнего сервиса не задумываясь - нужны эти настройки или нет. Да, принцип "работает - не трогай" встречается и у разработчиков)
2) решили явно прописать какие-то настройки, так сказать для надежности

Я считаю, что так делать не надо. Почему?

1) лишние настройки раскрывают нам лишние детали, которые или не нужны вообще, или нужны, но не сейчас. Повышается когнитивная сложность кода. Знать все детали своего сервиса - это хороший подход, был, лет 10-20 назад. Сейчас ПО очень сильно развилось в плане специализации, количество зависимостей среднего проекта - несколько сотен, поэтому знать все детали просто невозможно.
2) следствие из сказанного выше - ухудшается читаемость кода. Да, это моя любимая тема. Мы чаще читаем код, чем пишем. Настройки тоже часть кода.
3) среди скопированных настроек могут быть не нужные в данный момент. Код легко меняется, ТЗ меняется также легко, поэтому добавлять что-то "на вырост" не стоит
4) портянка настроек, в которую что-то постоянно добавляется, может превратится в некий аналог "большого кома грязи", который будут боятся трогать. Как разработчики, так и сопровождение. Чтобы этого не допускать - настройки нужно чистить. Чтобы меньше было чистить - не нужно добавлять лишнее. Как-то так)

А вообще есть такой хороший принцип, описывающий то, что я хочу сказать: convention over configuration. Тоже одна из моих любимых тем. Принцип говорит о том, что должны быть некие настройки по умолчанию, устраивающие большинство потребителей. Эти настройки потребитель не задает, они заданы где-то внутри сервера или библиотеки.

#clean_code #configuration #conv_over_conf
Всем привет!

Я уже писал про то, что не люблю код, в котором интерфейсы делаются ради интерфейсов. Самый яркий антипаттерн: интерфейс с единственной реализацией, лежащей рядом. Подозреваю, одной из причин такого проектирования является принцип Dependency Inversion - в модели должны быть интерфейсы, а в сервисном слое - их реализации. И они разнесены по разным слоям приложения. Тут вроде все сходится?
Как бы да, но я нашел интересное возражение: https://habr.com/ru/articles/888428/
Как всегда побуду в роли ChatGPT) Суть статьи, а точнее продвигаемого там принципа структурного дизайна в том, что вместо создания интерфейса, любой сложный сервис можно отрефакторить (или спроектировать), выделив 3 метода:

1) чтение - все интеграции по чтению из внешних источников
2) бизнес-логика - тут должны быть чистые классы модели, принимающие на вход только простые типы или коллекции, без побочных эффектов
3) запись результата во внешние источники

2-я часть - это ядро, все остальное - imperative shell. Методы ядра вызываются из imperative shell, зависимости направлены в одну сторону.

Потенциальная проблема - возможно, читать придется много, чтобы загрузить данные для всех условий в бизнес-логике. Решение - дробить бизнес-логику на более мелкие части.
Еще проблема - как отследить, что в метод с бизнес-логикой не передали "побочный эффект". Например, класс, делающий вызов к БД - JPA lazy initialized DTO. Или ссылку на синглтон - Spring bean. Навскидку - только ручное код-ревью. Формально описать проверку объекта на отсутствие побочных эффектов сложно.
Огромный плюс - бизнес-логика всегда легко тестируется, даже без mock-ов.
Еще плюс - код проще.

Вот пример такого рефакторинга: https://www.youtube.com/watch?v=wq9LBouRULs

До чтения статьи, по заголовку, "покушение" на основы чистой архитектуры я воспринял критически. Но после ее прочтения и дальнейших размышлений идея понравилась.

Очевидно, она применима не всегда. Можно описать такую эвристику:

Простой сервис:
1) используем структурный дизайн, четко разделяем чтение с записью от бизнес-логики. С интерфейсами не заморачиваемся.
2) нужна вторая реализация какого-то сервиса - для тестового mock-а, динамической замены в runtime - легко вводим интерфейс с помощью IDE там, где он нужен

Сложный сервис, например:
1) библиотека
2) система с плагинами
3) коробочный продукт с несколькими реализациями под разных клиентов
4) наличие ядра, которое нужно защитить от правок "не доверенными лицами" -
изначально проектируем с интерфейсами в модели и реализациями в сервисах и портах\адаптерах

Принципу KISS - соответствует. Dependency Inversion - как ни странно тоже, т.к. в точной формулировке он звучит так: ядро не должно зависеть от деталей реализации. А структурном дизайне в ядро передаются только простые типы данных и коллекции с ними.

#arch #clean_code #principles