간단한 프로젝트경험하고 프로그래머스 라이브 스터디를 참가해서 배운 것들에 대한 개인적인 사견입니다.
컨트롤러DTO, 서비스 DTO
지금까지는 컨트롤러에서 받은 DTO를 엔티티로 바꿔서 서비스에 넣어주거나, 컨트롤러 DTO 그대로 서비스로 넣어서 사용했다.
하지만 다음과 같은 이유로 서비스 DTO를 사용하는 것이 좋다.
1) 서비스에서 엔티티를 사용하면 DB에 저장되기 전일 수도 있고 이는 불완전한 엔티티를 서비스에서 이용하는 것이다.
2) 그대로 서비스에 넣어서 사용하면 서비스에서 컨트롤러 DTO에 의존하게 된다.
3) 컨트롤러 DTO와 서비스 DTO의 포맷이 다를 수 있고 이로 인한 처리비용이 발생할 수 있다.
거의 모든 코드가 중복일 가능성이 높지만 그래도 컨트롤러와 서비스의 강한 결합을 떨어트리는게 나은 것 같다.
컨트롤러에 종속되는 컨트롤러 DTO <> 서비스 DTO Mapper를 추가해서 컨트롤러에서 엔티티로 향한 접근을 막고 유지보수를 쉽게하도록 써봐야 겠다.
Optianl 사용
스터디를 참가하면서 JDBCTeamplate를 거의 처음 사용해봤는데 Data JPA를 쓸때는 생각을 안하던 Repository에서의 반환에 대한 고민을 해볼 수 있었다. 만약 DB에서 찾는 내용이 없을때도 null을 Optional로 감싼 객체로 사용하면 SQLException, NPE 등에서 개발자가 원하는 예외로 컨트롤 할 수 있게 된다.
@Repository
public class JdbcPostRepository implements PostRepository {
..// 생략
@Override
public Optional<Post> findById(Long postId) {
List<Post> results = jdbcTemplate.query("~~");
return ofNullable(results.isEmpty() ? null : results.get(0)); // Optioanl 사용
}
}
@Service
public class PostService {
..// 생략
@Transactional(readOnly = true)
public Optional<Post> findById(Long postId) {
checkArgument(postId != null, "postId must be provided."); // 해당 부분은 ServiceDTO의 생성자 유효성 검증으로 수정예정
Post post = postRepository.findById(postId, userId).orElseThrow(() -> new NotFoundException(Post.class, postId)); // NPE 컨트롤
return Optional.of(post);
}
도메인 생성자 유효값 검증
이것도 JPA의 @Entity와 필드에 거는 조건 어노테이션으로 처리하던 때는 별생각이 없었다. JDBC 사용시 엔티티에도 별도의 어노테이션을 달지 않기 때문에 객체 생성 전에 생성자에서 유효값 검증을 하기위해 이메일 Class를 만드는 등으로 처리했다.
엔티티는 DB 테이블과 직결되기 때문에 유효값 검증이 필수이다.
public class User {
private final Long seq;
private final Name name;
private final Email email;
..//
}
public class Email {
private final String address;
public Email(String address) {
checkArgument(isNotEmpty(address), "address must be provided.");
checkArgument(
address.length() >= 4 && address.length() <= 50,
"address length must be between 4 and 50 characters."
);
checkArgument(checkAddress(address), "Invalid email address: " + address);
this.address = address;
}
..//
서비스 유효값 검증
컨트롤러, 서비스 DTO로 분리해서 사용하면 서비스 DTO 생성시에 유효값 검증을 하면 되겠지만 지금까지는 컨트롤러에서 엔티티로 바꿔서 서비스로 넣어서 사용했다. 따라서 서비스에서 엔티티나 컨트롤러 DTO 값을 꺼내서 유효값 검증했는데 이 부분도 도메인 검증과 같이 중요하다. 왜냐면 서비스를 하나의 컨트롤러에서만 사용하는게 아니기 때문이다. 컨트롤러에서만 유효값을 검증하고 서비스에서 검증을 하지 않으면 혹시 모를 검증안된 컨트롤러에서의 서비스 호출이나, 다른 서비스에서의 호출시에 예기치 못한 예외가 발생할 수 있다. 따라서 서비스의 유효값 검증도 매우 중요하다.
컨트롤러 유효값 검증
컨트롤러 파라미터에 @Valid와 컨트롤러DTO 필드의 조건 어노테이션으로 보통 진행한다. 어노테이션을 사용해 꽤나 구현이 쉽고, 도메인, 서비스에서의 검증보다는 우선순위가 떨어지지만 빼먹지 말아야겠다.
참고
https://kafcamus.tistory.com/12?category=912020
https://techblog.woowahan.com/2711/