Skip to content

Conversation

@impatient0
Copy link
Owner

@impatient0 impatient0 commented Aug 8, 2025

Этот Pull Request добавляет базовую функциональность интернет-магазина в виде трёх новых микросервисов в модуле commerce: shopping-store, shopping-cart и warehouse.

Ключевые архитектурные решения и реализованная функциональность:

  1. Разделение по принципу "Database per Service":

    • Для полного соответствия требованиям CI-окружения, архитектура персистентности была переработана. Каждый сервис теперь работает с собственной, выделенной базой данных (вместо общей БД с разными схемами).
    • Генерация схемы полностью делегирована Hibernate (ddl-auto: update), что потребовало отказа от нативных ENUM-типов PostgreSQL в пользу их хранения в виде String.
  2. Централизованная конфигурация и Service Discovery:

    • Все новые сервисы интегрированы с существующей инфраструктурой: они получают конфигурацию из Spring Cloud Config и регистрируются в Eureka, что обеспечивает динамическое взаимодействие.
  3. Синхронное взаимодействие через Feign:

    • Коммуникация между сервисами (в частности, shopping-cart -> warehouse для проверки остатков) реализована с помощью декларативных Feign-клиентов.
    • Общие контракты (DTO и Feign-интерфейсы) вынесены в отдельный модуль interaction-api для обеспечения консистентности.
  4. Отказоустойчивость с помощью Circuit Breaker:

    • Реализован паттерн Circuit Breaker (с помощью Resilience4j) для Feign-клиента WarehouseClient в сервисе shopping-cart.
  5. Архитектура сервисов:

    • Каждый сервис построен по многослойной архитектуре с использованием DDD-принципа "Порты и Адаптеры" для репозиториев, что отделяет доменную логику от деталей персистентности (JPA).
    • Структура ApiErrorDto была полностью переработана для предоставления клиентам полезной, структурированной информации (timestamp, path, errorCode) без утечки внутренних деталей, таких как stack trace.
  6. Адаптация под CI-окружение:

    • Ряд эндпоинтов (например, quantityState в shopping-store) и конфигураций был адаптирован для полного соответствия с требованиями, обнаруженными в ходе интеграционного тестирования в CI.

Standardized all Java module names to follow the pattern
`{root}.{subsystem}.{module}`.
…ntions

To improve maintainability and align the module with Domain-Driven
Design principles, the package structure has been reorganized into
distinct layers.

This separates core domain logic from application and infrastructure
concerns, establishing a cleaner architecture. The new packages
include `domain`, `application`, `infrastructure`, and `presentation`.
…reporting

The ApiErrorDto has been completely redesigned to provide useful,
consistent, and safe error information to API clients. The previous
implementation was a thin wrapper around Throwable, which leaked
internal details.

The new structure includes key contextual fields like timestamp and
request path while explicitly preventing sensitive information, such
as stack traces, from being exposed.
To align with the requirements of the CI environment, the persistence
strategy has been completely refactored.

The key changes are:
- Switched from a single-database, multi-schema model to a dedicated
  database-per-service model.
- Removed per-service database users in favor of a single user.
- Eliminated the manual SQL initialization script and now rely entirely
  on Hibernate's `ddl-auto` for schema generation.
- As a consequence of using `ddl-auto`, all native PostgreSQL enums
  have been changed to be stored as Strings.
Copy link

@kesch9 kesch9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Несколько комментариев

@@ -0,0 +1,53 @@
server:
port: 8087
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

порты должны быть указаны 0
так сервис будет работать на свободному порту
server:
port: 0
В остальных сервисах также
Когда работают несколько инстансов, вы не сможете их запустить если будет жестко указан порт


management:
server:
port: 8087
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

При указании port 0, указывать здесь не нужно, будет работать на том порту, на котором работает сервис


logging:
level:
ru.yandex.practicum: DEBUG
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEBUG используется при отладке, на сдачу надо поднимать до INFO


@AutoConfiguration
@ComponentScan("ru.yandex.practicum.smarthometech.commerce.api.mapper")
public class InteractionApiModuleAutoConfiguration {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не совсем понятно зачем этот класс нужен в api

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, в данной версии API модуля уже нет мапперов, так что этот класс и правда лишний.

@JoinColumn(name = "shopping_cart_id", nullable = false)
private ShoppingCart shoppingCart;

@NotNull
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Валидационные аннотации для Entity избыточны, т.к. работаем c Dto и они поступают от клиентов. Для Entity достаточно указывать ограничения в Column


@Override
public int hashCode() {
return Objects.hash(shoppingCart, productId);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использовать shoppingCart в качестве расчета hashcode и equals не оптимально, т.к. это ManyToOne
В целом не обязательно переопределять equals и hashCode

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Согласен, использовать весь shoppingCart здесь не рационально. Т.к. я использую Set<CartItem>, мне нужен хороший hashCode(). Учитывая это, я переработал equals() и hashCode() — теперь они основываются только на ID у shoppingCart. ID у прокси-объектов Hibernate всегда инициализированы, поэтому это не вызовет проблем из-за lazy loading'а.

@Override
public ShoppingCart save(ShoppingCart cart) {
return jpaRepository.saveAndFlush(cart);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Применение адаптеров по моему мнению избыточно
Минусы:
Избыточность: Если интерфейс ShoppingCartRepository и JpaShoppingCartRepositoryInterface имеют много схожих методов, это может привести к избыточности кода.
Потенциальные накладные расходы: Если адаптер не добавляет значительной логики, его использование может быть излишним.
В вашей реализации можно было использовать просто repository

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне хотелось реализовать более чистую DDD архитектуру, где domain полностью независим от используемых технологий (JPA) и деталей реализации (saveAndFlush()). Изначально я пытался использовать только два интерфейса — "чистый" в domain и JPA в infrastructure, — но это вызывало проблемы, например, при попытке перегрузить save(), который уже является частью CrudRepository.
Я понимаю, что это компромисс, который даёт более чистые абстракции, но усложняет код. Если нужно, я упрощу это до одного JPA интерфейса в domain.

Copy link

@kesch9 kesch9 Aug 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Оставьте, для обучение самое подходящее место, оставил комментарий просто указать, что adapter будет избыточен для такой простой логики.

Copy link

@kesch9 kesch9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve

@impatient0 impatient0 merged commit fb207f0 into main Aug 12, 2025
2 checks passed
@impatient0 impatient0 deleted the 7-spring-cloud-microservices branch August 12, 2025 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants