도메인이란 우리가 해결하고자 하는 핵심 비즈니스 로직이 반영되는 곳이다.
특히 도메인 객체에서 자기 자신의 책임을 충분히 다 하지 않으면, 그 로직들은 자연스럽게 Service 영역 및 외부 영역으로 책임이 넘겨지게 된다.
본인의 책임을 다하는 도메인 객체를 어떻게 만들지에 대해 정리해보겠다.
알맞은 Lombok 사용법
JPA 어노테이션
- @Table(name = "member") : 테이블의 네임은 반드시 명시한다. 명시하지 않으면 기본적으로 클래스 네임을 참조하기 때문에 클래스 네임 변경 시 영향을 받게 된다.
- @Column : 컬럼 네임도 반드시 지정한다.
- nullable, unique, updatable 등의 기능을 적극 활용한다. 이메일일 경우 nullable, unique 같은 속성을 추가한다.
- @CreationTimestamp, @UpdateTimestamp 어노테이션을 이용하여 생성, 수정 시간을 설정할 수 있다.
Embedded 적극 활용하기
Embedded 어노테이션을 이용하여 도메인 객체의 책임을 나눌 수 있다. Name, Address 객체들이 대표적인 Embedded 대상이 되는 객체들이다.
Embedded로 작성되지 않았을 경우,
class Member {
@NotEmpty @Column(name = "first_name", length = 50)
private String firstName;
@Column(name = "middle_name", length = 50)
private String middleName;
@NotEmpty @Column(name = "last_name", length = 50)
private String lastName;
@NotEmpty @Column(name = "county")
private String county;
@NotEmpty
@Column(name = "state")
private String state;
@NotEmpty
@Column(name = "city")
private String city;
@NotEmpty
@Column(name = "zip_code")
private String zipCode;
}
전체 이름, 전체 주소를 가져오기 위해서 Member 객체에서 기능을 구현해야 한다.
또한 Name, Address는 많은 도메인 객체에서 사용되는 객체이므로 중복 코드가 증가된다.
Embedded 활용한 코드
public class Name {
@NotEmpty @Column(name = "first_name", length = 50)
private String first;
@Column(name = "middle_name", length = 50)
private String middle;
@NotEmpty @Column(name = "last_name", length = 50)
private String last;
}
public class Address {
@NotEmpty @Column(name = "county")
private String county;
@NotEmpty @Column(name = "state")
private String state;
@NotEmpty @Column(name = "city")
private String city;
@NotEmpty @Column(name = "zip_code")
private String zipCode;
}
public class Member {
@Embedded private Name name;
@Embedded private Address address;
}
Embedded의 장점
- 데이터 응집력 증가
- 중복 코드 방지
- 책임 분산
- 테스트 코드의 용이함
도메인 자체에서 해결할 수 있는 것들은 그 안에 메소드를 만들자
도메인 객체에 기본적인 getter, setter 외에 메소드를 작성하지 않는 경우가 있다. 하지만 이럴 경우에는 객체 본인의 책임을 다하지 않으니 다른 객체에게 넘겨지게 된다.
public class Coupon {
@Embedded
private CouponCode code;
@Column(name = "used", nullable = false)
private boolean used;
@Column(name = "discount", nullable = false)
private double discount;
@Column(name = "expiration_date", nullable = false, updatable = false)
private LocalDate expirationDate;
public boolean isExpiration() {
return LocalDate.now().isAfter(expirationDate);
}
public void use() {
verifyExpiration();
verifyUsed();
this.used = true;
}
private void verifyUsed() {
if (used) throw new CouponAlreadyUseException();
}
private void verifyExpiration() {
if (LocalDate.now().isAfter(getExpirationDate())) throw new CouponExpireException();
}
}
쿠폰의 만료 여부, 쿠폰 사용 가능 여부, 쿠폰 사용 등의 메소드는 어떤 객체(클래스)에서 제공해야 할까?
당연히 쿠폰 Entity 객체 자신이다.
쿠폰 객체 스스로가 자율성을 가지고 해당 요청에 응답할지의 여부도 판단해야 협력적인 관계를 갖게 된다.
'Spring' 카테고리의 다른 글
[Spring] Spring MVC 동작 원리 (0) | 2023.10.25 |
---|---|
[Spring] 스프링 JPA 정리 (0) | 2023.10.25 |
[Spring] lombok 어노테이션 정리와 주의사항 (0) | 2023.10.24 |
[Spring] @RequestParam, @PathVariable, @RequestBody, @ResponseBody 차이 (0) | 2023.10.11 |
[Spring]@RequestMapping과 @GetMapping, @PostMapping, @DeleteMapping, @PutMapping (1) | 2023.10.11 |