💻문제점
현재 MemberController 클래스만 보아도 회원 가입, 프로필 수정, 섭취량 조회 등 다양한 기능을 MemberController에서 수행한다. 너무 많은 기능이 MemberController에 존재한다.
@RestController
@RequiredArgsConstructor
@RequestMapping("api/v1/members")
public class MemberController {
private final MemberService memberService;
private final MemberQueryService memberQueryService;
private final NutrientsQueryService nutrientsQueryService;
private final PostSearchService postSearchService;
private final MemberMapper memberMapper;
private final NutrientsMapper nutrientsMapper;
private final PostMapper postMapper;
@PostMapping()
public ResponseEntity<MemberInfoResponse> modifyMemberInfo(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestBody @Valid MemberInfoRequest memberInfoRequest) {
//
}
@DeleteMapping()
public ResponseEntity<Void> removeMember(@AuthenticationPrincipal UserDetailsImpl userDetails) {
//
}
@GetMapping("/profile")
public ResponseEntity<MemberProfileResponse> getMemberDetails(
@AuthenticationPrincipal UserDetailsImpl userDetails) {
//
}
@PutMapping("/profile")
public ResponseEntity<MemberProfileResponse> modifyMemberProfile(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@RequestBody @Valid MemberProfileRequest memberProfileRequest) {
//
}
}
🔍해결
컨트롤러 나누기
클린 아키텍처에서 다음과 같은 내용을 보았다.
모든 요청에 응답할 수 있는 하나의 컨트롤러를 만들어야 할까? 그럴 필요 없다.
웹 어댑터는 하나 이상의 클래스로 구성해도 된다.
단, 클래스들이 같은 소속이라는 것을 표현하기 위해 같은 패키지 수준에 놓아야 한다.
그럼 컨트롤러는 몇 개 만들어야 할까? 너무 적은 것 보다는, 많은게 낫다.
각 컨트롤러가 가능한 좁고 다른 컨트롤러와 가능한 적게 공유하는 웹 어댑터를 구현해야 한다.
현재 내 코드는 회원과 관련된 모든 것이 하나의 클래스에 모여 있어 괜찮아 보이지만 단점이 분명하다.
클래스마다 코드는 적을수록 좋다.
모든 기능이 한 클래스에 모여 있으니 컨트롤러에 몇 줄만 추가되어도 이해하기 어렵다.
테스트 코드도 마찬가지다. 컨트롤러에 코드가 많아 그에 해당하는 테스트 코드도 많아질 것이다.
테스트 코드는 보통 추상적이라서 프로덕션 코드에 비해 파악하기 어려울 때가 많다.
따라서 특정 프로덕션 코드에 해당하는 테스트 코드를 찾기 쉽게 만들어야 하는데, 클래스가 작을 수록 찾기가 쉽다.
동시 작업이 어렵다.
다른 사람이 MemberController를 사용하는 회원과 관련된 기능을 개발하고 있다면, 다른 사람은 회원과 관련된 기능을 개발하기 어렵다. (병합 충돌 문제가 발생할 수 있다)
하지만 세부적으로 MemberController가 나누어져 있다면 서로 다른 연산에 대한 동시 작업이 유리할 것이다.
불필요한 의존성
private final MemberService memberService;
private final MemberQueryService memberQueryService;
private final NutrientsQueryService nutrientsQueryService;
private final PostSearchService postSearchService;
private final MemberMapper memberMapper;
private final NutrientsMapper nutrientsMapper;
private final PostMapper postMapper;
위와 같이 MemberController 하나만 사용하게 되면 다른 기능에 필요 없는 의존성까지 주입하게 된다.
회원 프로필 수정에 NutrientsQueryService가 필요한가? 그렇지 않다.
💡결론
그동안 Service 측은 기능을 분리하면서 왜 Controller를 분리하려고 하지 않았는지 의문이다... (마가 씌인 것이야!)
확실히 테스트할 때 많은 불편함을 느꼈는데, 기능 테스트와 예외 테스트가 많아 특정 기능에 대해 작성한 테스트 코드를 찾기 어려웠다.
앞으로의 리팩토링은 Controller를 분리하는 것도 포함하여 진행하는 것이 좋을 것 같다.
'TIL' 카테고리의 다른 글
[TIL-231219] 사용자 정의 애노테이션을 사용한 List 요소 검증 (0) | 2024.03.20 |
---|---|
[TIL-20240307] 주간/월간/연간 섭취량 조회 API 성능 개선 (1) | 2024.03.07 |
[TIL - 20240103] Spring Data JPA @Modifying 문제 (0) | 2024.01.03 |
[TIL - 20231228] Interface의 default 메서드를 활용한 Enum 확장 (0) | 2023.12.28 |
[TIL - 20231226] jacoco 패키지, 클래스 Report에서 제외 (0) | 2023.12.26 |