코드 리뷰 문화 정착 - 주니어 개발자 2명을 독립 개발자로 만든 방법
공동주택 관리 서비스 팀에 백엔드 주니어 1명, 프론트 주니어 1명이 들어왔다. 3개월 후 이들은 독립적으로 기능을 개발하고 배포할 수 있는 개발자가 됐다. 코드 리뷰 프로세스를 도입하고 멘토링한 과정을 정리한다.
시작점
2021년 9월, 공동주택 관리 서비스 개발팀에 주니어 개발자 2명이 입사했다.
- 주니어A (백엔드): Python 6개월 경험, FastAPI 처음
- 주니어B (프론트): JavaScript 3개월 경험, React 처음
- 나: 백엔드 개발 및 팀 리드
팀 기술 스택을 Python/FastAPI, React로 결정한 직후였다. 주니어들은 프레임워크 경험이 없었고, 나는 이들을 어떻게 온보딩할지 고민이었다.
초기 문제
처음 1주일은 주니어들에게 간단한 CRUD API를 만들어보라고 했다.
결과:
- 코드가 돌아가지 않는다 (문법 에러, 미완성 함수)
- 커밋 메시지가 “수정”, “테스트”, “ㅁㄴㅇㄹ” 같은 형태
- main 브랜치에 직접 푸시
- 버그가 프로덕션에 배포됨
명확한 가이드라인이 필요했다.
코드 리뷰 프로세스 도입
1. Branch Protection Rule 설정
GitHub에서 main 브랜치 직접 푸시를 막았다.
Settings → Branches → Branch protection rules
✓ Require a pull request before merging
✓ Require approvals (1명 이상)
✓ Dismiss stale pull request approvals when new commits are pushed
이제 main에 푸시하려면 PR이 필수다.
2. PR 템플릿 작성
.github/PULL_REQUEST_TEMPLATE.md 파일을 만들어서 PR 작성 가이드를 제공했다.
## 무엇을 변경했나요?
<!-- 변경 내용을 간단히 설명해주세요 -->
## 왜 변경했나요?
<!-- 변경 이유 (버그 수정, 기능 추가, 리팩토링 등) -->
## 어떻게 테스트했나요?
<!-- 테스트 방법을 설명해주세요 -->
- [ ] 로컬에서 테스트 완료
- [ ] 관련 API 동작 확인
## 스크린샷 (선택)
<!-- UI 변경이 있다면 스크린샷을 첨부해주세요 -->
## 체크리스트
- [ ] 코드가 정상 동작합니다
- [ ] 커밋 메시지가 명확합니다
- [ ] 불필요한 주석이나 console.log가 없습니다
3. 첫 코드 리뷰
주니어A가 처음 올린 PR:
# 학생 목록 조회 API
@router.get("/students")
def get_students(db: Session = Depends(get_db)):
students = db.query(Student).all()
return students
내 리뷰:
💬 코멘트 1: 반환 타입을 명시하면 좋겠습니다
def get_students(...) -> List[StudentResponse]:
💬 코멘트 2: 에러 처리가 없네요
DB 조회 실패 시 어떻게 처리할지 고민해보세요
💬 코멘트 3: 페이징이 필요할 것 같은데요
학생이 1000명이면 한 번에 다 조회할까요?
주니어A 반응: “아… 생각 못 한 부분이 많네요”
4. 수정 후 재요청
from typing import List
from fastapi import HTTPException
@router.get("/students", response_model=List[StudentResponse])
def get_students(
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db)
) -> List[StudentResponse]:
try:
students = db.query(Student).offset(skip).limit(limit).all()
return [StudentResponse.from_orm(s) for s in students]
except Exception as e:
raise HTTPException(status_code=500, detail="학생 목록 조회 실패")
내 리뷰:
✅ Approve
타입 명시, 에러 처리, 페이징 모두 반영됐네요!
한 가지 더: Exception을 광범위하게 잡기보다
SQLAlchemyError 같은 구체적인 예외를 잡는 게 좋습니다.
다음 PR에서 시도해보세요.
리뷰 원칙
주니어를 리뷰하면서 지킨 원칙:
1. “왜 안 좋은지” 설명한다
❌ 나쁜 리뷰:
이 코드는 문제가 있습니다. 수정해주세요.
✅ 좋은 리뷰:
이 코드는 N+1 문제가 발생합니다.
루프 안에서 DB 조회를 100번 하면 느려집니다.
JOIN을 사용하거나 한 번에 조회하는 방식으로 개선해보세요.
2. 완벽을 요구하지 않는다
처음부터 모든 걸 완벽하게 하길 기대하지 않았다. 한 PR에서 1~2개 개선점만 지적하고, 나머지는 나중에.
단계적 개선:
- 1주차: 문법 에러, 기본 동작 확인
- 2주차: 에러 처리, 타입 힌트
- 3주차: 성능, 테스트
- 4주차: 설계, 아키텍처
3. 긍정 피드백을 먼저
✅ 에러 처리를 잘 추가했네요!
✅ 변수명이 명확해서 읽기 좋습니다.
💬 한 가지 개선하면 좋을 점:
여기서 try-except 범위를 좁히면 어떨까요?
비판만 하면 의욕이 떨어진다. 잘한 부분을 먼저 언급하고, 개선점을 제안한다.
4. 질문 형태로 유도한다
❌ 지시형:
이 부분은 함수로 분리하세요.
✅ 질문형:
이 부분이 여러 곳에서 반복되는 것 같은데,
함수로 분리하면 어떨까요?
질문 형태로 하면 스스로 생각하게 만든다.
5. 참고 자료를 같이 제공
이 부분은 SOLID 원칙 중 단일 책임 원칙(SRP)에 어긋납니다.
https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
읽어보시고 다음 PR에 적용해보세요.
단순히 “고치세요”가 아니라 “왜 그런지, 어떻게 하는지” 배울 수 있게.
주니어 성장 과정
1개월차: 코드가 돌아간다
- 문법 에러 없이 동작하는 코드
- 커밋 메시지가 명확해짐 (“학생 목록 조회 API 추가”)
- PR 템플릿을 채워서 올림
2개월차: 에러 처리와 테스트
- try-except 추가
- 타입 힌트 사용
- 간단한 단위 테스트 작성
- 리뷰 코멘트를 반영하는 속도가 빨라짐
3개월차: 독립 개발 가능
- 기능 명세서를 받으면 혼자 API 설계
- DB 스키마, 비즈니스 로직, 테스트까지 구현
- 내 리뷰 없이도 다른 주니어 코드를 리뷰
- “이 부분은 어떻게 하면 좋을까요?” 질문의 질이 올라감
리뷰 통계
3개월간 PR 통계:
| 항목 | 주니어A | 주니어B |
|---|---|---|
| 총 PR 수 | 45개 | 38개 |
| 평균 리뷰 소요 시간 | 30분 | 40분 |
| Approve까지 평균 반복 | 1.8회 | 2.1회 |
| Request Changes 비율 | 60% → 20% | 70% → 25% |
초반에는 Request Changes가 많았지만, 3개월 후에는 1~2번 코멘트로 Approve 가능한 수준이 됐다.
예상치 못한 부수 효과
1. 주니어끼리 리뷰
2개월차부터 주니어A와 주니어B가 서로 코드를 리뷰하기 시작했다.
주니어A → 주니어B PR:
"이 부분은 useState보다 useReducer가 나을 것 같아요"
내가 시키지 않았는데 자발적으로.
2. 문서화 개선
주니어B가 PR에 스크린샷과 동작 영상을 첨부하기 시작했다. “다른 사람이 이해하기 쉽게”라는 마인드가 생긴 것.
3. 버그 감소
코드 리뷰로 배포 전에 버그를 발견하는 경우가 많아졌다. 프로덕션 버그가 70% 감소했다. (로그 분석 기준)
실패 사례
모든 게 순조롭지는 않았다.
1. 리뷰가 너무 세세했던 적
초반에 변수명, 줄바꿈, 공백까지 지적했더니 주니어가 위축됐다.
주니어A: "리뷰가 무섭습니다..."
이후 중요한 것(로직, 버그)만 지적하고 스타일은 린터에 맡겼다.
2. 리뷰 시간 부족
내 업무가 바쁠 때 리뷰가 하루 이상 밀렸다. 주니어가 대기하는 시간이 길어졌다.
해결:
- 오전 10시, 오후 4시 두 번 리뷰 타임 고정
- 긴급한 PR은 사내메신저로 멘션
3. “왜”를 설명 안 했을 때
“이렇게 고치세요”만 하고 이유를 안 알려주면 다음에도 같은 실수를 한다.
개선: 항상 “왜”를 추가. “이렇게 하면 ~한 문제가 생기기 때문입니다”
배운 점
-
코드 리뷰는 교육 도구다. 주니어 교육의 가장 효과적인 방법이었다. 책이나 강의보다 실제 코드를 리뷰하는 게 배움이 빠르다.
-
칭찬과 비판의 균형이 중요하다. 비판만 하면 위축되고, 칭찬만 하면 성장이 느리다. 7:3 비율 (칭찬 7, 개선점 3)이 적당했다.
-
시간이 걸린다. 리뷰는 시간이 많이 든다. 하루 1~2시간을 리뷰에 썼다. 하지만 3개월 후 주니어들이 독립 개발하면서 내 시간이 오히려 절약됐다.
-
규칙보다 문화가 중요하다. PR 템플릿, Branch Protection은 도구일 뿐. “코드는 함께 만드는 것”이라는 문화가 먼저다.
-
리뷰어도 배운다. 주니어 코드를 리뷰하면서 “내가 당연하게 생각한 것”을 설명하다 보니, 내 지식도 정리됐다.
마무리
코드 리뷰는 단순히 버그를 찾는 도구가 아니다. 팀의 코드 품질을 올리고, 주니어를 성장시키고, 협업 문화를 만드는 과정이다. 처음엔 시간이 많이 들지만, 장기적으로는 팀 전체의 생산성을 높인다. 3개월 후 주니어 2명이 독립 개발자가 된 걸 보면서, 코드 리뷰에 투자한 시간이 아깝지 않았다고 느꼈다.