코드 리뷰 베스트 프랙티스
코드 리뷰 베스트 프랙티스
1. 개요
최근 팀에서 코드 리뷰 문화를 개선하면서 많은 시행착오를 겪었다. 처음에는 “리뷰를 하긴 하는데, 이게 맞는 건가?” 싶은 순간들이 많았다. 단순히 “LGTM” 한 줄 남기고 승인하거나, 반대로 사소한 스타일 지적에 며칠을 소비하기도 했다.
코드 리뷰는 단순히 버그를 찾는 게 아니다. 팀의 코드 품질을 높이고, 지식을 공유하며, 서로 성장하는 과정이다. 이 글에서는 내가 경험하면서 정리한 코드 리뷰 베스트 프랙티스를 공유한다.
2. 핵심 개념 설명
좋은 코드 리뷰의 목적
- 버그 및 결함 발견: 배포 전에 문제를 잡아낸다
- 코드 품질 향상: 가독성, 유지보수성, 성능 개선
- 지식 공유: 팀원 간 기술 전파와 컨텍스트 공유
- 일관성 유지: 코드 스타일과 아키텍처 통일
리뷰어의 관점
코드 리뷰를 할 때 확인해야 할 체크리스트:
| 항목 | 확인 포인트 |
|---|---|
| 설계 | 변경 사항이 전체 시스템과 잘 어우러지는가? |
| 기능 | 의도한 대로 동작하는가? 엣지 케이스는? |
| 복잡도 | 더 단순하게 구현할 수 있는가? |
| 테스트 | 적절한 테스트가 포함되어 있는가? |
| 명명 | 변수, 함수 이름이 명확한가? |
| 주석 | 필요한 곳에 적절한 설명이 있는가? |
리뷰 요청자의 관점
리뷰를 요청할 때 지켜야 할 원칙:
- 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, 명확한 설명
- 리뷰어의 시간을 존중
- 피드백을 배움의 기회로
처음부터 완벽한 코드 리뷰 문화를 만들 수는 없다. 중요한 건 팀이 함께 지속적으로 개선해 나가는 것이다. 우리 팀도 여전히 다듬어 가는 중이고, 그 과정 자체가 가치 있다고 생각한다.
참고 자료:
Comments