아래는 헥사고날 아키텍처를 기반으로 한 두 가지 접근 방식을 설명하는 예시입니다. 각각의 접근 방식에서 DTO를 Command로 변환하여 UseCase를 호출하고, 포트에서 응답을 받아 변환하는 과정을 포함하고 있습니다.

예시 시나리오: 사용자 정보 시스템

사용자 정보를 처리하는 시스템에서 User라는 도메인 모델이 있고, 민감한 정보가 포함되어 있습니다. 클라이언트에게는 민감한 정보를 노출하지 않고, 기본 정보만 제공해야 합니다.

접근 방식 1: 서비스 레이어에서 필터링 및 변환

서비스 레이어에서의 처리

서비스 레이어는 포트로부터 도메인 객체를 받아 DTO로 변환하고, 컨트롤러에 반환합니다.

  1. Domain Model: 비즈니스 로직을 포함하는 객체
public class User {
    private String id;
    private String name;
    private String email;
    private String password; // 민감한 데이터
    private String socialSecurityNumber; // 민감한 데이터

    // 비즈니스 메서드들...
}

  1. DTO: 클라이언트에 노출될 데이터만 포함
public class UserDTO {
    private String id;
    private String name;
    private String email;

    public UserDTO(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // Getters...
}

  1. Command: 요청을 처리하기 위한 데이터 구조
public class GetUserCommand {
    private final String userId;

    public GetUserCommand(String userId) {
        this.userId = userId;
    }

    public String getUserId() {
        return userId;
    }
}

  1. Use Case Interface: 애플리케이션 서비스의 정의
public interface UserUseCase {
    UserDTO getUser(GetUserCommand command);
}

  1. Service Implementation: UseCase를 구현하는 서비스
public class UserService implements UserUseCase {
    private final UserRepositoryPort userRepositoryPort;

    public UserService(UserRepositoryPort userRepositoryPort) {
        this.userRepositoryPort = userRepositoryPort;
    }

    @Override
    public UserDTO getUser(GetUserCommand command) {
        // 포트를 통해 도메인 객체 조회
        User user = userRepositoryPort.findById(command.getUserId())
            .orElseThrow(() -> new UserNotFoundException("User not found"));

        // 도메인 객체를 DTO로 변환
        return new UserDTO(user.getId(), user.getName(), user.getEmail());
    }
}

  1. Port Interface: 저장소와의 인터페이스
public interface UserRepositoryPort {
    Optional<User> findById(String userId);
}