3 minute read

코드 리뷰 베스트 프랙티스

1. 개요

최근 팀에서 코드 리뷰 문화를 개선하면서 많은 시행착오를 겪었다. 처음에는 “리뷰를 하긴 하는데, 이게 맞는 건가?” 싶은 순간들이 많았다. 단순히 “LGTM” 한 줄 남기고 승인하거나, 반대로 사소한 스타일 지적에 며칠을 소비하기도 했다.

코드 리뷰는 단순히 버그를 찾는 게 아니다. 팀의 코드 품질을 높이고, 지식을 공유하며, 서로 성장하는 과정이다. 이 글에서는 내가 경험하면서 정리한 코드 리뷰 베스트 프랙티스를 공유한다.

2. 핵심 개념 설명

좋은 코드 리뷰의 목적

  1. 버그 및 결함 발견: 배포 전에 문제를 잡아낸다
  2. 코드 품질 향상: 가독성, 유지보수성, 성능 개선
  3. 지식 공유: 팀원 간 기술 전파와 컨텍스트 공유
  4. 일관성 유지: 코드 스타일과 아키텍처 통일

리뷰어의 관점

코드 리뷰를 할 때 확인해야 할 체크리스트:

항목 확인 포인트
설계 변경 사항이 전체 시스템과 잘 어우러지는가?
기능 의도한 대로 동작하는가? 엣지 케이스는?
복잡도 더 단순하게 구현할 수 있는가?
테스트 적절한 테스트가 포함되어 있는가?
명명 변수, 함수 이름이 명확한가?
주석 필요한 곳에 적절한 설명이 있는가?

리뷰 요청자의 관점

리뷰를 요청할 때 지켜야 할 원칙:

  • PR은 작게 유지: 200-400줄 이하가 이상적
  • 명확한 설명 작성: 왜 이 변경이 필요한지 컨텍스트 제공
  • 셀프 리뷰 먼저: 본인이 먼저 한 번 훑어보기

3. 실제 코드 예제

나쁜 코드 리뷰 예시

// 리뷰어 코멘트: "이거 이상한데요"
// 이런 피드백은 도움이 되지 않는다

public List<User> getUsers(String status) {
    List<User> result = new ArrayList<>();
    for (User u : userRepository.findAll()) {
        if (u.getStatus().equals(status)) {
            result.add(u);
        }
    }
    return result;
}

좋은 코드 리뷰 예시

// 리뷰어 코멘트:
// 1. NPE 위험: u.getStatus()가 null일 수 있습니다
// 2. 성능: DB에서 필터링하면 네트워크 비용을 줄일 수 있습니다
// 3. 제안:
//    return userRepository.findByStatus(status);
//    또는 Stream API를 사용하면 어떨까요?

// 개선된 코드
public List<User> getUsers(String status) {
    if (status == null) {
        throw new IllegalArgumentException("status는 필수입니다");
    }
    return userRepository.findByStatus(status);
}

PR 템플릿 예시

## 변경 사항
- 사용자 조회 API에 상태 필터 기능 추가

## 변경 이유
- CS팀에서 특정 상태의 사용자만 조회하는 기능 요청 (#123)

## 테스트
- [x] 단위 테스트 추가
- [x] 로컬에서 API 테스트 완료

## 리뷰 포인트
- UserRepository.findByStatus() 쿼리 성능 확인 부탁드립니다

효과적인 피드백 작성법

// Before: 요청 코드
public void processOrder(Order order) {
    if (order.getItems().size() > 0) {
        // 처리 로직
        for (int i = 0; i < order.getItems().size(); i++) {
            Item item = order.getItems().get(i);
            inventory.decrease(item.getId(), item.getQuantity());
        }
        order.setStatus("PROCESSED");
        orderRepository.save(order);
    }
}
// 리뷰 코멘트 (구체적이고 건설적)
/**
 * [suggestion] 몇 가지 개선 포인트가 있습니다:
 * 
 * 1. isEmpty() 사용: size() > 0 보다 의도가 명확합니다
 * 2. 향상된 for문: 인덱스가 필요 없으므로 for-each 권장
 * 3. 상수 사용: 문자열 "PROCESSED" → OrderStatus.PROCESSED
 * 4. 트랜잭션: 재고 감소와 주문 저장이 원자적으로 처리되어야 할 것 같습니다
 */

// After: 개선된 코드
@Transactional
public void processOrder(Order order) {
    if (!order.getItems().isEmpty()) {
        for (Item item : order.getItems()) {
            inventory.decrease(item.getId(), item.getQuantity());
        }
        order.setStatus(OrderStatus.PROCESSED);
        orderRepository.save(order);
    }
}

4. 실무에서의 적용 팁

코멘트에 접두사 사용하기

팀에서 도입해서 효과를 본 방법이다. 코멘트의 성격을 명확히 하면 불필요한 논쟁을 줄일 수 있다.

[must] : 반드시 수정 필요 (버그, 보안 이슈)
[suggestion] : 제안사항, 선택적 수정
[question] : 이해를 위한 질문
[nit] : 아주 사소한 지적 (오타, 포맷팅)
[praise] : 좋은 코드에 대한 칭찬

리뷰 시간 확보하기

// 팀 규칙 예시
- 리뷰 요청 후 24시간 내 최소 1차 피드백
- 매일 오전 30분은 코드 리뷰 시간으로 확보
- 긴급 PR은 슬랙에서 별도 요청

자동화할 수 있는 것은 자동화

# .github/workflows/lint.yml
name: Lint Check
on: [pull_request]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run Checkstyle
        run: ./gradlew checkstyleMain

스타일, 포맷팅, 정적 분석은 도구에 맡기고, 리뷰어는 로직과 설계에 집중하자.

비동기 리뷰의 한계 인식하기

복잡한 변경이나 설계 논의가 필요한 경우, 코멘트로 끝없이 핑퐁하지 말고 10분 화상 회의가 더 효율적일 때가 있다.

5. 정리

코드 리뷰를 잘하는 건 결국 커뮤니케이션이다.

리뷰어로서:

  • 구체적이고 건설적인 피드백 제공
  • 왜 문제인지, 어떻게 개선할 수 있는지 설명
  • 좋은 코드도 칭찬하기

리뷰 요청자로서:

  • 작은 PR, 명확한 설명
  • 리뷰어의 시간을 존중
  • 피드백을 배움의 기회로

처음부터 완벽한 코드 리뷰 문화를 만들 수는 없다. 중요한 건 팀이 함께 지속적으로 개선해 나가는 것이다. 우리 팀도 여전히 다듬어 가는 중이고, 그 과정 자체가 가치 있다고 생각한다.


참고 자료:

Categories:

Updated:

Comments