💡 Java совет: избегай глубоких if-else - используй guard clauses
Одна из самых частых проблем в Java-коде глубоко вложенные условия.
Код формально работает, но читать и поддерживать его тяжело.
❌ Плохо: вложенные if-else
- сложно читать
- логика размазана
- любая правка превращается в боль
✅ Хорошо: guard clauses (ранние выходы)
- проверки сразу отсекают невалидные состояния
- основной сценарий читается сверху вниз
- код короче и понятнее
Почему guard clauses — это профессиональный подход:
- уменьшают когнитивную нагрузку
- делают бизнес-логику очевидной
- упрощают рефакторинг и тестирование
- отлично сочетаются с fail-fast философией
Правило простое:
если условие — это ошибка или исключение из нормального потока,
проверь его сразу и выйди из метода.
Так код становится:
- линейным
- предсказуемым
- удобным для поддержки
Мелочь на уровне синтаксиса, но огромная разница на уровне качества кода.
Теги: java, clean code, best practices, backend, javadev
Одна из самых частых проблем в Java-коде глубоко вложенные условия.
Код формально работает, но читать и поддерживать его тяжело.
❌ Плохо: вложенные if-else
- сложно читать
- логика размазана
- любая правка превращается в боль
✅ Хорошо: guard clauses (ранние выходы)
- проверки сразу отсекают невалидные состояния
- основной сценарий читается сверху вниз
- код короче и понятнее
Почему guard clauses — это профессиональный подход:
- уменьшают когнитивную нагрузку
- делают бизнес-логику очевидной
- упрощают рефакторинг и тестирование
- отлично сочетаются с fail-fast философией
Правило простое:
если условие — это ошибка или исключение из нормального потока,
проверь его сразу и выйди из метода.
Так код становится:
- линейным
- предсказуемым
- удобным для поддержки
Мелочь на уровне синтаксиса, но огромная разница на уровне качества кода.
Теги: java, clean code, best practices, backend, javadev
👍25❤6🥰1
⚡️ Улучшаем графику Minecraft с Iris!
Iris — это открытый шейдерный мод для Minecraft, который поддерживает популярные шейдерные пакеты OptiFine. Он обеспечивает отличную производительность и совместимость с другими модами, такими как Sodium, позволяя игрокам наслаждаться красивой графикой без потери FPS. Iris создан для тех, кто хочет настраивать свою игру и использовать любимые шейдеры на современных версиях Minecraft.
🚀Основные моменты:
- Поддержка шейдеров OptiFine.
- Высокая производительность в сочетании с Sodium.
- Совместимость с модами и настройками.
- Открытый исходный код для разработчиков.
- Активное сообщество и поддержка в Discord.
📌 GitHub: https://github.com/faringcuddles443/iris
@javatg
Iris — это открытый шейдерный мод для Minecraft, который поддерживает популярные шейдерные пакеты OptiFine. Он обеспечивает отличную производительность и совместимость с другими модами, такими как Sodium, позволяя игрокам наслаждаться красивой графикой без потери FPS. Iris создан для тех, кто хочет настраивать свою игру и использовать любимые шейдеры на современных версиях Minecraft.
🚀Основные моменты:
- Поддержка шейдеров OptiFine.
- Высокая производительность в сочетании с Sodium.
- Совместимость с модами и настройками.
- Открытый исходный код для разработчиков.
- Активное сообщество и поддержка в Discord.
📌 GitHub: https://github.com/faringcuddles443/iris
@javatg
❤8👍3🔥1😁1
💡 Java-совет: никогда не возвращайте null вместо коллекций.
Если метод возвращает null, вызывающему коду приходится делать бессмысленные проверки - и это источник багов.
Лучше всегда возвращать пустую коллекцию:
Тогда вызов становится безопасным, а код чище.
Пример:
❌ Плохо (придётся проверять на null):
✔️ Хорошо (без лишних проверок):
Теперь вызов можно писать так:
List<String> users = findUsers();
users.forEach(System.out::println); // без null-check
@javatg
Если метод возвращает null, вызывающему коду приходится делать бессмысленные проверки - и это источник багов.
Лучше всегда возвращать пустую коллекцию:
- Collections.emptyList()
- List.of()
- Set.of()Тогда вызов становится безопасным, а код чище.
Пример:
❌ Плохо (придётся проверять на null):
public List<String> findUsers() {
if (!dataAvailable()) {
return null;
}
return loadUsers();
}
✔️ Хорошо (без лишних проверок):
public List<String> findUsers() {
if (!dataAvailable()) {
return Collections.emptyList();
}
return loadUsers();
}
Теперь вызов можно писать так:
List<String> users = findUsers();
users.forEach(System.out::println); // без null-check
@javatg
👍17❤2🤔2🔥1
Spring Boot Tip: тестируем REST проще с `RestTestClient` 🚀
В Spring Boot можно легко писать интеграционные тесты для REST-эндпоинтов,
используя `RestTestClient` вместе с аннотацией:
Это автоматически настраивает клиент и позволяет:
- отправлять запросы прямо из тестов
- проверять статус и тело ответа
- работать с объектами, а не “сырым” JSON
Пример
👉 Для TestRestTemplate есть похожая аннотация:
Тесты становятся чище, короче и ближе к реальному поведению API ✨
@javatg
В Spring Boot можно легко писать интеграционные тесты для REST-эндпоинтов,
используя `RestTestClient` вместе с аннотацией:
@AutoConfigureRestTestClient
Это автоматически настраивает клиент и позволяет:
- отправлять запросы прямо из тестов
- проверять статус и тело ответа
- работать с объектами, а не “сырым” JSON
Пример
Копировать код
@SpringBootTest
@AutoConfigureRestTestClient
public class PersonControllerTests {
private static final String API_PATH = "/persons";
@Test
void add(@Autowired RestTestClient restTestClient) {
restTestClient.post().uri(API_PATH)
.body(Instancio.create(Person.class))
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(Person.class)
.value(person -> assertNotNull(person.getId()));
}
}
👉 Для TestRestTemplate есть похожая аннотация:
@AutoConfigureTestRestTemplate
Тесты становятся чище, короче и ближе к реальному поведению API ✨
@javatg
🔥7❤3👍3
21 января(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3
🚀 SPRING BOOT совет: ускорь запуск в dev
Spring Boot по умолчанию инициализирует все бины сразу при старте.
В разработке это часто лишнее:
- приложение стартует дольше (особенно в больших проектах)
- ты ждёшь загрузку компонентов, которые сейчас не нужны
✅ Решение: включи ленивую инициализацию только для dev-режима.
Spring Boot по умолчанию инициализирует все бины сразу при старте.
В разработке это часто лишнее:
- приложение стартует дольше (особенно в больших проектах)
- ты ждёшь загрузку компонентов, которые сейчас не нужны
✅ Решение: включи ленивую инициализацию только для dev-режима.
# application.properties (dev)
spring.main.lazy-initialization=true
# Важно:
# В проде лучше оставить eager-init:
# 1) ошибки старта ловятся сразу
# 2) все компоненты готовы обрабатывать запросы моментально
👍9❤3🥰1
💡 Java совет: начиная с Java 14 вы можете использовать **switch expressions** - код становится короче и чище при логике с несколькими ветками.
Раньше приходилось писать громоздко с
❌ Старый способ
Теперь можно сразу вернуть значение из switch:
✅ Новый switch expression
Что это даёт:
• меньше кода
• нет риска забыть break
• читается как выражение, а не как “мини-процедура”
@javatg
#Java #SoftwareEngineering
Раньше приходилось писать громоздко с
break и присваиваниями:❌ Старый способ
String season;
switch (month) {
case 12:
case 1:
case 2:
season = "Winter";
break;
case 3:
case 4:
case 5:
season = "Spring";
break;
default:
season = "Invalid";
}
Теперь можно сразу вернуть значение из switch:
✅ Новый switch expression
String season = switch (month) {
case 12, 1, 2 -> "Winter";
case 3, 4, 5 -> "Spring";
default -> "Invalid";
};
Что это даёт:
• меньше кода
• нет риска забыть break
• читается как выражение, а не как “мини-процедура”
@javatg
#Java #SoftwareEngineering
❤11👍5🔥4
Представь фэнтези-мир, где заклинания - это SQL-запросы, а древние артефакты спрятаны в таблицах и JSON-документах.
🧙Ты - боевой дата-аналитик, который с помощью SQL, Python, ETL и визуализаций охотится за харизматичным злодеем Архивариусом Пакостусом, что ломает индексы, крадёт данные и готовит “шторм данных” на столицу.🔮
В каждом эпизоде тебя ждут: выборы с последствиями, хитрые задачи от простых SELECT до рекурсивных CTE и BigQuery, юмор, эпик и неожиданные повороты.
Хочешь проверить, сможешь ли ты спасти королевство не мечом, а запросами? Тогда добро пожаловать в SQL-квест.
🪄 Начать квест: https://uproger.com/sql-kvest-fentezijnoe-priklyuchenie-dlya-analitikov-dannyh/
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥2🤬2🥰1
💡 SOLID: принцип подстановки Лисков (LSP) говорит:
🔁 объекты базового класса должны без проблем заменяться объектами его подклассов.
Если подкласс меняет поведение так, что код начинает ломаться — дизайн неправильный.
❌ Плохой пример
У нас есть Vehicle с методом startEngine().
Мы наследуем Bicycle, но… у велосипеда нет двигателя — и метод бросает исключение.
Такая иерархия:
Теперь любой тест, ожидающий, что любой Vehicle умеет завести двигатель, падает.
👉 Подкласс ведёт себя не так, как базовый — LSP нарушен.
✅ Как исправить
Разделяем ответственность на интерфейсы:
Теперь только те объекты, которым по смыслу нужен двигатель, реализуют Motorized.
🧠 Вывод
✔ Подклассы не должны ломать ожидания, заложенные в базовый класс.
✔ Лучше разделить поведение, чем «затыкать» методы исключениями.
✔ LSP делает код предсказуемым и безопасным для расширения.
#Java #JavaDev #SOLID #CleanCode
🔁 объекты базового класса должны без проблем заменяться объектами его подклассов.
Если подкласс меняет поведение так, что код начинает ломаться — дизайн неправильный.
❌ Плохой пример
У нас есть Vehicle с методом startEngine().
Мы наследуем Bicycle, но… у велосипеда нет двигателя — и метод бросает исключение.
Такая иерархия:
class Vehicle {
public void startEngine() { ... }
}
class Bicycle extends Vehicle {
@Override
public void startEngine() {
throw new UnsupportedOperationException("Bicycles don't have engines!");
}
}
Теперь любой тест, ожидающий, что любой Vehicle умеет завести двигатель, падает.
👉 Подкласс ведёт себя не так, как базовый — LSP нарушен.
✅ Как исправить
Разделяем ответственность на интерфейсы:
interface Vehicle {}
interface Motorized {
void startEngine();
}
class Car implements Vehicle, Motorized {
public void startEngine() { ... }
}
class Bicycle implements Vehicle {
// без двигателя — всё ок
}
Теперь только те объекты, которым по смыслу нужен двигатель, реализуют Motorized.
🧠 Вывод
✔ Подклассы не должны ломать ожидания, заложенные в базовый класс.
✔ Лучше разделить поведение, чем «затыкать» методы исключениями.
✔ LSP делает код предсказуемым и безопасным для расширения.
#Java #JavaDev #SOLID #CleanCode
❤11👍9🔥2
💡 Java-совет: не оптимизируй слишком рано
Частая ошибка разработчиков — пытаться «ускорять» код ещё до того, как он вообще готов.
Сначала важно:
• написать чистый и понятный код
• убедиться, что он работает
• закрыть функциональные требования
А уже потом — смотреть профилировщик и оптимизировать то, что реально узкое место.
Простой пример:
Сначала пишем просто:
Код читается и делает своё дело.
А позже, если понадобится скорость, можно переписать:
Сначала читаемость кода, потом производительность.
Иначе легко «ускорить то, что вообще не нужно в работе».
Частая ошибка разработчиков — пытаться «ускорять» код ещё до того, как он вообще готов.
Сначала важно:
• написать чистый и понятный код
• убедиться, что он работает
• закрыть функциональные требования
А уже потом — смотреть профилировщик и оптимизировать то, что реально узкое место.
Простой пример:
Сначала пишем просто:
String hello = "Hello " + "there" + "!";
System.out.println(hello);
Код читается и делает своё дело.
А позже, если понадобится скорость, можно переписать:
StringBuilder sb = new StringBuilder();
sb.append("Hello ");
sb.append("there");
sb.append("!");
System.out.println(sb.toString());
Сначала читаемость кода, потом производительность.
Иначе легко «ускорить то, что вообще не нужно в работе».
🔥10👍7🤔2❤1😁1😢1
💡 Java-совет: выбирай constructor injection вместо field injection
Во многих проектах до сих пор можно встретить такое:
Работает, но хуже тестируется и прячет зависимости «за кулисами».
Гораздо лучше - передавать зависимости через конструктор:
Почему это лучше:
• зависимости явно видны
• класс становится иммутабельным
• проще писать unit-тесты (можно подставить fake/mock)
• меньше сюрпризов при инициализации Spring-контейнера
Итог: если нет веской причины - предпочитай constructor injection 👍
Во многих проектах до сих пор можно встретить такое:
@Component
public class UserController {
@Autowired
private Logger logger;
public void createUser(String username) {
...
}
}
Работает, но хуже тестируется и прячет зависимости «за кулисами».
Гораздо лучше - передавать зависимости через конструктор:
@Component
public class UserController {
private final Logger logger;
@Autowired
public UserController(Logger logger) {
this.logger = logger;
}
}
Почему это лучше:
• зависимости явно видны
• класс становится иммутабельным
• проще писать unit-тесты (можно подставить fake/mock)
• меньше сюрпризов при инициализации Spring-контейнера
Итог: если нет веской причины - предпочитай constructor injection 👍
👍9❤2🔥1
Есть простой принцип, который часто ломают.
peek() — не для логики. Его задача — подсмотреть, что проходит по конвейеру, и помочь отладке.
Пример — посмотреть, как меняются данные по шагам:
list.stream()
.filter(x -> x > 10)
.peek(x -> System.out.println("Filter: " + x))
.map(x -> x * 2)
.peek(x -> System.out.println("Map: " + x))
.toList();
Вот, как это работает:
- filter() — отбрасывает лишнее
- peek() — просто печатает, ничего не меняя
- map() — преобразует значения
Почему важно не класть туда «настоящую» логику:
- peek() могут удалить или отключить
- порядок выполнения потоков может меняться
- код становится хрупким и непредсказуемым
Коротко:
- нужен вывод - используй peek().
- нужна логика - используй map(), filter() и другие операторы.
@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤4🔥1
🚫 Spring Boot: избегай FetchType.EAGER, если это не жизненно необходимо
Когда ты помечаешь связь как EAGER, ORM будет загружать её КАЖДЫЙ раз при загрузке сущности, даже если тебе эти данные вообще не нужны.
Что это значит на практике:
❌ Ты загружаешь Order - автоматически тянется и Customer
❌ Даже если ты не обращаешься к customer в коде
❌ Растёт объём данных, время запроса и нагрузка на БД
А дальше классика жанра — N+1 проблема:
1 запрос - получить список всех Orders
+ N запросов - получить Customer для каждого Order
И всё, производительность улетела.
EAGER кажется удобным, но это скрытая ловушка.
Гораздо безопаснее по умолчанию использовать LAZY и явно управлять загрузкой через JOIN FETCH, EntityGraph или DTO-проекции.
Контроль > магия.
#SpringBoot #Java #Backend
@javatg
Когда ты помечаешь связь как EAGER, ORM будет загружать её КАЖДЫЙ раз при загрузке сущности, даже если тебе эти данные вообще не нужны.
Что это значит на практике:
❌ Ты загружаешь Order - автоматически тянется и Customer
❌ Даже если ты не обращаешься к customer в коде
❌ Растёт объём данных, время запроса и нагрузка на БД
А дальше классика жанра — N+1 проблема:
1 запрос - получить список всех Orders
+ N запросов - получить Customer для каждого Order
И всё, производительность улетела.
EAGER кажется удобным, но это скрытая ловушка.
Гораздо безопаснее по умолчанию использовать LAZY и явно управлять загрузкой через JOIN FETCH, EntityGraph или DTO-проекции.
Контроль > магия.
#SpringBoot #Java #Backend
@javatg
👍12😁2