Product Domain 완료
오늘은 친구와 함께 공부를 하는 날이었다. PR까지 오늘 친구를 만나서 공부할 때 다 작성하려고했는데, 친구와 만나서 개발이야기 및 갑자기(?) 친구 일이 생기면서 한 3시간 공부하고선 집으로 오느라 PR작성까지는 마치지 못했었다. 집에 도착하고선 비가와서 습하고 더운 날씨에 잠깐(긴) 휴식 후에 남은 부분을 개발하고 늦게 PR작성을 마무리 했다.
Product Domain 계층의 개발은 Member 도메인과 크게 다른 부분이 없을 것이라고 생각하여, 쉽고 빠르게 끝날 줄 알았는데 그렇지 않았다. 공부를 할수록 고민하는 내용이 많아지면서 오래걸렸다. 근데 너무 재밌었다.
Product-Domain PR 특이사항
Product 도메인 계층을 개발하면서 다양한 고민들이 존재했었다. 그리고 수 많은 고민들의 결과물로입력 유효성 검사, 프로젝트 패키지 구조 변경 을 이야기 할 수 있을 것 같다.
입력 유효성 검사
나는 입력 유효성 검사를 추가했다. 이를 추가하게 전, 기존의 입력 유효성 검사는 ApplicationService 에서만 진행이 되었다. 거의 없다봐도 무방했다. 이와 관련하여, 어느곳에 입력 유효성검사를 추가해야할까? 하는 고민과 언제 입력 유효성 검사를 추가하는 것이 맞는가에 대한 고민을 많이 하게 되었다.
언제
입력 유효성 검사를 할 수 있는 순간으로 처음 데이터를 입력 받을 때, 메서드가 실행될 때 를 이야기 할 수 있을 것 같다.
어느곳에서
입력 유효성 검사는 최초 해당 입력 값이 받아들여지는 곳, 해당 데이터가 사용되는 곳에서 유효성 검사를 진행할 수 있을 것이다.
이에 대한 고민을 하면서, 내가 먼저 고민해야할 부분을 하지 않고 있음을 깨달을 수 있었는데, 입력 유효성 검사의 목적이다. 입력 유효성 검사를 왜하는지를 알고서 어디에 언제 사용해야하는가? 에 대한 고민을 해야하는데 나는 순서가 잘못됬었다.
목적
내가 생각하는 입력 유효성 검사의 목적은 요청(입력값)의 오류(잘못된 값으로 인한 문제)를 사전에 방지하는 것이다. 이를 통해 시스템의 안정성과 잘못된 데이터로 인한 데이터의 문제를 방지(데이터 무결성 유지) 할 수 있다.
그렇다면 이제 언제 어디서 입력 유효성 검사를 진행해야할까? 처음 데이터를 입력 받을 때, 메서드가 실행될 때, 최초 해당 입력 값이 받아들여지는 곳, 해당 데이터가 사용되는 곳 에서 모두 다 가능한 이야기라고 생각한다. 즉, 상황에 따라 다르다.
근데 상황에 따라 다르다 라는것은 논란의 가능성이 무궁무진하다고 생각한다. 사람들마다 차이가 발생할 수 있고, 이는 프로젝트를 진행하면서 계속해서 다르게 사용될 수 있으며, 컨벤션을 통해 약속을 해야할 것이다..(무진장 피곤할 것같다.)
나는 이전 회사의 프로젝트에서 지금과 같은 고민을 했던 경험이 있다. 당시 Test API 를 생성하며 프로젝트 코드를 분석하고 있었는데, 전혀 예상치 못한 동작을 하는 API가 존재했다. 해당 문제는 입력 유효성 검사가 제대로 이뤄지지 않아 잘못된 값이 넘어오는 것을 확인하지 못해 발생한 문제였다. 이로 인해 해당 메서드에 입력 유효성 검사를 추가하면서 지금과 같은 고민을 하게되었다.
그리고 나는 어느곳에서 입력 유효성 검사를 진행해야할까? 이와 사수님과 함께 이야기를 나눴었다. 사수님도 정답을 모른다고하셨다. 최대한 많이, 많은곳에서 사용해야한다. 라고 말씀하셨던 기억이 난다. 프론트에서 백으로 보낼 때, 백에서 받을 때, 백에서 사용할 때 등 할수있는 모든곳에서 해야한다고 하셨다.(근데 사수님 그렇게 안했다.) 그래서 나는 입력 유효성 검사를 모든 곳에서 다 사용했다.
다시 이번 Product 로 돌아와서 이야기를 해보면, 나는 과거와 같은 고민에 직면했다. 그리고 이에 대한 답을 찾기 위해 책임을 따져보기 시작했다. 각 계층의 책임은 무엇일까? 내가 나눈 계층의 목적은 뭐지? 에 대한 고민을 하고 선, 입력 유효성 검사의 책임은 각 계층에 포함할 수 없다. 판단했다. 그럼 어디서 이 입력 유효성 검사 책임을 담당해야할까? 나는 DTOs 에서 이 입력 유효성 검증의 책임을 해야한다 생각한다.
각 계층내 메서드에서 사용되는 매개변수 및 반환 객체의 타입은 다른 계층과 비교하여 같으면서 다르다. 그래서 계층간 사용되는 매개변수의 타입에 맞게 Mapper 모듈을 사용한다. 이런 상황에서 입력 유효성 검사를 이전에 말한 방법으로 한다면? 할 수 있다. 하지만 효율적이지 못하다. DTO 내에 입력 유효성 검사를 추가한다면 이것이 효율적일까? 라고 생각해볼 때, 나는 그렇다고 생각한다.
여기서 주의해야할 것은 입력 유효성 검사지, 각 계층에 존재하는 비즈니스에 사용에 알맞는지 확인하는 것이 아니다.
DTO 의 책임은 요청(입력)을 각 계층에 전달하는 것이다. 그리고 유효한 DTO를 통해 비즈니스 로직을 거쳐 비즈니스 규칙을 준수하는 데이터 만이 영속성 계층에 저장된다는 것을 잊지 말아야한다.(나는 이걸 자꾸만 헷갈려했다.)
그리하여 나는 DTO 객체 내에서 객체 생성 시, 입력 유효성 검사를 진행하도록 하였다.
나는 Bean Validatation API 를 사용했다. 책의 내용을 참고하여 개발을 이어 나갈 수 있었다. 나는 SelfValidating 클래스를 통해 다음과 같은 장점을 또 얻을 수 있었다. Mapper 를 통해 변환-생성 되는 클래스에 대하여 유효성검사를 손쉽게 할 수 있었다. 이 부분은 지난 Member 개발 간 (나의 실수로) 나를 괴롭히던 부분 중 하나이다. 당시 Mapper 및 Builder 를 사용하면서 발생한 문제를 어떻게 해결할 수 있을까? 하는 고민을 이번 SelfValidating 을 통해 해결할 수 있었다.
프로젝트 구조 개선
나는 프로젝트 구조를 Member 도메인을 개발하면서 다른 도메인들에서도 해당 구조를 따르도록 결정했었다. 하지만 클린아키텍처에 대한 공부를 계속하면서, 그리고 지난 PR 피드백을 받으면서 지금의 패키지 구조가 내가 목표하는 표현력 있는 아키텍처에는 아직 못미친다 판단하게되었다.
이를 토대로 앞으로으 Adapter 계층을 개발해볼 생각이다.
이번에는 같이 공부하시는 분들이 보기 쉽도록, PR의 단위를 줄여보려고 노력했는데 여전히 diff의 수치가 너무 크다.. 좀더 줄일 수 있도록 더 작은 단위의 PR을 작성하도록 노력해야겠다..
이번에는 같이 공부하시는 분들의 많은 생각을 같이 공유할 수 있기를...