패키지 하나 빼서 주기는 너무 과하고 그렇다고 여기에만 있는것도 좀 그렇긴하네염 ..아니면 저희 baseEntity 랑 같이 두는건 어떨까요 ? -hyeb
혜빈님 말씀대로 별도의 패키지에 공통 model들을 담는것도 좋을 것같네요 - NULL
repository
UserRepository
dto
UserRequest
UserResponse
service
UserService
controller
UserController
team
config
empty
model
Team
TeamInvitation
TeamMember
TeamMemberRole
dto
XXRequest
XXResponse
repository
TeamRepository
TeamInvitationRepository
TeamMemberRepository
service
TeamService
TeamInvitationService
TeamMemberService
controller
TeamController - TeamService, TeamInvitationService, TeamMemberService 의존, 한곳에서 관리 → 뚱뚱해지면 분리
2. 테스트 코드
현재 진행 상황
Service 단 통합 테스트(DB 연동)
Controller 단 Mock 테스트 (진행 중…)
🤔 궁금한 점
Service 통합 테스트 메서드마다 데이터를 DB로 등록하고 있어서,
테스트 실행 속도 저하로 이어지는데, 더 좋은 방법이 있는지 궁금합니다.
서비스 통합테스트를 1순위로 작성하고있는데, 그 다음 순위로 필수로 생각하시는 테스트가 무엇인가요?
💡
저희 생각은 아래와 같은데, 멘토님 생각은 어떠신가요 ?
진형
Service 통합테스트가 1순위라고 생각하는 이유
서비스 목 테스트는 그렇지 않은 함수도 있겠지만 어떤 함수는 given을 통해서 많은 부분에서 응답값을 지정해주고 있고, 테스트 코드 작성이 무의미하다고 느껴질 때도 있어 유효한 테스트 코드를 작성하는데에는 식별하는 시간이 소요되기때문에 비효율적이라고 느껴졌습니다.
처음 테스트 코드를 작성할 시점에는 기능 구현을 빠르게 하고 최소한의 테스트를 하는게 목적이었기 때문에 given으로 일일이 응답값을 입력해줄 필요 없는 Service 통합테스트를 선택했습니다.
2순위는 Controller 목 테스트
클라이언트 요청에 따른 유효성 검사 테스트가 필요하다고 생각했습니다.
그 다음은? service mock 테스트라고 생각합니다.
병연
Mock은 전체 다 반드시 필요
Controller 통합 테스트 반드시 필요
api가 없다면 service Integration이라도 있어야함
동운
Controller 목 테스트 → Service 목 테스트 → Controller 통합 테스트
혜빈
컨트롤러 목 테스트
클라이언트의 입력 값부터 결과까지 해당 API 흐름을 다 테스트하기 때문에 필요하다고 생각합니다.
형욱
Controller mock
실제 흐름을 테스트하는것은 꼭 필요하기 때문에 필수라고 생각합니다.
3. 엔드 포인트
@RequestMapping("/api/teams")
public class TeamInvitationController{
...
}
@RequestMapping("/api/teams")
public class TeamController{
...
}
TeamInvitation과 Team의 현재 RequestMapping이 동일합니다.
@Operation(summary = "초대 목록 조회", description = "자신이 초대받은 초대 목록을 조회한다.")
@GetMapping("/invitations")
public ApiResponse<PageDto.CursorResponse> getInvitations(...) {
...
}
@PostMapping("/{teamId}/invitations")
@Operation(summary = "팀원 초대", description = "팀 ID와 초대 대상 회원 ID를 받아 팀으로 초대한다.")
public ApiResponse<TeamInvitationResponse.InviteResponse> invite(...) {
...
}
다른 컨트롤러 임에도 경우에 따라서 teamId 값이 필요한게 있고 필요 없는 부분이 있어서,
클래스 위의 공통 엔드포인트 설정 부분이 동일한 경우가 있었습니다.
🤔 궁금한 점
편의를 위한 클래스 공통 설정 부분(@RequestMapping)이니까, 상관 없는 부분인 건지?
아니면 엔드 포인트 설계를 잘못한 부분인건지 궁금합니다.
4. 도메인 분리의 어려움
전반적으로 Repository를 도메인 마다 분리가 애매 모하기도 하면서 JPA를 사용하면서 Fetch Join이라는 기능이 다는 아니지만 해당 이점을 못누리는데 있어 JPA를 사용하는데 의미가 없어진다라는 느낌을 가지기도합니다.
그래서 우선 엔티티들을 같은 그룹으로 (우리 팀이 정하고) 묶어서 Repository를 참조하는 방법은 절대 해서는 안되는 방법인지 멘토님 의견이 궁금합니당
또 다른 방법은 User Entity만 fetch Join을 허용하고 나머지 엔티티의 라이프 사이클 범위를 최소화 하는 방식 입니다. erd 구성을 보면 전반적으로 사용자를 기점으로 연관된 것들이 많이 있습니다.
그렇기 때문에 JPA 에서의 장점 중 하나이자 Fetch Join을 일부 하용하는 것입니다. 그리고 나머지의 엔티티의 라이프 사이클 스코프 범위는 기존에 3 tier layer 아키텍처를 적용함으로써 클린한 아키텍처 면에서 의미있지 않을까 생각합니다.
🍯
멘토님에게 질문 투척!
두가지 점을 보았을 떄 멘토님의 생각은 어떠신지 궁금해요
그리고 보통? 실무에서 어떻게 하는지 궁금해용
5. OAuth 코드 피드백 가능할까요?
6. 테스트 가독성을 위한 꿀팁이 있을까요?
하나의 메서드에 대한 예외 케이스가 3-4개 이상 하게 되면,
클래스 전체로 봤을 때는 가독성이 떨어지는 것이 우려가 되는데, 이를 @Nested 를 적극 활용해야 되는지?
테스트 코드의 설명 문장 형식을 통일화 할 필요가 있는지?
테스트 메서드명 짓는 꿀팁이 있을까요?
💎 멘토님 피드백
1. 패키지 구조
모듈단위로 생각을 해보세요
common에는 크게보면 aws가 있고 web이있는 방식
aws에는 aws에 관련된 exception을 넣어보세요.
공통으로 사용되는 모델은 common영역에 빠져서 별도의 공통 model 패키지에 둬보세요
멀티 모듈로 뻈을 때 유저 모듈은 common.model 모듈에 의존성을 갖는것
Location
팀과 유저가 서로 어떻게 의존하고 있는지?
제일 하위에 있는 곳의 모델에 배치를 하면 사용할 수 있다.
매치는 유저를 의존하고있으므로 유저쪽에 location을 둬도 무방하다.
지금은 괜찮지만 패키지 구조도 틀에 박히지 않아도됨, 여러분들이 편하게 생각하는 구조를 잡아 만들어보셔도 됩니다.
서비스, 레포, 컨트롤러 등 모두 엔티티 이름을 따라간 클래스 하나만 만들지 않아도 됩니다.
뚱뚱해지면 분리하는 것입니다.
2. 테스트 코드
🤔 Service 테스트 메서드마다 데이터를 DB로 등록하고 있어서, 테스트 실행 속도 저하로 이어지는데, 더 좋은 방법이 있는지 궁금합니다.
클래스 단위로 데이터를 넣어놓고 진행하면됩니다. 테스트에 대해서는 정답이 있는 부분이 아닙니다.
문제가 있고 여러번 반복되는 행위가 있을 시 청크나 벌크로 사용하면 됩니다. 조금 더 큰 단위로 묶으면 문제가 해결 될 것 같습니다.
고려해야할 부분은 삭제가 잘 일어나는지 고려해야합니다.
🤔 삭제가 포함이 된다면 ? 데이터를 패키지 단위로 넣어 놓고 들어가는데 삭제가 진행 된다면 매번 채워놓고 시작해야하는건가요?
삭제하는 메서드 위에 주입을 하는건 어떨까요?
삭제 한 후에 삭제된 데이터를 미리 백업해서 다시 넣는건 어떨까요
🤔 서비스 통합테스트를 1순위로 작성하고있는데, 그 다음 순위로 필수로 생각하시는 테스트가 무엇인가요?
Mock 우선순위, 통합 우선순위 사실상 둘다 맞는 말이다.
당장 정답을 따질 수 없지만 현재 상황(시간이 없는 관계로)으로는 통합 테스트로 진행해 보는 것은 어떨까요 ?
네이티브나 동적 쿼리가 있다면 repository 테스트도 진행해야합니다.
3. 엔드 포인트
컨트롤러 분리 ( 팀 관리, 팀 초대 . .. ) 하면 어떨지
하나의 엔티티에서 여러 도메인이 나올수있다
ex) 바우처는 2개의 도메인에서 하나의 엔티티만 사용하고 있음, 엔티티는 단일 테이블을 의미하고 있음
도메인도 너무 뚱뚱하면 에픽이나 스토리 단위로 나눌 수 있다.
유사한 도메인마다 묶어져있으니까 행위에대해서 조금 더 뭉쳐져있는 도메인이있을것이고 하나의 컨트롤러로 묶일 수 있을 것
메서드가 몇 개 일때 분리를 하는게 맞을까요?
컨트롤러에서 서비스메서드 딱 한줄 사용하는 경우가 있는데, 20개 있다고 헷갈리지는 않음.
하지만 참조하는 부분이 많은 코드는 10개만 있어도 헷갈릴 수 있음.
그러니 메서드 수나 코드라인 수에 따라 분리하지 말고 복잡할 때 분리하면 됩니다.
의존성이 많은 클래스는 어떤 역할을 하는지 불분명하다.
엔드 포인트 (requestMapping)은 같아도 상관 없습니다.
경우에 따라 다르지만, 컨트롤러의 의존성은 5개가 적절하다.
유지보수에는 편의성도 중요합니다.
코드 작성자가 편리하지 않은데 유지보수가 쉬울 수 없습니다.
4. 도메인 분리
크기가 작기 때문에 아키텍처가 클린하게 가져갈 필요는 없다고 생각합니다.
대신에 1번으로 가져간다면 신중해야할 것 같습니다.
repository를 무조건 하나만 가져가야하는 건 아닙니다.
방향성은 개발이 편리한 방향으로 가져가는 것이 우선이다 (현 7일 시점에서)
실무는 어떤지?
핵심은 실무에서 하는 것은 환상한가 클린할 수 있기도 하지만 강남의 뒷골목과 비슷하다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ → 팀 내부적으로 보면 실망스러운 부분이 많을 거다. (현재 리소스 안에서 빠르게 개발하는 게 가장 중요한 핵심이고 우선순위 이다.)
실무는 여유가 없다.
거의 리팩타링 못한다. 따로 개인적으로 하는게 대부분이다.
우선 패키지 구조먼저 잡는 것이 먼저 인 것 같다.
도메인 관련 서비스 단위로 나누고 시도하면 좋을 것 같다.
페치를 공존해서 사용하는게 좋다.
도메인이 곧 엔티티 처럼 되고 있는 문제 - 병연님, 진형님 의견 [바운더리 컨텍스트]
현 시점에서 패키지 구조를 만족 위에것을 봤을 떄
좀 더 세부적으로 나누면 좋을 것 같다.
팀 초대 , 관리는 다르므로 이런식으로 그룹핑 하는게 좋을 것 같다.
바우처가 있으면, 고정 할인 바우처랑, 정률할인 바우처 처럼 나누듯이 나눌 수 있다.
행위 단위로 분리하는 것이 좋을 것 같다.
ex) 팀 초대 영역이랑 팀 관리 영역이 컨텍스트가 나뉠수 있다고 생각한다.
패키지에 전반적으로 레이어드 아키텍처 향이 많이 묻어나있지 않나~~ 싶습니다.
지금은 패키지 구조(진형님이 쓴 방향) 맘에 듬.
코드적으로는 표준이 있지만 구조는 표준이 없다. 우리만의 이렇게 구조를 해보자 ! 만든다.
우리의 목적은 점진적과 영속성 이다.
🍯
결론
- 우선 이렇게 그룹으로 나누어보고 점점 개선시키자!
5. OAuth 코드 피드백
6. 테스트 가독성
전체적으로 테스트 코드는 너무 형식에 맞출 필요는 없음.
하나의 메서드에 대한 예외 케이스가 3-4개 이상 하게 되면,
클래스 전체로 봤을 때는 가독성이 떨어지는 것이 우려가 되는데, 이를 @Nested 를 적극 활용해야 되는지?
Nested를 써도 되지만, 설명란에 prefix를 붙이는 방법도 있다.
→ 클래스 단위로 꼭 묶을 필요는 없이 prefix로 명시만 해주고, flat하게 가져가도 됨.
테스트 코드의 설명 문장 형식을 통일화 할 필요가 있는지?
테스트 코드의 목적 자체가 테스트가 잘 되고 있는지 확인을 위한 작업이니,
문장을 보고 이해할 수 있으면 되고, 너무 형식에 얽매이지 않아도 된다.