[CS300 #297] 개발자 커뮤니케이션 — 맥락을 함께 보내는 기술
컴퓨터공학 300 주제 시리즈의 297번째 글이다. 전체 지도는 여기.
한 줄 요약
개발자의 커뮤니케이션은 대부분 비동기 텍스트다. 커밋 메시지, PR 설명, 코드 리뷰 댓글, 이슈, 장애 공지. 좋은 메시지는 받는 사람이 되묻지 않고 행동할 수 있도록 맥락·근거·요청을 함께 담는다.
왜 필요한가
팀이 커질수록 코드보다 사람 사이의 정보 전달이 병목이 된다.
- “이거 왜 이렇게 했어요?” 에 아무도 답하지 못한다. 커밋 메시지가
fix뿐이다. - 리뷰 댓글 하나에 상처받은 동료가 다음 PR 을 올리지 않는다.
- “로그인 안 돼요”라는 이슈에 재현 정보가 없어 다섯 번 왕복한다.
- 장애 중 상황 공유가 없어 세 사람이 같은 조사를 한다.
기술력이 같다면 소통을 잘하는 사람과 팀이 더 빨리 간다. 이것은 성격이 아니라 익힐 수 있는 기술이다.
핵심 개념
동기와 비동기
| 방식 | 예 | 맞는 상황 |
|---|---|---|
| 동기 | 회의, 전화, 페어 프로그래밍 | 빠른 왕복이 필요한 논의, 갈등 해소, 장애 대응 지휘 |
| 비동기 | PR, 이슈, 문서, 메신저 스레드 | 기록이 남아야 하는 결정, 시간대가 다른 협업, 깊은 검토 |
비동기 메시지는 받는 사람이 맥락 없이 읽는다. 그래서 하나의 메시지 안에 완결성이 있어야 한다. “잠깐 시간 되세요?”만 보내고 답을 기다리는 대신, 질문 자체를 처음부터 보낸다.
질문을 잘하는 법
좋은 질문은 답하는 사람의 시간을 아낀다.
목표: 무엇을 하려고 하는가
현상: 무엇이 일어나는가 (오류 메시지 원문, 로그 일부)
기대: 무엇이 일어나야 한다고 생각하는가
시도: 이미 해 본 것과 그 결과
환경: 버전, OS, 설정 (민감 정보는 가린다)
재현: 최소 재현 예제
최소 재현 예제를 만들다 보면 스스로 원인을 찾는 경우가 많다. 그 자체로 디버깅 기법이다.
커밋 메시지
커밋 메시지는 미래의 동료(와 나)에게 보내는 편지다. Git 공식 문서는 50자 이하의 짧은 요약 한 줄로 시작하고, 빈 줄을 둔 뒤 자세한 설명을 쓰는 것을 권한다. 첫 빈 줄까지가 제목으로 취급되어 여러 도구에서 쓰이기 때문이다.
fix(api): 주문 조회 시 타임존을 KST 로 고정 <- 무엇을 (50자 안팎)
<- 빈 줄
UTC 로 저장된 값을 그대로 보여 주어 자정 근처 <- 왜 (diff 가 말해 주지 않는 것)
주문의 날짜가 하루 밀려 보였다.
Refs: #123 <- 관련 이슈
diff 는 “무엇이” 바뀌었는지 보여 준다. 메시지는 diff 가 말하지 못하는 “왜”를 써야 한다. Conventional Commits 명세는 feat, fix 같은 타입과 ! 로 호환성 깨짐을 표시하는 형식을 정해, 변경 기록 생성과 버전 결정을 자동화할 수 있게 한다.
PR 설명
리뷰어는 내 머릿속을 모른다. PR 설명에는 다음을 쓴다.
- 무엇을, 왜 바꾸는가(이슈 링크)
- 어떻게 확인했는가(테스트, 스크린숏, 실행 결과)
- 리뷰어가 특히 봐 줬으면 하는 곳, 그리고 일부러 하지 않은 것
- 배포 시 주의점(마이그레이션, 설정 변경)
PR 은 작게 만든다. 작은 PR 은 빨리 리뷰되고, 리뷰 품질이 높고, 되돌리기 쉽다.
코드 리뷰 댓글
Google 의 공개 엔지니어링 가이드는 코드 리뷰에 대해 몇 가지를 분명히 한다. 리뷰 요청에는 길어도 1 영업일 안에 응답할 것, 코드에 대해 말하고 사람에 대해 말하지 말 것, 이유를 설명할 것, 필수가 아닌 제안은 “Nit:” 처럼 표시할 것.
나쁜 예: 이거 왜 이렇게 짰어요? 비효율적이네요.
좋은 예: 이 루프가 요청마다 DB 를 한 번씩 조회해서 N+1 이 됩니다(목록 100건이면 쿼리 101번).
IN 절로 한 번에 가져오면 어떨까요? 예: SELECT ... WHERE id IN (...)
좋은 예: Nit: 변수 이름 `d` 를 `deadline` 으로 바꾸면 읽기 쉬울 것 같아요. (필수 아님)
받는 쪽도 기술이 필요하다. 리뷰 댓글은 코드에 대한 의견이지 인격 평가가 아니다. 동의하지 않으면 근거를 들어 답하고, 결론이 나지 않으면 짧은 대화로 정리한 뒤 결과를 PR 에 남긴다.
장애 상황의 커뮤니케이션
장애 중에는 정보가 부족하고 사람들이 불안하다. 역할을 나눈다.
| 역할 | 하는 일 |
|---|---|
| 지휘자(incident commander) | 우선순위 결정, 작업 배분 |
| 커뮤니케이터 | 정해진 주기로 상황 공지 |
| 조사·조치 담당 | 원인 파악과 복구 |
공지는 짧고 정기적으로 한다. “현재 영향, 조치 중인 것, 다음 공지 시각.” 모르는 것은 모른다고 쓴다. 추측을 사실처럼 쓰지 않는다.
장애 후 회고(postmortem)는 비난 없이(blameless) 쓴다. Google SRE 책은 회고가 사람을 탓하지 않고 시스템과 절차의 개선점을 찾는 데 집중해야, 사람들이 실수를 숨기지 않고 정직하게 보고한다고 설명한다.
직접 해 보기
커밋 메시지 검사기를 만든다. Git 의 commit-msg 훅이나 CI 에 붙이는 도구가 하는 일이다.
import re
PATTERN = re.compile(r"^(feat|fix|docs|refactor|test|chore|perf|build|ci)(\([\w-]+\))?(!)?: \S")
def lint_commit(msg):
lines = msg.splitlines()
subject = lines[0]
problems = []
if not PATTERN.match(subject):
problems.append("제목이 '<type>(<scope>): <설명>' 형식이 아니다")
if len(subject) > 50:
problems.append(f"제목이 {len(subject)}자. 50자 이내 권장")
if subject.endswith("."):
problems.append("제목 끝에 마침표")
if len(lines) > 1 and lines[1].strip():
problems.append("제목과 본문 사이에 빈 줄이 없다")
if subject.lower().split(":")[-1].strip() in ("수정", "fix", "update", "wip", "변경"):
problems.append("무엇을 왜 바꿨는지 알 수 없는 제목")
return problems
samples = [
"fix: 수정",
"fix(api): 주문 조회 시 타임존을 KST 로 고정\n\nUTC 로 저장된 값을 그대로 보여 주어 날짜가 하루 밀렸다.\nRefs: #123",
"Updated some files and fixed the bug in the login page that users reported.",
"feat(auth)!: 세션 만료 시간을 30분으로 단축\n본문이 붙어 있음",
]
for m in samples:
print(repr(m.splitlines()[0]))
for p in lint_commit(m) or ["문제 없음"]:
print(" -", p)
실행 결과다.
'fix: 수정'
- 무엇을 왜 바꿨는지 알 수 없는 제목
'fix(api): 주문 조회 시 타임존을 KST 로 고정'
- 문제 없음
'Updated some files and fixed the bug in the login page that users reported.'
- 제목이 '<type>(<scope>): <설명>' 형식이 아니다
- 제목이 75자. 50자 이내 권장
- 제목 끝에 마침표
'feat(auth)!: 세션 만료 시간을 30분으로 단축'
- 제목과 본문 사이에 빈 줄이 없다
fix: 수정 은 형식은 맞지만 내용이 없다. 형식 검사는 최소한의 기준일 뿐이다. 50자 기준은 Python 의 len() 이 세는 문자 수로 적용했다. 한글은 터미널에서 두 칸을 차지하므로 팀에 따라 기준을 조정하기도 한다.
현업에서는
- 메신저에서 장애나 결정이 오가면 결론을 이슈나 문서에 옮겨 둔다. 메신저는 검색이 약하고 맥락이 흩어진다. 혼자 운영하는 홈랩 k3s 라도 “왜 이 노드의 설정을 바꿨는지” 를 커밋 메시지나 노트에 남기면 몇 달 뒤 같은 고민을 반복하지 않는다.
- 상태 보고는 “완료”라는 말보다 확인 근거를 함께 쓴다. “배포했다”보다 “배포했고, 헬스체크 URL 이 200 을 반환하는 것을 확인했다”가 낫다. 확인하지 못했다면 그렇다고 쓴다.
- 나쁜 소식은 빨리 알린다. 일정이 밀릴 것 같으면 마감 직전이 아니라 알게 된 순간 공유한다. 일찍 알리면 선택지가 많다.
- 글로 쓰기 어려운 갈등은 짧은 통화로 풀고, 결론은 다시 글로 남긴다.
확인 문제
- 비동기 메시지에 완결성이 필요한 이유는?
- 커밋 메시지 본문에 무엇을 써야 하는가? diff 와 무엇이 다른가?
- 다음 리뷰 댓글을 고쳐 써라: “이건 틀렸어요.”
- 비난 없는 회고가 조직의 신뢰성을 높이는 이유는?
풀이
- 받는 사람이 다른 시간·맥락에서 읽으므로 되묻기 왕복이 비싸다. 한 메시지 안에 목표·현상·요청이 있어야 바로 행동할 수 있다.
- 왜 바꿨는지, 어떤 문제를 풀었는지, 고려한 대안과 영향. diff 는 무엇이 바뀌었는지만 보여 준다.
- 예: “여기서
items가 비어 있으면items[0]에서 IndexError 가 날 것 같습니다. 빈 목록일 때는 기본값을 반환하면 어떨까요?” 문제, 근거, 제안을 담는다. - 사람이 처벌을 두려워하지 않아야 실수와 근본 원인을 정직하게 보고하고, 그래야 시스템과 절차를 고칠 수 있기 때문이다.
더 읽을거리 (References)
- Git, git-commit Documentation — DISCUSSION 절의 메시지 형식
- Conventional Commits 1.0.0
- Google, Code Review Developer Guide
- Google SRE Book, Postmortem Culture: Learning from Failure