Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- 도커
- Spring
- 데이터베이스
- web server
- HTTP
- 웹 서버
- JPA
- CS
- 스프링 배치
- 가상화
- 스프링
- 영속성 컨텍스트
- Java
- virtualization
- ORM
- Spring Security
- vm
- 백엔드
- computer science
- spring cloud
- 컨테이너
- 배포
- mysql
- 자바
- 스프링 부트
- spring boot
- CI/CD
- spring batch
- 스프링 시큐리티
- Container
Archives
- Today
- Total
개발 일기
[Spring Boot] 데이터 전송 객체 그리고 DTO를 class가 아닌 record로 선언한 이유 본문
Back-End/Spring
[Spring Boot] 데이터 전송 객체 그리고 DTO를 class가 아닌 record로 선언한 이유
개발 일기장 주인 2024. 8. 18. 18:54평소에 나는 DTO 객체를 생성할때 class가 아닌 record를 통해 선언한다.
처음 그렇게 쓰게된 계기는 그냥 구글링 대충하다가 reocrd가 더 낫다는 텍스트만 몇개 보고 그냥 record로 써야지 하고 줄곧 써왔었는데 왜 record가 class보다 더 적합한지 이해가 필요하다고 생각해서 찾아보게 됐다. 우선 DTO가 무엇인지에 대해 먼저 정리해보자
DTO(Data Transfer Object)
"계층 간에 데이터를 전달하기 위해 사용되는 객체"
처음에는 "왜 굳이 번거롭게 DTO라는 객체를 따로 생성해서 데이터를 주고받지?"라는 생각을 했었다. 아래와 같은 이유들로 DTO가 필요하다고 한다.
도메인 보호
- 도메인 로직의 보호: 도메인 객체는 비즈니스 로직과 상태를 포함한다. 도메인 객체를 외부 계층에서 직접 접근할 수 있으면, 외부에서 이 객체의 상태를 변경하거나 비즈니스 로직을 호출할 수 있게 되고 이는 도메인 모델의 일관성과 무결성을 해칠 수 있다.
DTO와 역할을 분리한다면 불변성을 위해 필드를 final로 선언하거나 Setter를 제공하지 않음으로써 도메인 객체의 상태 변경 등 일관성과 무결성을 해치는 동작을 막을 수 있다.
ex) 도메인 객체의 상태를 변경하는 메소드(예: updateStatus())를 외부 계층에서 호출하면, 시스템의 상태를 의도하지 않게 변경할 수 있다. - 캡슐화: DTO를 사용하면 도메인 객체의 중요 메소드와 상태를 외부 계층에서 접근할 수 없게 만들 수 있다. DTO는 데이터만 포함하며, 도메인 객체의 비즈니스 로직이나 상태 변경 메소드가 포함되지 않는다. 즉, 캡슐화를 통해 역할을 확실히 분리한다.
ex) DTO는 단순히 데이터를 전달하는 역할만 하므로, 도메인 객체의 calculateDiscount()와 같은 복잡한 로직을 외부에서 호출할 수 없습니다.
불필요한 데이터 노출 방지
- 도메인 객체에는 시스템 내부에서만 사용되어야 하는 민감한 정보나 복잡한 비즈니스 로직이 포함될 수 있다. 이런 정보를 외부 계층에 노출하면 보안적으로 문제가 될 수 있다.
- DTO는 오직 필요한 데이터만을 포함하여 전달함으로써, 외부에 불필요한 정보를 노출하지 않도록 해야한다.
의도 명확화 및 데이터 검증
- DTO는 특정한 데이터 전송의 의도를 명확히 해주는 역할도 한다. 각 DTO는 특정한 작업이나 요청에 대한 데이터 구조를 정의하며, 이를 통해 각 계층 간의 데이터 흐름을 명확하게 파악할 수 있게 돕는다.
- 또한, 컨트롤러에서 DTO를 생성할 때, Bean Validation을 통해 입력 데이터를 검증할 수 있다. 이를 통해 데이터의 무결성을 보장하며, 잘못된 데이터가 시스템에 유입되는 것을 방지할 수 있다.
👉 Controller 계층에서 변환
: 클라이언트로부터 받은 DTO를 Controller 계층에서 도메인 객체로 변환하고, Service에서 도메인 객체를 처리한 후 다시 Controller에서 DTO로 변환하는 방법.
👉 Service 계층에서 변환
: DTO를 Service 계층으로 전달하고, Service 계층에서 도메인 객체로 변환 및 처리한 후, 다시 DTO로 변환하여 Controller로 반환하는 방법.
그렇다면 class와 record 중에 선택할때 무엇을 선택할지는 위에 DTO를 따로 사용하는 이유에 더 부합하는 것을 선택하면될 것이다.
그렇다면 왜 여러 사람들이 Record가 DTO에 더 작합하다고 하는 것일까?
record와 DTO
Record는 Java 14에서 처음 도입되었고, Java 16에서 안정화되었다.
- 불변성: Record는 불변 객체를 쉽게 만들 수 있도록 지원한다. 필드는 자동으로 final로 선언되며, 생성자와 접근자 메소드가 자동으로 생성됩니다.
- 간결한 코드: 데이터만을 저장하는 단순한 객체를 생성할 때, 많은 보일러플레이트 코드를 줄일 수 있습니다. Record를 사용하면, toString(), equals(), hashCode() 등의 메소드를 자동으로 생성할 수 있습니다.
예시
public record MemberDto(
Long id,
String name,
String email,
Integer age,
LocalDateTime createdDate,
LocalDateTime updatedDate
) {
// 1. `of` 메서드: DTO 객체를 생성하는 팩토리 메서드
public static MemberDto of(Long id, String name, String email, Integer age, LocalDateTime createdDate, LocalDateTime updatedDate) {
return new MemberDto(id, name, email, age, createdDate, updatedDate);
}
// 2. `from` 메서드: 엔티티 객체를 DTO로 변환하는 메서드
public static MemberDto from(Member member) {
return new MemberDto(
member.getId(),
member.getName(),
member.getEmail(),
member.getAge(),
member.getCreatedDate(),
member.getUpdatedDate()
);
}
// 3. `toEntity` 메서드: DTO 객체를 엔티티 객체로 변환하는 메서드
public Member toEntity() {
return Member.builder()
.id(id)
.name(name)
.email(email)
.age(age)
.createdDate(createdDate)
.updatedDate(updatedDate)
.build();
}
}
'Back-End > Spring' 카테고리의 다른 글
[Spring Boot] 예외처리 및 @RestControllerAdvice & @ExceptionHandler (0) | 2024.09.15 |
---|---|
[Spring Boot] 서비스 운영 관점에서 FK(외래키) 설정이 꼭 필요할까? (3) | 2024.08.28 |
[Spring Boot] JPA의 @Query, @Modifying 그리고 @Transactional (0) | 2024.08.16 |
[Spring Boot] 우아콘2020 - 수십억건에서 QUERYDSL 사용하기 감상문 (2) | 2024.06.04 |
[Spring Boot] Entity에서의 올바른 롬복(Lombok) 사용에 있어서 나의 생각 정리 (1) | 2024.06.03 |