Java Portal | Программирование
13K subscribers
1.19K photos
98 videos
37 files
1.12K links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
Паттерны архитектуры приложений Spring Boot: здесь

Серебряной пули не существует. Когда речь заходит об архитектуре современного приложения, часто можно услышать, что Anemic Domain Model — это плохо, или что Transaction Script — это антипаттерн. Также многие советуют Clean Architecture или Hexagonal Architecture в связке с DDD как «лучшую» или «правильную» архитектуру.

Но бесплатных обедов не бывает. Любое решение всегда приходит со своим набором компромиссов. Важно понимать эти trade-offы и выбирать архитектуру, которая лучше всего подходит под конкретные требования приложения.

Если вы делаете микросервис для одного конкретного сабдомена, возможно, простой слоистой архитектуры будет вполне достаточно. Если это монолит с низкой или средней сложностью — модульный монолит может быть хорошим выбором. Но если вы строите сложную систему с высокой сложностью, несколькими сабдоменами, процессами и воркфлоу, тогда имеет смысл задуматься о модульном монолите с DDD и гексагональной архитектурой.

Может возникнуть вопрос: почему стоит довольствоваться «достаточно хорошей» архитектурой, а не сразу делать «лучшую»?

Ответ простой: всё упирается в соотношение стоимости и пользы. Архитектура «достаточно хорошего уровня» в большинстве случаев полностью закрывает потребности приложения и при этом её проще реализовывать, поддерживать и развивать, чем идеальную, но переусложнённую архитектуру.

Лично я считаю, что исправлять недоинженеренную систему проще, чем переинженеренную. Добавлять всегда легче, чем убирать.

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

Поэтому лучше начинать с архитектуры «достаточно хорошего уровня» и эволюционировать её по мере развития системы.

Именно это и демонстрируется в данном репозитории: реализация примера приложения с использованием разных архитектурных подходов. Начиная с простой слоистой архитектуры и постепенно переходя к модульному монолиту с DDD и гексагональной архитектурой. В каждом модуле дизайн и архитектура улучшаются за счёт применения лучших практик и паттернов.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9
Совет по Java: предпочитай инъекцию через конструктор, а не инъекцию в поля.

Инъекция в поле:

@Component
public class UserController {

@Autowired
private Logger logger;

public void createUser(String username) {
...
}
}

// Сложнее тестировать изолированно.

Инъекция через конструктор:

...
private final Logger logger;

@Autowired
public UserController(Logger logger) {
this.logger = logger;
}

...
// Проще создавать экземпляр для unit-тестов


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Топ оконных функций, которые использует каждый data-инженер

1. ROW_NUMBER()
ROW_NUMBER() позволяет пронумеровать строки в рамках группы, что сильно упрощает дедупликацию. Нужно взять последнюю запись по клиенту или первое событие в сессии — решается чисто и без костылей.

2. DENSE_RANK()
Если делаешь лидерборды или бизнес-уровни, эта функция всплывает почти сразу. Она группирует одинаковые значения без пропусков в нумерации — рейтинги получаются понятными даже для нетехнических стейкхолдеров.

3. LAG() / LEAD()
Используются, чтобы посмотреть на предыдущее или следующее значение. Идеально подходит для сравнения сегодняшних продаж со вчерашними или поиска изменений между событиями.

4. SUM() OVER()
Так делаются накопительные суммы без развала запроса. SUM() OVER() позволяет сохранить детализацию по строкам и при этом добавить кумулятивные итоги. Очень удобно в финансовых и событийных пайплайнах.

5. FIRST_VALUE() / LAST_VALUE()
Нужны, когда важен контекст. Помогают взять первое или последнее значение внутри партиции — критично для временной аналитики, например при сравнении стартовых и финальных значений или расчёте метрик жизненного цикла.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍2😁2
Spring Boot: если в коде используется RestTemplate, тесты можно писать, подменяя внешние HTTP-вызовы с помощью MockRestServiceServer.

MockRestServiceServer работает за счет перехвата HTTP-запросов.

Дан сервис, который дергает внешний API:

@Service
public class ProductService {

private final RestTemplate restTemplate;

public ProductService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public String getProductName(long id) {
Product product = restTemplate.getForObject(
"https://remoteapi.com/products/{id}",
Product.class,
id
);
return product.getName();
}
}



Тест можно реализовать так:

@SpringBootTest
class ProductServiceTest {

@Autowired
private RestTemplate restTemplate;

@Autowired
private ProductService productService;

private MockRestServiceServer mockServer;

@BeforeEach
void setup() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}

@Test
void shouldReturnProductWhenExternalApiCalled() {
// Arrange
mockServer.expect(requestTo("https://remoteapi.com/products/1"))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess(
"{\"id\":1,\"name\":\"USB stick\"}",
MediaType.APPLICATION_JSON
));

// Act
ProductDto product = productService.getProduct(1L);

// Assert
assertThat(product.getName()).isEqualTo("USB stick");

mockServer.verify();
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍54🔥2😁2
Нашли офигенный способ выучить PostgreSQL в браузере : crunchydata

PostgreSQL-песочница с практическими уроками SQL, транзакциям, индексам, PostGIS и не только

🛌

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍122😁1
Java: не пихай бизнес-логику в Stream.peek(). Используй его только для отладки.

Смысл простой: 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();


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94
📱 Держите 6 хороших каналов по искусственному интеллекту и программированию для любого уровня!

Выбирай направление:

📱 Нейросети@neuro_prompt

🤖 AI-инструменты @ai_prompt

📱 Python@python_prompt

🤔 InfoSec & Хакинг @infosec_prompt

👩‍💻 IT Новости @it_news

😄 IT Мемы@it_memes

Промпты, обучение, шпаргалки и полезные ресурсы на каждую тему!
Please open Telegram to view this post
VIEW IN TELEGRAM
🌚2🔥1
Под капотом многопоточной синхронизации в Java: как потоки договариваются через Mark Word

Синхронизация в Java часто воспринимается как простая языковая конструкция — достаточно использовать ключевое слово synchronized, и код начинает «просто работать».

На практике же на уровне JVM происходит цепочка событий, которую можно проследить до Mark Word — восьмибайтового служебного поля заголовка каждого Java-объекта.

Современные JVM (HotSpot, OpenJ9, GraalVM) не используют фиксированную модель блокировок. Вместо этого они динамически выбирают стратегию синхронизации, исходя из реального поведения потоков и истории использования объекта.

Эта статья предназначена для Java‑разработчиков, которые уже знакомы с многопоточностью и synchronized, но хотят разобраться, как именно JVM управляет блокировками, какие состояния проходит объект и какую роль в этом играет Mark Word.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Java подсказка : не злоупотребляй наследованием. Когда можно — лучше делегируй. Наследование создаёт сильную связку, и это может выстрелить в ногу, если базовый класс изменится.

Предположим, у нас есть такой класс:

class Engine {
void start() {
}
}


и Car наследуется от Engine:

class Car extends Engine {
void drive() {
start();
}
}


Наследование выражает отношение is, но автомобиль на самом деле не является двигателем, он имеет двигатель. Перепишем через делегацию:

class Car {
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void drive() {
engine.start();
}
}


Таким образом эти два класса развязаны, и отношение превращается в has.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
А может ли Java гонять TensorFlow без JNI и без Python?

Автор взял Java 25 + FFM и протащил это всё до C-шного TensorFlow API, собрав рабочий REST-сервис на macOS.

Результат: предсказуемая память, нативная производительность и максимально скучная (в хорошем смысле) архитектура.

Ломали когда-нибудь Quarkus-эндпоинт просто тем, что решили залогировать request body?

В этом гайде показывают, как безопасно аудировать, чистить и трассировать HTTP-запросы через request filters в Quarkus, не блокируя обработку и не убивая API.

Практично и можно почти копипастить.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
3👀3
Java: не вешай логику в Stream.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();



👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3
СХЕМЫ АУТЕНТИФИКАЦИИ

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
8👍6🤔2🤣1
Spring Boot. Чтобы Jackson создавал объекты из JSON явно и предсказуемо, можно использовать аннотацию
@JsonCreator

Каждый параметр явно биндится.

Определяем конструктор с @JsonCreator:

class User {
public final String username;
public final int age;

@JsonCreator
public User(
@JsonProperty("username") String username,
@JsonProperty("age") int age
) {
this.username = username;
this.age = age;
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
11
Многопоточность позволяет писать так, чтобы несколько задач выполнялись параллельно внутри одного приложения.

Чтобы использовать многопоточность (то есть писать многопоточный код), нужен класс java.lang.Thread.

Стадии жизненного цикла потока:

• New: Новый поток начинает жизнь в состоянии new. Он остается там, пока программа не запустит поток.

• Runnable: После запуска новый поток становится runnable. В этом состоянии считается, что поток выполняет свою работу.

• Waiting: Иногда поток переходит в waiting, когда ему нужно дождаться выполнения задачи другим потоком.

• Timed Waiting: Поток из runnable может перейти в timed waiting на определенный промежуток времени. После истечения этого времени он снова возвращается в runnable.

• Terminated: Поток попадает в terminated после завершения задачи или принудительного завершения.

Приоритеты потоков:

Каждый Java-поток имеет приоритет, который помогает ОС решать порядок планирования потоков.

• MIN_PRIORITY (константа 1)
• NORM_PRIORITY (константа 5) (приоритет по умолчанию)
• MAX_PRIORITY (константа 10)

Базовые способы создать поток в Java:

• Реализовать интерфейс Runnable
• Наследоваться от Thread

Методы потоков:

• public void start()
Запускает поток в отдельном пути выполнения и затем вызывает run() у этого объекта Thread.

• public void run()
Если объект Thread был создан с отдельным Runnable, то run() будет вызван на этом Runnable.

• public final void setPriority(int priority)
Устанавливает приоритет потока. Возможные значения от 1 до 10.

• public void interrupt()
Прерывает поток, заставляя продолжить выполнение, даже если он был заблокирован.

• public final boolean isAlive()
Возвращает true, если поток "жив", то есть после старта и до завершения.

Это были базовые вещи. Пост длинный, но надеюсь, что что-то новое унес с собой.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92
Spring Boot. С помощью @DataJpaTest можно прогонять JPA репозитории изолированно.

@DataJpaTest поднимает только JPA слой без всего приложения, использует in-memory базу H2 и откатывает транзакции после каждого теста.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
4