Java: fill the gaps
12.9K subscribers
7 photos
215 links
Привет! Меня зовут Диана, и я занимаюсь разработкой с 2013. Здесь пишу просто и понятно про джава бэк

🔥Тот самый курс по многопочке🔥
https://fillthegaps.ru/mt

Комплименты, вопросы, предложения: @utki_letyat
Download Telegram
Статический анализ кода, часть 2. Инструменты

В части 1 обсудили основные метрики: связность, связанность, сложность и размер. Также статический анализ включает проверку форматирования, поиск уязвимостей и возможных ошибок.

Когда и чем можно выполнять статистический анализ?
1️⃣ Во время написания кода.
С помощью встроенных правил IDE и дополнительных плагинов:
▫️Checkstyle проверяет форматирование, возможные ошибки, показывает сложные классы. Самый популярный плагин для Intellij IDEA.
▫️SonarLint и FindBugs ищут возможные ошибки, уязвимости, проверяют код на несколько тысяч ошибочных паттернов.
▫️CodeMR замеряет атрибуты качества кода — связность, сложность и т.д. Считает метрики, рисует картинки, показывает проблемные места с точки зрения дизайна.
▫️PMD ищет ошибочные паттерны в разных категориях — дизайн, кодстайл, производительность. Не знаю, почему этот плагин попадает во все списки анализаторов, у него достаточно скудный список правил по сравнению с аналогами.

2️⃣ Во время сборки.
Анализ редко делают в процессе сборки, но такая опция доступна — с помощью maven или gradle плагинов: Checkstyle Plugin, PMD Plugin.

3️⃣ На этапах CI/CD.
Можно запускать периодически или после определённых событий: создание пул-реквеста, слияние ветки. Результаты могут иметь рекомендательный характер, а могут не пропускать дальше по CI.

Конкретных инструментов много, как платных, так и бесплатных. Самый популярный - SonarQube. Метрики качества не считает, но проверяет на гигантское количество ошибочных паттернов и интегрируется с плагином в IDE.
JArchitect менее распространён и стоит дороже. Но и функций больше — метрики качества и красивые графики.

Статический анализ проводят в большинстве проектов. Обычно это проверка форматирования и поиск частых ошибок. Конкретные метрики считаются редко. И зря, ведь по ним можно объективно оценить:
🔸Текущее состояние кода
🔸Развитие системы от релиза к релизу
🔸Необходимость рефакторинга
🔸Проблемные места системы
1
Тестирование, часть 1. Вопросы на собеседовании

Чем опытней разработчик, тем больше тем обсуждается на собеседованиях. Начиная с уровня middle будьте готовы к таким вопросам:

1️⃣ Назовите свойства юнит-тестов?
Хорошие юнит-тесты соблюдают принцип FIRST:

🔸F – Fast
Выполняются быстро. Никто не хочет лишний раз запускать медленные тесты. Один юнит-тест — не дольше 0.5 сек.

🔸I – Isolated / Independent
Любой набор тестов можно запускать в любом порядке, тесты не зависят друг на друга. Каждый тест сфокусирован на одном действии и наборе параметров. Если тест упал, то сразу понятно, где и при каких условиях возникла ошибка.

🔸R – Repeatable
Результат теста не зависит от операционной системы, конфигурации компьютера, внешних ресурсов и наличия интернета. Результат теста повторяется при многократном вызове.
⭐️ Это свойство хромает, когда тесты используют случайные числа или проверяют работу нескольких потоков.

🔸S – Self-Validating
У теста два результата — прошёл или нет. Разработчик не должен проверять записи в логе или сравнивать текстовые файлы.

🔸T - Timely
Тесты пишутся вовремя, в рамках той же задачи, что и основной код.

⭐️ Юнит-тесты должны быть читаемыми. Тогда их легко поменять, если бизнес-логика изменится. Сложно разбираться в методах test1(), test2(), test3() и переменных a, b, c.
⭐️ По тестам можно оценить инженерную культуру компании. Обратите внимание на количество и качество юнит-тестов, кто и когда их пишет. Если тестов нет, или сеньор пишет код и создаёт подзадачу «написать тесты» для джуниора - это дно. Откладывать тесты из-за дедлайна — тоже так себе.
⭐️ Тесты можно не писать для PoC (proof of concept) — временный код для проверки гипотез, который не связан с продакшн кодом.

Тесты организуют по структуре 3A (Arrange-Act-Assert), также встречается название Given-When-Then.
// given
Инициализация переменных и моков.
// when
Вызов проверяемого метода.
// then
Проверка результата и состояния других объектов.

3 блока должны чётко следовать друг за другом, тогда тест легко читать. Если после блока проверок идёт действие и дополнительные проверки — значит тест слишком большой.

2️⃣ Что такое TDD?
Test Driven Development - процесс разработки, когда сначала пишется тест, а потом код. Подробно это выглядит так:
▫️Написать тест для кода, которого нет
▫️Запустить тесты, новый тест падает
▫️Написать код, чтобы тест проходил
▫️Запустить тесты, тесты проходят
▫️Рефакторинг нового кода
▫️Запустить тесты, тесты проходят

Плюсы TDD:
Код сразу покрыт тестами
У класса удобный интерфейс, который сразу используется в тестах
Структурированный код

После этого следует такой диалог:
- А Вы лично используете TDD?
- Нет.
- Почему? У него же столько плюсов.
- Большой минус - частое переключение контекста и фокус на деталях. Мне удобнее написать простое рабочее решение, и только потом добавить проверки, валидацию и обработку ошибок. После этого в соответствии с требованиями как следует оттестировать то, что получилось. Я сразу пишу код, который легко использовать и тестировать, поэтому TDD меня только замедляет.
- Согласен.
3👍2
Тестирование, часть 2. Тестовое покрытие

Code coverage (CC) - метрика, которая показывает, насколько код покрыт тестами.

Как считается СС?
Запускаются тесты и отслеживается, какие классы, методы и строки кода выполнились. Это число делится на общее количество и так получается процент кода, покрытый тестами.

Почему у СС плохая репутация?
Не говорит о качестве тестирования и надёжности системы. Если метод выполнился, это не значит, что он протестирован.
Тестировать get/set методы, конструкторы и классы-конфиги нет необходимости, но из-за жёстких требований по СС приходится писать бесполезные тесты.

Зачем считать СС?
Менеджеры хотят быть в курсе состояния проекта и не хотят смотреть в код. Поэтому их главный инструмент - это метрики, в том числе СС. Так оценивается текущая ситуация и сравниваются релизы.
Качество и надёжность— понятия субъективные. С помощью СС и последующего анализа можно найти компоненты, которые слабо покрыты тестами. Таким образом увеличить надёжность системы.

Какие значения СС нормальные?
Для большинства проектов это 60-80%.

Как посчитать?
1️⃣ Intellij IDEA:
Run → Run with Coverage
По умолчанию IDEA использует свой способ подсчёта, но для java есть ещё 2 библиотеки:
🔸JaCoCo
🔸Emma (не поддерживается с 2013)

Результаты разных библиотек могут отличаться. Если на этапе CI/CD используется JaCoCo, то лучше в IDE тоже использовать JaCoCo. Чтобы поменять:
Run → Edit Configurations... → Code Coverage → Choose coverage runner

2️⃣ Во время сборки.
Те же библиотеки используются в Maven и Gradle плагинах — JaCoCo Plugin, Emma Plugin.

3️⃣ На этапах CI/CD.
JaCoCo Plugin и Emma Plugin доступны для Jenkins, Teamcity, GitLab, Travis и остальных CI серверов.
3👍1
Статистика: что использовали Java разработчики в 2019 году

Бостонская компания Snyk каждый год опрашивает разработчиков об их проектах и технологиях. В прошлом году в опросе поучаствовало две тысячи человек, в том числе 8% участников из России.

Главное из отчёта за 2019:
1️⃣ Какая версия java используется в продакшене?
64% — 8
25% — 11
3% — 7 и ниже

2️⃣ Почему Вы не переходите на последнюю версию java?
51% — И так всё устраивает
32% — Трудности с миграцией
30% — Сложно согласовать переход

3️⃣ Какой JVM язык используется в качестве основного?
87% — Java
5,5% — Kotlin
2,9% — Closure
2,6% — Scala
1,5% — Groovy

4️⃣ Вы используете разбиение на модули (фича Java 9)?
64% — Нет
29% — Планируем
7% — Да

5️⃣ Какая у Вас версия Spring в продакшене?
48% — 5.1
18% — 5.0
17% — 4.3
5% — 4.2
4% — 3.2

6️⃣ Какой серверный веб-фреймворк Вы используете?
50% — Spring Boot
31% — Spring MVC
11% — JSF
5% — Vert.x
5% — Vaadin
5% — Struts

7️⃣ Ваша основная IDE:
62% — Intellij IDEA
20% — Eclipse
10% — NetBeans

8️⃣ Ваш инструмент сборки:
64% — Maven
25% — Gradle
6% — Ant

9️⃣ Ваш CI-сервер:
58% — Jenkins
12% — Никакой
6% — GitLab
5% — TeamCity
4% — Bamboo
4% — Travis
4%— Circle

🔟 Ваш репозиторий:
24% — private GitLab
16% — public GitHub
15% — Enterprise GitHub
15% — BitBucket Server
11% — public GitLab
10% — BitBucket Cloud

Полная версия отчёта тут. Очень удивило, что 12% не используют CI, и что Closure обогнал Scala. Рост популярности Intellij IDEA по сравнению с прошлым годом тоже впечатляет:
1
Сколько часов в день Вы пишете код?
Anonymous Poll
20%
Меньше часа
31%
1-3 часа
27%
3-5 часов
16%
5-8 часов
6%
Больше 8 часов
WakaTime: лёгкий способ прокачать навык эстимации

Секрет успеха прост — составить план и придерживаться его. Задача разработчика при планировании - оценить время на задачу с учётом сложности и рисков. Точные прогнозы это плюс к репутации, сорванные сроки — минус.

Навык оценки легко тренировать - почаще сравнивать оценку и фактическое время выполнения. Со временем у вас разовьётся сильная интуиция и адекватная оценка своих способностей. Приятный бонус - любовь менеджеров и низкий уровень стресса😌

Самое сложное — посчитать, сколько времени по факту ушло на задачу. Можно полагаться на память, а можно трекать время автоматически. Самый популярный плагин Intellij IDEA для Git — WakaTime. В бесплатной версии недоступно почти всё, но можно смотреть:
🔸Сколько времени ушло на написание кода
🔸Сколько времени заняла каждая задача:
5h 6 mins feature/EX-45
50 mins bugfix/EX-64

Для мониторинга своей активности этого достаточно.

Полная инструкция:
1️⃣ Установить в IDEA плагин WakaTime
2️⃣ Перезапустить IDEA, появится окошко для ключа
3️⃣ Зарегистрироваться на сайте и перейти в раздел для IDEA
4️⃣ Взять из п.5 API Key, ввести его в IDE
5️⃣ Зайти в настройки, отключить все уведомления
6️⃣ Зайти в дашборд

Можно трекать работу в других IDE и редакторах — Eclipse, Android Studio, GoLand, даже в Notepad++. Можно подключить к GitLab, GitHub и BitBucket и смотреть, сколько времени занял каждый коммит.
1
Привет!

Сегодня будет не полезный пост, а небольшая просьба. Я пишу посты в этом канале уже 5 месяцев: делюсь знаниями, инструментами и аналитикой, стараюсь доступно передать свой 7-летний опыт java разработки.

Постоянная обратная связь мотивирует писать дальше: меня очень радуют ваши лайки, шеры и личные сообщения. Приятно, что вы цените точную и практическую информацию и мой труд🧡

Я уже несколько месяцев занимаюсь созданием курса по многопоточности в java. В нём будет:
▫️Необходимая теоретическая часть
▫️Как и какими инструментами решать конкретные задачи
▫️Что актуально сейчас и тренды ближайших лет
▫️Разбор вопросов с собеседований

Большая часть материалов готова, но я хочу убедиться, что раскрыла все важные и интересные темы. Поэтому прошу вас мне помочь и заполнить небольшую анкету:
https://docs.google.com/forms/d/10zfRjnM6Fbpr03LWbNRETQDl3SNd7kjGmVh7Rh2XFRY/edit?usp=sharing
1
Ребята, спасибо, что уделили время заполнению анкеты! Я получила больше сотни ответов и ценных идей, буду внедрять💪
Многие писали, что присоединились недавно, поэтому на этой неделе будут подборки самых популярных статей. Если что-то пропустили — рекомендую прочесть.
Что напечатается в консоли?
Anonymous Poll
19%
true
78%
false
3%
Compilation error
Как JVM работает со строками, часть 1

По статистике OpenJDK в приложениях 15-50% памяти занимают экземпляры String. Это много, поэтому разработчики JVM прикладывают много усилий, чтобы оптимизировать работу со строками.

Как сэкономить память, если в системе миллионы экземпляров?

1️⃣ Уменьшить количество памяти под одну строку.

Мы уже разбирали этот случай: в java 9 вышло обновление Compact String и размер памяти под строки сократился до 2 раз.

2️⃣ Добавить кэширование.

Есть два способа создать экземпляр String:
🔸Через оператор new:
String s = new String ("one");
В памяти создаётся новый объект.

🔸Без оператора new:
String s = "one";

В этом случае идёт работа с кэшем строк под названием String pool. Схема работы такая:
▫️Проверить в String Pool, есть ли там такая строка.
▫️Если есть — вернуть её.
▫️Если нет — создать объект, поместить в кэш, вернуть.

Как реализован String pool?
Структура похожа на HashMap: хэш-таблица фиксированного размера с парами хэш — строка. В последних версиях java она занимает 64 МБ, при желании размер меняется с помощью флажка:
-XX:StringTableSize=65536

В следующем посте рассмотрим ещё два способа снижения издержек на строки.

Ответ на 1 вопрос перед постом:
new String("Java") создаёт новый объект в хипе,
s2 = "Java" создаёт объект в String pool. Это два разных объекта, поэтому при сравнении через == результат будет false.

Можно исправить ситуацию и добавить строчку в кэш методом intern():
String s1="Java";
String s2=new String("Java");
s2=s2.intern();
println(s1==s2); //true

Рассмотрим второй вопрос. О том, сколько строк создаётся в конструкции
String str=new String("Java");

Подвох в том, что для конструктора String нужен экземпляр String, поэтому создаётся 2 строки — "Java" и new String;

Но если строка "Java" использовалась раньше и попала в кэш, то будет создана только одна строка — new String.
1
А вот и второй вопрос, он должен был быть перед постом🤫

Сколько экземпляров String создаётся в этой строке кода:
String str = new String("Java");
Anonymous Poll
37%
1
61%
2
2%
3
Как JVM работает со строками, часть 2

Ссылка на часть 1.
Сегодня рассмотрим ещё 2 простых, но эффективных приёма JVM по оптимизации строк.

Оба связаны со внутренним устройством String:
byte[] value — текст
byte coder — тип кодировки
int hash

1️⃣ String Deduplication (Java 8)
При использовании оператора new в памяти создаётся новый объект:
String str = new String("12");

Отдельный JVM поток ищет в памяти экземпляры String и записывает их текст в хэш-таблицу:
hash → byte[]

Если поток находит дубликат, то заменяет ссылку в повторяющейся строке на ссылку из хэш-таблицы:
str.value = hashtable.value

На текст дубликата больше нет ссылок, поэтому он удалится сборщиком мусора. Так можно сэкономить 5-30% памяти. Опция String Deduplication работает только со сборщиком G1, и по умолчанию отключена.

Почему заменяется только текст, а не вся строка?
Ссылки на строчку могут быть в десятках мест. Текст — внутреннее поле, его заменить гораздо проще

Почему совместим только с G1?
Нашла только один комментарий по теме: G1 – единственный сборщик мусора, в котором есть pinned regions. Это области, в которых не происходит дефрагментация. Но почему нельзя разместить хэш-таблицу в другом месте — непонятно😕

Почему опция по умолчанию не работает?
Deduplication хорошо экономит память, когда в программе через оператор new создаётся много похожих строк-долгожителей. Тогда экономится больше памяти, чем затраты на копирование в хэш-таблицу. По статистике OpenJDK таких случаев мало, поэтому StringDeduplication по умолчанию отключен.

Для активации добавьте при запуске VM флажок:
-XX:+UseStringDeduplication

Чтобы посмотреть, сколько памяти сэкономил Deduplication, можно вывести статистику Xlog:
-Xlog:stringdedup*=debug

2️⃣ Оптимизация хэш-кода (Java 13)
Хэшкод строки играет важную роль в хэш-таблицах String pool, Deduplication и других процессах JVM.

Внутри класса String хэш хранится как примитив:
int hash

Вычисляется и сохраняется при первом вызове hashcode():
if (hash == 0) {
hash = ...
}

⛔️Минус такого решения:
Если хэш равен 0, то он пересчитывается каждый раз. Шанс этого очень низкий, но в Java 13 в String добавился флаг для нулевого хэша:
boolean hashIsZero

Проверка того, что хэш-код ещё не посчитан, стала такой:
if (h == 0 && !hashIsZero)

Теперь хэш-код всегда считается один раз.

Итого: оптимизацией строк идёт по всем фронтам:
1️⃣ Структура данных (Java 9: Compact Strings)
2️⃣ Кэширование (String pool)
3️⃣ Оптимизация частных случаев (Java 8: String Deduplication)
4️⃣ Микрооптимизации (Java 13: флажок hashIsZero)
👍3
Intellij IDEA: Memory view

Как в IDEA посмотреть количество объектов в памяти?

По умолчанию подсчёт объектов при дебаге выключен, потому что это тяжелая операция и сильно тормозит процесс отладки.

Чтобы включить:
1️⃣ В окне Debug найдите вкладку Memory View.
2️⃣ Нажмите на шестерёнку в Memory View и выберите
Update Loaded Classes On Debugger Stop

Картинка с инструкцией внизу⬇️

Что показывает:
🔸Count - количество экземпляров
🔸Diff - изменения с прошлого шага

При каждой остановке информация о количестве объектов обновляется.

Так можно наглядно посмотреть на работу String pool. Помните, был вопрос:

Сколько строк создаётся в конструкции:
String s = new String("Java");

Откроем Memory View. После выполнения строки напротив класса java.lang.String увидим Diff +2.

Поменяем код на
String java = "Java";
String s = new String("Java");

Запустим снова. "Java" в первой строке отправилась в String pool. Теперь после выполнения второй строки напротив java.lang.String будет Diff +1.
1
Паттерны GoF: инструкция по изучению

В 1994 вышла книжка Design Patterns: Elements of Reusable Object-Oriented Software. Авторов часто называют Gang of Four — Банда четырёх, а описанные в книге приёмы - паттернами GoF.

Зачем?
Паттерны активно используются на практике, а ещё помогут:
🔸Общаться с коллегами на одном языке и быстро обсуждать идеи.
🔸Проходить собеседования на джуниор и мидл позиции.

Что читать?

Книга "Design Patterns: Elements of Reusable Object-Oriented Software"
Та самая книга. 1994 год, 440 страниц, примеры на С++. В 2020 году вышло обновлённое издание, но стиль изложения не изменился, читать тяжело.

Википедия
Текст и диаграммы скопированы из книги Design patterns.

😐 Книга "Head First: Паттерны проектирования"
Простые описания, много картинок и примеров, но очень растянуто — 650 страниц.

Каталог паттернов
Читать приятно, много схем и картинок. Всё по полочкам: какая проблема решается, преимущества и недостатки паттерна, сравнение паттернов между собой. Есть примеры на java.
Ресурс не идеален, но это лучшее по теме паттернов в интернете.

Какие сложности могут быть?

1️⃣ Формализм
Паттерны сами по себе простые. Некоторые из них вы использовали, не осознавая этого. Но определения паттернов максимально формальные. Все ресурсы описывают цель паттерна Мост так:

«Отделить абстракцию от реализации так, чтобы то и другое можно было изменять независимо»

Поэтому ориентируйтесь на примеры и картинки.

2️⃣ Непонятна разница между паттернами
Исходные задачи могут быть разными, а реализация в коде одна и та же. Это нормально, и часто встречается в структурных паттернах.

3️⃣ Мало реальных примеров
Для объяснения часто берут вымышленные примеры, хотя к каждому паттерну можно подобрать пример из JDK или Spring.

4️⃣ Не все одинаково полезны
Одни используются чаще, чем другие. Некоторые паттерны никогда не придётся писать самостоятельно:
▪️Итератор есть в каждой коллекции.
▪️Команда передаётся в лямбда выражениях.
▪️Синглтон легко создать через аннотацию Component в Spring.

Каждый паттерн - готовое решение конкретной проблемы. На практике всё может быть интереснее как по задачам, так и по реализации. Например, паттерн Builder может помочь при разработке многопоточных программ, а паттерн Proxy можно реализовать через AOP.
👍3