Skip to content

3. Code Convention (코드 컨벤션)

Eunbi Lee edited this page Sep 11, 2023 · 14 revisions

1. 기본적으로 Google Java Style Guide를 준수한다.

2. 테스트 코드는 BDD Style로 작성한다.

3. 명명 규칙

\n

클래스의 선언부와 내부 코드 사이에는 한 줄을 띄도록 한다.

public class InterestServiceTest {

    @InjectMocks
    private InterestService interestService;
    ...
} 

필드 사이에는 줄 바꿈이 없도록 한다.

public class InterestFacade {

    private final BadWordChecker badWordChecker;
    private final InterestService interestService;
    private final HashtagService hashtagService;
    ...
}

성질이 다른 필드들 사이에는 한 줄을 띄우도록 한다.

public class SocialAccount {

    private long socialAccountId;
    private Long iconId;
    private long userId;
    private String socialAccountUrl;

    private static String urlRegex = "(?:https?://)?(?:www\\.)?([^/.]+)";
    ...
}

클래스 선언이 종료되는 지점에는 줄 바꿈이 없도록 한다.

public interface InterestMapper {

   int delete(@Param("userId") long userId, @Param("hashtagId") Long hashtagId);
}

DTO는 예외로 필드들 사이에 줄 바꿈을 허용한다.

public class Comment {

    @Schema(example = "1")
    protected long postId;

    @Schema(example = "1")
    protected long userId;

    @Schema(example = "1")
    protected long commentId;

    @Schema(example = "1", description = "대댓글이 존재할 경우, 가장 최상단의 댓글")
    protected long rootId;

    @Schema(example = "화이팅 합시다!")
    protected String content;

    @Schema(example = "방금 전")
    protected String createTime;

    @Schema(example = "1400", defaultValue = "0")
    protected long likeCount;

    @Schema(example = "14", defaultValue = "0")
    protected long commentCount;
}

테스트 코드 작성 시, 검증이 2번 이상 발생하는 메서드는 줄 바꿈을 진행하도록 한다.

    @DisplayName("AddInterest의 String으로 된 필드를 뽑아낼 수 있다.")
    @Test
    void getStringFields(){
        AddInterest addInterest = new AddInterest(1L, "test");

        List<String> stringFields = addInterest.getStringFields();

        assertThat(stringFields).hasSize(1)
                .containsExactly("test");
    }

mapper.xml 파일 작성 시, 쿼리 태그 간엔 줄 바꿈을 진행하도록 한다.

<mapper namespace="flab.project.mapper.UserMapper">

    <insert id="save" parameterType="socialAccount">
        INSERT INTO SOCIAL_ACCOUNTS(icon_id, user_id, social_account_url)
            VALUE (#{socialAccount.iconId},#{socialAccount.userId},#{socialAccount.socialAccountUrl});
    </insert>

    <select id="getNumberOfExistingSocialAccounts" resultType="integer">
        SELECT COUNT(social_account_id)
        FROM SOCIAL_ACCOUNTS
        where user_id = #{userId};
    </select>

    <delete id="remove" parameterType="socialAccount">
        DELETE
        FROM SOCIAL_ACCOUNTS
        WHERE user_id = #{socialAccount.userId}
          AND social_account_url = #{socialAccount.socialAccountUrl};
    </delete>

</mapper>

mapper.xml 파일 작성 시, 쿼리 태그와 mapper 태그 사이에 줄 바꿈을 진행하도록 한다.

<mapper namespace="flab.project.mapper.UserMapper">

    <insert id="updateProfileImage">
        UPDATE USERS
        SET profile_img_url=#{profileImgUrl}
        where user_id = #{userId};
    </insert>

</mapper>

주석

given, when, then은 주석을 붙이도록 한다.

    @DisplayName("존재하는 게시물 또는 존재하는 유저가 좋아요를 추가할 때, 정상적으로 게시물에 좋아요가 반영된다.")
    @Test
    void validParamterInAddPostLike() {
        // given
        long postId = 1L;
        long userId = 2L;

        // when
        likeService.addPostLike(postId, userId);

        // then
        then(likeMapper).should().addPostLike(postId, userId);
    }

given, when, then의 분류가 명확하지 않을 경우, 아래와 같이 작성한다.

    @DisplayName("게시물에 좋아요를 추가할 때, postId 및 userId는 양수 값만 가능하다.")
    @Test
    void parameterOfLikeIsPostitive() throws Exception {
        // given
        long postId1 = 1L;
        long userId1 = 2L;

        given(likeService.addPostLike(postId1, userId1)).willReturn(new SuccessResponse());

        // when & then
        mockMvc.perform(
                post("/posts/{postId}/likes", postId1)
                        .param("userId", String.valueOf(userId1))
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.isSuccess").value(ResponseEnum.SUCCESS.isSuccess()))
                .andExpect(jsonPath("$.code").value(ResponseEnum.SUCCESS.getCode()))
                .andExpect(jsonPath("$.message").value(ResponseEnum.SUCCESS.getMessage()));
    }

단순 학습용 및 메모용 주석은 PR을 올리기 전에 삭제하도록 한다.

Todo 주석은 PR에 포함시키는 것을 허용하며, 머지 전에 삭제하지 않아도 된다.

질문용 주석은 멘토님이 리뷰하신 이후에 머지 전 삭제하도록 한다.

작성 순서

public ~ private 순으로 메서드를 작성하도록 한다. 생성자는 일반 메서드 이전에 작성하도록 한다.

public class AddInterest {

    @Positive
    private long userId;

    @Length(min = 1, max = 15)
    private String interestName;

    public AddInterest(
            @JsonProperty("userId") long userId,
            @JsonProperty("interestName") String interestName
    ) {
        this.userId = userId;
        this.interestName = HtmlUtils.htmlEscape(interestName);
    }

    @JsonIgnore
    public String getInterestNameWithSharp() {
        return "#" + interestName;
    }

    @JsonIgnore
    public List<String> getStringFields() {
        return List.of(interestName);
    }

    private String convertEscapeCharacter() {
        return HtmlUtils.htmlEscape(interestName);
    }
}

변수명

해시태그는 Hashtag/hashtag가 아닌 HashTag/hashTag로 선언한다.

우리 팀은 해시태그가 Hash+Tag로 구성된 합성어로 보고 위의 Convention을 따르기로 결정했다.

Insert, Update, Delete 쿼리의 결과로 반영된 row의 개수를 받을 땐, "numberOfAffectedRow" 변수 명을 사용한다.

DTO

(보류)

(class) AddInterest

테스트

컨트롤러 테스트 코드 작성 시, 아래와 같이 변수를 선언한 후 값을 할당하는 방식으로 진행한다.

    @DisplayName("게시물에 좋아요를 추가할 때, postId 및 userId는 음수 값일 수 없다.")
    @Test
    void parameterOfLikeIsNonPositive() throws Exception {
        // given
        long negativePostId = -1L;
        long negativeUserId = -2L;

        // when & then
        mockMvc.perform(post("/posts/{postId}/likes", negativePostId)
                        .param("userId", String.valueOf(negativeUserId))
                        .contentType(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.isSuccess").value(ResponseEnum.INVALID_USER_INPUT.isSuccess()))
                .andExpect(jsonPath("$.code").value(ResponseEnum.INVALID_USER_INPUT.getCode()))
                .andExpect(jsonPath("$.message").value(ResponseEnum.INVALID_USER_INPUT.getMessage()));
    }

중요하지 않은 필드 값일 경우, 변수로 따로 선언하지 않고 내부에서 바로 값을 사용하는 방식으로 진행한다.

    @DisplayName("관심사 추가 API에서 userId는 양수여야 한다.")
    @Test
    void userIdMustBePositiveWhenAddInterest() throws Exception {
        // given
        long negativeUserId = -1L;

        AddInterest addInterestWithinvalidUserId1 = new AddInterest(negativeUserId, "test");

        // when & then
        mockMvc.perform(
                        post(ADD_INTERST_API_URL, -1)
                                .content(objectMapper.writeValueAsString(addInterestWithinvalidUserId1))
                                .contentType(MediaType.APPLICATION_JSON_VALUE)
                )
                .andDo(print())
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.isSuccess").value(INVALID_USER_INPUT.isSuccess()))
                .andExpect(jsonPath("$.code").value(INVALID_USER_INPUT.getCode()))
                .andExpect(jsonPath("$.message").value(INVALID_USER_INPUT.getMessage()));

매퍼 메서드명

DB의 입장에서 메서드의 명명 규칙을 아래와 같이 정한다.

  1. save vs add : add
  2. get vs find : find