-
Notifications
You must be signed in to change notification settings - Fork 1
컨벤션
hseong3243 edited this page Aug 13, 2024
·
1 revision
- 브랜치 전략은 Github Flow를 기본으로 커스텀해서 사용한다.
- 제품 브랜치는 master 대신 main으로 한다.
- feature(기능), hotifx(버그 수정), refactor(기능 개선)
-
commit message는 아래와 같은 룰을 사용한다.
prefix description feat 기능 구현 fix 오류 수정 setting 설정 정보 추가, refactor 외부 기능이 변경되지 않을 때만 사용 docs README, api 문서 작업 할 때 사용
계층형 아키텍처
- 3주 안에 빠르게 목표에 도달하기 위해 쉽고, 간단한 아키텍처가 적합합니다.
- 팀원 모두가 다른 아키텍처(클린, 헥사고날 아키텍처)에 대한 지식을 가지고 있지 않습니다. 학습에 들일 시간이 부족하기 때문에 익숙한 아키텍처를 선택하였습니다.
기능 기반 패키지
- domain
- member
- performance
- place
- ticket
- global
- config
- ...
- 기능 개발을 진행하면서 프로젝트 구조가 복잡해지는 것을 고려합니다.
네이밍
- 요청, 응답 DTO의 네이밍은
…Request
,…Response
suffix를 사용한다.
클래스 사용
- 일반 클래스를 사용하고
lombok
의@Data
를 사용한다. -
클래스 사용 이유
- 레코드 장점
- toString, equals, hashCode와 같은 반복적인 메서드를 만들어주지 않아도 된다.
- 레코드 단점
-
Getter, Setter
네이밍이 자바빈 규약과 어긋난다. - 자유도가 낮다.
- 다른 클래스들과 일관성을 지키는 편이 좋다고 생각한다.
-
- 레코드 장점
목록 조회 DTO
- 목록 조회 네이밍: 안에 가지는 컨텐트는
{EntityName}Elment
(ex.TicketElement
)로 통일한다. - 페이징
@Getter
public class PageResult<T> {
//hasNext, hasPrevious 와 같은 추가적인 변수 적용 가능
int totalPage;
Long totalCount;
List<T> items;
public PageResult(List<T> items, long totalCount, int totalPage) {
totalPage = data.getTotalPages();
totalCount = data.getTotalElements();
itemList = data.getContent();
}
public static <T> PageResult<T> of(List<T> items, long totalCount, int totalPage) {
return new PageResult<>(items, totalCount, totalPage);
}
}
- 단순 목록
class ItemsResult<T> {
private List<T> items;
public static <T> ItemsResult<T> of(List<T> items) {
return new ItemsResult<>(items);
}
}
ErrorCode의 형태는 다음과 같이 한다.
public enum ErrorCode {
INTERNAL_SERVER_ERROR(500, "예측하지 못한 ~");
private final int statusCode;
private final int message;
이유는 다음과 같다.
- 본 enum의 문제는 여러 계층이 표현 계층과 결합된다는 문제가 있다. 서비스 로직, 영속성 로직이 표현 계층과 결합된다.
- 그러나 계층간의 결합도를 낮추기 위해 에러 코드에서 statusCode를 제거하면 발생할 수 있는 문제도 있다. 표현 계층에서는 에러 코드 enum을 statusCode와 매핑하기 위한 별도의 유틸이 필요하다.
- 우리는 빠른 기능 개발을 목적으로 한다. 따라서 계층간의 결합이 발생하는 문제는 당장은 무시한다. 이후 리팩토링을 통해 결합도를 낮추는 작업이 어렵지 않을 것으로 판단하였다.
검증은 컨트롤러 단에서 Bean Validation을 이용하여 한 번만 수행하는 것으로 한다.
비교
도메인 검증
- 도메인 엔티티에서 검증하면 개발자의 실수를 방지할 수 있다.
- 도메인 엔티티, 로직은 비즈니스에서 가장 중요하게 보호되어야 한다.
빈 밸리데이션
- 복잡한 로직 수행 이전에 검증을 수행하여 코스트를 줄일 수 있다.
투표 결과 도메인 검증 1 : 빈 밸리데이션 3 으로 본 프로젝트의 검증은 빈 밸리데이션으로 수행하는 것으로 한다.
-
@Transactional
어노테이션은 메서드마다 붙인다. - 조회 트랙재션은
@Transactional(readOnly = true)
- 업데이트 트랜잭션
@Transactional
-
nullable = false
,length
옵션은 작성해줍니다. -
cascade
옵션을 사용하려는 경우 팀에 알리고 사용해주세요.
- 테스트는
@Nested
와@DisplayName
을 적극적으로 활용한다.- 단,
@WebMvcTest
의 경우@Nested
를 사용하지 않고 바로 테스트를 작성한다.
- 단,
#1 게시글 생성 시
#1.1 투표 카테고리일 경우
#1.1.1 이미지는 최소 2장 이상 등록해야 한다.
#1.1.2 등록한 이미지가 1장일 경우 예외가 발생한다.
#1.1.3 등록한 이미지가 5장을 초과할 경우 예외가 발생한다.
#1.2 찬반 카테고리일 경우
#1.2.1 이미지는 1장만 등록할 수 있다.
#1.2.2 등록한 이미지가 1장을 초과할 경우 예외가 발생한다.
#2 게시글 수정 시
#2.1 작성자라면
#2.1.1 투표 카테고리의 글을 수정할 때
#2.1.1.1 이미지는 최대 5장까지 추가할 수 있다.
#2.1.1.2 추가한 이미지가 5장을 초과할 경우 예외가 발생한다.
#2.1.1.3 이미지는 2장까지만 삭제할 수 있다.
#2.1.1.4 이미지를 2장 미만으로 삭제할 경우 예외가 발생한다.
#2.1.2 찬반 카테고리의 글을 수정할 때
#2.1.2.1 등록한 이미지 1장만 변경할 수 있다.
#2.1.2.2 추가한 이미지가 1장을 초과할 경우 예외가 발생한다.
#2.2 게시글 작성자가 아닐 경우
#2.2.1.1 수정할 수 없다.
참고 링크: https://velog.io/@langoustine/DCI%ED%8C%A8%ED%84%B4%EC%9C%BC%EB%A1%9C-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EB%8F%85%EC%84%B1-%ED%96%A5%EC%83%81%EC%8B%9C%ED%82%A4%EA%B8%B0
- 표현 계층(controller)은 서비스 계층에 대한 의존성을 Mock으로 대체하여 Rest Docs를 위한 테스트를 작성한다.
- 서비스 계층(service)은 실제 데이터베이스 대신, H2 인메모리에 데이터베이스를 대역으로 사용한 단위 테스트를 작성한다.
- 영속성 계층(repository)은 본인의 판단에 따라 검증이 필요한 경우 작성한다.
- 테스트 검증에 사용하는 라이브러리는 assertj로 통일한다.
-
assertEquals
보다assertThat
이 더 가독성이 좋다고 판단하였다.
-
BDDMockito.given()
을 활용한다. - 행위 기반의 given, when, then 패턴을 활용하기 때문에
when()
으로 시작하기 보다given()
으로 시작하는 것이 의미상 더 적절할 것 같습니다.
//mockito
when(memberPerformanceService.getPerformances())
.thenReturn(List.of(performanceElement));
//BDDMockito
given(memberService.createMember(any())
.willReturn(new MemberCreationResponse(1L));
- 문서화 테스트 작성은 서비스 의존성을 목킹하고 있기 때문에 테스트 패키지와 분리하는 것이 좋아보인다.
- 최상위 패키지
ticketing
아래에docs
패키지를 별도로 두고 문서화 테스트 클래스를 추가한다.