Skip to content

컨벤션

hseong3243 edited this page Aug 13, 2024 · 1 revision

1. 브랜칭 컨벤션

Github Flow

Untitled

  • 브랜치 전략은 Github Flow를 기본으로 커스텀해서 사용한다.
  • 제품 브랜치는 master 대신 main으로 한다.
  • feature(기능), hotifx(버그 수정), refactor(기능 개선)

2. 커밋 커벤션

  • commit message는 아래와 같은 룰을 사용한다.

    prefix description
    feat 기능 구현
    fix 오류 수정
    setting 설정 정보 추가,
    refactor 외부 기능이 변경되지 않을 때만 사용
    docs README, api 문서 작업 할 때 사용

3. 코드 컨벤션

1) 아키텍처

계층형 아키텍처

  1. 3주 안에 빠르게 목표에 도달하기 위해 쉽고, 간단한 아키텍처가 적합합니다.
  2. 팀원 모두가 다른 아키텍처(클린, 헥사고날 아키텍처)에 대한 지식을 가지고 있지 않습니다. 학습에 들일 시간이 부족하기 때문에 익숙한 아키텍처를 선택하였습니다.

2) 패키지 구조

기능 기반 패키지

- domain
	- member
	- performance
	- place
	- ticket
- global
	- config
	- ...
  1. 기능 개발을 진행하면서 프로젝트 구조가 복잡해지는 것을 고려합니다.

3) DTO 사용

네이밍

  • 요청, 응답 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);
		}
}

4) 예외

ErrorCode의 형태는 다음과 같이 한다.

public enum ErrorCode {
	INTERNAL_SERVER_ERROR(500, "예측하지 못한 ~");
	
	private final int statusCode;
	private final int message;

이유는 다음과 같다.

  • 본 enum의 문제는 여러 계층이 표현 계층과 결합된다는 문제가 있다. 서비스 로직, 영속성 로직이 표현 계층과 결합된다.
  • 그러나 계층간의 결합도를 낮추기 위해 에러 코드에서 statusCode를 제거하면 발생할 수 있는 문제도 있다. 표현 계층에서는 에러 코드 enum을 statusCode와 매핑하기 위한 별도의 유틸이 필요하다.
  • 우리는 빠른 기능 개발을 목적으로 한다. 따라서 계층간의 결합이 발생하는 문제는 당장은 무시한다. 이후 리팩토링을 통해 결합도를 낮추는 작업이 어렵지 않을 것으로 판단하였다.

5) Validation

검증은 컨트롤러 단에서 Bean Validation을 이용하여 한 번만 수행하는 것으로 한다.

비교

도메인 검증

  • 도메인 엔티티에서 검증하면 개발자의 실수를 방지할 수 있다.
  • 도메인 엔티티, 로직은 비즈니스에서 가장 중요하게 보호되어야 한다.

빈 밸리데이션

  • 복잡한 로직 수행 이전에 검증을 수행하여 코스트를 줄일 수 있다.

투표 결과 도메인 검증 1 : 빈 밸리데이션 3 으로 본 프로젝트의 검증은 빈 밸리데이션으로 수행하는 것으로 한다.

6) @Transactional

  • @Transactional 어노테이션은 메서드마다 붙인다.
  • 조회 트랙재션은 @Transactional(readOnly = true)
  • 업데이트 트랜잭션 @Transactional

7) @Column

  • nullable = false , length 옵션은 작성해줍니다.
  • cascade 옵션을 사용하려는 경우 팀에 알리고 사용해주세요.

4. 테스트

1) @Nested

  • 테스트는 @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

2) 계층별 테스트

  • 표현 계층(controller)은 서비스 계층에 대한 의존성을 Mock으로 대체하여 Rest Docs를 위한 테스트를 작성한다.
  • 서비스 계층(service)은 실제 데이터베이스 대신, H2 인메모리에 데이터베이스를 대역으로 사용한 단위 테스트를 작성한다.
  • 영속성 계층(repository)은 본인의 판단에 따라 검증이 필요한 경우 작성한다.

3) 테스트 검증 라이브러리

  • 테스트 검증에 사용하는 라이브러리는 assertj로 통일한다.
  • assertEquals 보다 assertThat이 더 가독성이 좋다고 판단하였다.

4) 모키토 사용 방식

  • BDDMockito.given()을 활용한다.
  • 행위 기반의 given, when, then 패턴을 활용하기 때문에 when() 으로 시작하기 보다 given() 으로 시작하는 것이 의미상 더 적절할 것 같습니다.
//mockito
when(memberPerformanceService.getPerformances())
.thenReturn(List.of(performanceElement));

//BDDMockito
given(memberService.createMember(any())
.willReturn(new MemberCreationResponse(1L));

5) RestDocs 패키징

  • 문서화 테스트 작성은 서비스 의존성을 목킹하고 있기 때문에 테스트 패키지와 분리하는 것이 좋아보인다.
  • 최상위 패키지 ticketing 아래에 docs 패키지를 별도로 두고 문서화 테스트 클래스를 추가한다.