헥사고날 아키텍처와 마이크로서비스 아키텍처(MSA)를 결합하면 시스템의 복잡성을 효과적으로 관리할 수 있습니다. 이 글에서는 Feature 중심 설계와 Port와 Adapter를 활용한 Feature 간 상호작용 방법을 설명합니다.
...
헥사고날 아키텍처와 MSA의 결합
헥사고날 아키텍처는 애플리케이션을 Core Domain과 외부 시스템으로 명확히 구분합니다. 모든 외부와의 상호작용은 Port와 Adapter를 통해 이루어지며, Core Domain은 외부 의존성 없이 비즈니스 로직을 중심으로 설계됩니다.
...
Port 중심 상호작용:
Feature 간 데이터 요청은 Inbound Outbound Port를 통해 이루어집니다.
Outbound Adapter는 다른 Feature의 Inbound Port를 호출하여 데이터를 가져옵니다.
Feature 간 의존성 최소화:
한 Feature는 다른 Feature의 내부 구현을 알지 못하도록 설계해야 합니다.
상호작용은 Interface(Port)를 통해 상호작용을 추상화합니다.
기술 독립성 보장:
REST, gRPC, 메시징 등 다양한 통신 기술은 Adapter에서 처리하고, Core Domain은 이를 알 필요가 없습니다.
...
아래 예제는 Notification
Feature와 User
Feature 간의 상호작용을 Port와 Adapter를 통해 처리하는 방식을 보여줍니다.
...
Notification Feature의 Outbound Port
Notification
Feature는 User
Feature와의 상호작용을 위해 Outbound Port를 정의합니다. 이를 통해 Notification
Feature는 User
Feature의 내부 구현을 알 필요가 없습니다.
Code Block |
---|
public interface UserServicePortUserClientPort { UserResponse getUserByIdgetUser(String userId); } |
User Feature의 Adapter
User
Feature는 Notification
Feature의 Outbound Port를 구현하여 데이터를 제공합니다. 이 Adapter는 User
Feature 내에 위치하며, Notification
Feature에서 호출됩니다.
Code Block |
---|
@Service@Component public class UserServiceAdapterUserClientAdapter implements UserServicePortUserClientPort { private final UserRepositoryUserServicePort userRepositoryuserServicePort; // User Feature의 Inbound Port public UserServiceAdapterUserClientAdapter(UserRepositoryUserServicePort userRepositoryuserServicePort) { this.userRepositoryuserServicePort = userRepositoryuserServicePort; } @Override public UserResponse getUserByIdgetUser(String userId) { User user = userRepository.findById(userId) .orElseThrow(() -> new RuntimeException("User not found")); return userServicePort.getUserById(userId); return new UserResponse(user.getId(), user.getName(), user.getEmail()); } } |
...
User Feature의
...
Inbound Port
User
Feature는 내부 데이터를 외부에 제공하기 위해 Inbound Port를 정의합니다. 이 Port는 User
Feature의 Core Domain과 외부 시스템 간의 추상화된 인터페이스 역할을 합니다.
Code Block |
---|
public interface UserClientPortUserServicePort { UserResponse getUsergetUserById(String userId); } |
Notification Feature의
...
Code Block |
---|
@Component
public class UserClientAdapter implements UserClientPort {
private final RestTemplate restTemplate;
@Override
public UserResponse getUser(String userId) {
return restTemplate.getForObject("http://user-service/users/" + userId, UserResponse.class);
}
}
|
Notification Feature의 서비스서비스
Notification
Feature는 Outbound Port를 통해 User
Feature와 상호작용하며, 비즈니스 로직을 처리합니다.
Code Block |
---|
@Service public class NotificationService { private final UserClientPort userClientPort; public NotificationService(UserClientPort userClientPort) { this.userClientPort = userClientPort; } public NotificationResponse sendNotification(String userId, String message) { UserResponse user = userClientPort.getUser(userId); // 비즈니스 로직 수행 return new NotificationResponse("Sent to " + user.getEmail()); } } |
...