spring-boot-starter-validation
의존성으로 쉽게 추가할 수 있다.실무에서 Controller
를 개발하면서 아래의 로직들이 섞이는 것을 많이 봐왔다.
구조상 Validation 에 대한 완전한 분리가 가능할지는 모르겠지만 어느정도는 분리하여 앱의 복잡성을 제거할 수 있겠다고 생각이 들었다. 검증에 대해 간단하게 표현 가능한 부분을 javax.validation
을 통해 간소화할 수 있었다.
특히 도메인 클래스에 대한 검증을 매우 쉽게 만들어준다. 필드 위에 검증 애노테이션을 하나 얹고, 컨트롤러에서 @Valid
애노테이션을 파라미터 앞에 붙여주면 컨트롤러 단으로 데이터가 넘어올 때 자동으로 검증된다.
경험상 validation 을 구성할 때, 컨트롤러의 파라미터 앞에
@Valid
애노테이션을 깜빡하는 경우가 생각보다 많았다. 꼭 테스트를 꼼꼼히 하자.
아래의 포스팅들을 통해 스프링과의 연동 방식을 알았고, @ControllerAdivce
를 통해 API 에 대한 예외처리를 잘 할 수 있었다.
자바에서 자주 쓰이는 보일러 플레이트 코드인 Getter
, Setter
, Constructor
, Builder
등을 쉽게 만들 수 있도록 도와주는 라이브러리이다.
Lombok 은 말도 많고 탈도 많다. 편의성 측면에서는 매우 좋다. 그러나, 설계 측면에서는 글쎄..? 내 코드에 어떤 부작용을 줄 수 있을지 항상 생각하며 사용하자.
개발자는 라이브러리나 프레임워크를 활용하여 쉽게 프로덕션을 만들어낼 수 있다. 그러나 해당 라이브러리나 프레임워크에 대한 이해가 없다면 이로 인해 많은 버그를 만들어내기도 쉽다.
access
엘리먼트를 잘 활용하자.lombok.config
파일을 이용하여 롬복의 자유도를 제한하자.JPA 는 ORM 기술 중 하나로, 관계형 DB 와 자바 객체간의 불일치를 해결해주는 데 도움을 준다. JPA 에서 사용하는 엔티티(@Entity
)는 관계형 DB 에서 테이블에 있는 한 row 와 매칭된다.
엔티티는 데이터를 매핑하여, 활용하기에는 좋으나 Input, Output 에는 별도의 객체를 구성해 활용하는 편이 좋다.
엔티티를 그대로 요청이나 응답에 활용하기 보다는 DTO (Data Transfer Object)
를 활용할 수 있고 이는 컨트롤러 단에서 요청 또는 응답에 사용되는 매개체로 훌륭한 역할을 할 수 있다.
간단히 축약해서 말하자면, 엔티티를 그대로 사용했을 때에 발생하는 문제를 해결할 수 있다.
첫째는 엔티티를 그대로 반환하거나 받아들일 때의 단점을 해결한다. 회원 정보 조회를 할 때 엔티티를 그대로 반환한다면, 비밀번호 등 모든 정보를 보여주게 될 것이다. 그러나 DTO 를 반환하면 DTO 에 외부로 보여주기 원하는 필드만 세팅하여 보여줄 수 있다.
둘째는 엔티티를 그대로 검증할 때의 단점을 해결한다. 회원 가입 시에는 아이디, 이름, 비밀번호 등 대부분의 정보가 필수인 반면에, 회원 정보 수정 시에는 필수 값이 아닐 수 있다. 이를테면 회원 수정 폼 제출 시 이름에 대한 정보만 받았다면, 이름만 바꿔주는 식이다. 이렇게 특정 작업에 특화된 검증 객체로서 활용될 수 있다.
이 부분은 개발자마다 생각이 다른듯 하다.
윤석님: 최소한의 레이어에만 공개해야 하는 것이 바람직하다.
종립님: DTO 클래스를 사용하는 것보다는 차라리 인터페이스를 사용하고, DTO 가 해당 인터페이스를 구현하게 하자.
아샬님: DTO 를 Infrastructure Layer 까지 연결하면 오히려 CQRS 에서까지 유용하게 쓸 수 있다.
핵심은 프로그램을 복잡하게 만드는 요인을 파악해서 제거하자는 것이다.
결국 정답은 없는 것 같다.
대표적으로 ModelMapper
, Dozer
등이 있었다.
이 라이브러리들은 모두 @Getter
, @Setter
가 public
으로 공개되어 있어야 제 역할을 한다. 없다면, 로그 메세지라도 줬으면 좋겠는데 어떠한 말도 없이 동작을 하지 않아서 약간의 혼란을 주었다.
@Configuration
과 @Bean
에 대해 이해해보자@Retention
을 잘 모르면, 애노테이션 자체를 이해할 수 없다.@GeneratedValue
의 전략들을 알아보자.import *
의 사용을 지양하자.
*
이 되는지를 설정할 수 있다. 저걸 늘려서 import *
이 나오는 것을 최대한 방지하자.... 메서드에서
라는 표현을 썼는데, 메서드는 행동하는 대상으로 보고 ... 메서드는
, ... 메서드가
등의 표현으로 고쳐야겠다.""
과 같이 공백인 경우와 null
같이 null 인 경우로 구분될 수 있어서 어떤 게 '없는' 인지 알기 어려우니 더 명확한 표현을 사용하자.@Data
가 어떤 역할을 하는지 설명해보자.@ToString
, @EqualsAndHashCode
, @Getter
를 모든 필드에 설정한다.@Setter
필드를 final
이 아닌 필드에 설정한다.@RequiredArgsConstructor
를 설정한다.생성자
로 처리하자.@BeforeEach
를 사용하자.@BeforeAll
은 static
메서드로 작성해야 해서 별로이다.@Valid
잊지 않기Bean Validation 을 적용하고도 컨트롤러 파라미터 부분에 @Valid
애노테이션이 없으면 Bean Validation 은 작동하지 않는다.
테스트 커버리지가 필요 없는 부분들을 제거할 수 있다.
jacocoTestCoverageVerification {
violationRules {
rule {
element = "CLASS"
limit {
counter = 'LINE'
minimum = 1
}
limit {
counter = 'BRANCH'
minimum = 1
}
excludes = [
"com.codesoom.assignment.App",
"com.codesoom.assignment.dto.*",
"com.codesoom.assignment.domain.*"
]
}
}
}
좋은 설계를 위해 Setter
, Constructor
등을 제한하면 자꾸 JavaBeans 가 내 앞길을 막는다.
Dozer
의 경우에는 Setter
가 없으면 제대로 매핑이 되지 않았다. 앞으로 공식문서에서 이러한 부분들을 잘 찾아봐야겠다. JavaBeans Mapper
라는 이름부터 Setter
가 필요하다는 의미였을 수도 있겠다.
모르는 키워드가 나올 때마다 공식문서에서 찾아서 하나씩 정리하다보면, 언젠가는 인간 스펙이 될 것 같다. 이제 공식문서 정리하는 게 좀 더 익숙해지고 있는데, 이렇게 공식문서 내용을 이해하는 게 익숙해지면 어떤 언어, 어떤 라이브러리, 어떤 프레임웍을 사용하게 되더라도 해낼 수 있다는 자신감이 생길 것 같다.
공식문서의 정리 방법은 처음부터 목차대로 하나하나씩 정리하기보다는 모르는 게 나올 때마다 하나하나 확실히 알아가는 게 좋을 것 같다. 그리고, 보통 공식문서를 검색하면 스펙이 나오는데, 구현체를 구현한 웹사이트에 세부적인 내용이 많다. 이를테면 이번에는 Java ee persistence 에 있는 @GeneratedValue
, GenerationType
등에 대해 알아보았는데, 하이버네이트 공식문서에 세부적인 구현을 아주 자세히 설명해놓았었다.
그것도 모르고 java ee 공식문서만 뒤졌더니 굉장히 추상적이고 이해하기 힘든 내용만 있었다.