본문 바로가기

블로그 / 기술

사고가 난 자리마다 검사 하나: PallMark 커밋 전 훅을 만든 기록

PallMark 저장소에는 원래 커밋 전 검사가 하나도 없었다. 이틀 동안 실제로 난 사고 여섯 가지에서 규칙을 뽑아 git 훅을 만들고, 거짓 경보를 없애고, 클래스 등록 16자리를 대조하는 검사까지 붙인 과정을 정리했다.

Salmonholic ·· 5분 읽기

PallMark 캐릭터 선택 화면에서 신관 클래스를 고른 모습

PallMark는 Unity로 만드는 PC 게임이고 저장소가 크다. 검증 장치도 많다. 컴파일, 시뮬레이션 시험, 씬 생성, 에디터 시험, 플레이 시험, 화면 캡처까지 여섯 단계의 게이트가 있다. 문제는 이게 전부 커밋 뒤에 돈다는 점이었다. 몇 분에서 몇 시간 뒤, 때로는 다른 기계에서 빨간불이 뜬다. 그 사이에 다른 작업이 그 커밋 위에 쌓인다.

9월 21일 오전 커밋 6a325a2af의 첫 문장은 이렇다. “우리 저장소에는 훅이 하나도 없었다.” 전날과 그날 아이콘 사고 두 건이 바로 그 빈틈에서 났다.

왜 git 훅인가

나는 AI 에이전트 여러 개와 같이 작업한다. 에이전트마다 자기 훅 기능이 있지만, 그건 그 에이전트가 커밋할 때만 돈다. 맥과 윈도 PC를 오가며 작업하니 기계도 여럿이다. git 훅은 누가 커밋하든, 어느 기계에서 하든 git이 부른다. 설치는 한 줄이다.

git config core.hooksPath tools/githooks

규칙도 하나 정했다. 차단(커밋 실패)은 “이대로 커밋되면 다른 기계나 빌드가 깨지는 것”만이다. 나머지는 경고만 띄우고 커밋은 된다. 급할 때는 --no-verify로 건너뛸 수 있지만, 그러면 커밋 메시지에 이유를 적는다.

사고 여섯 가지와 검사 여섯 개

훅의 검사는 모두 실제로 난 사고에서 나왔다. 사고 번호는 코드 주석에 그대로 남아 있다.

사고 무슨 일이 있었나 검사 등급
① FX 맵 항목에 렌더러 정보가 빠져 초기화가 죽었다. 역병사제 22항목 때문에 모든 클래스의 이펙트가 사라졌다 FX 맵 렌더러 정보 확인 차단
② 두 에셋 팩에 같은 그림이 다른 이름으로 있었다. 경로만 보고 서로 다른 아이콘이라 판단했다 아이콘 그림 해시 중복 차단
③ 스킬 아이콘 파일 이름 규칙 위반이 커밋 뒤 원격 셋업에서야 드러났다 아이콘 이름 규칙, 파일 실재 차단
④ 다시 생성해서 고친 생성물이 커밋에 안 들어가, 다른 기계는 옛것을 썼다 생성물 짝 확인 경고
⑤ 생성기 입력이 바뀌었는데 산출물이 따라가지 않고 조용히 낡았다 생성물 짝 확인 경고
⑦ 윈도에서 심볼릭 링크가 텍스트 파일로 풀려 체크아웃됐다. 그걸 커밋하면 맥의 링크 구조가 깨진다 링크가 일반 파일로 바뀌는지 확인 차단

여기에 JSON 파싱 검사를 더했다. 깨진 JSON이 커밋되면 셋업과 게임 실행이 같이 죽는다.

처음엔 매 커밋이 막혔다

첫 버전은 거짓 양성 36건을 냈고, 그래서 모든 커밋이 막혔다. 커밋 메시지에 이렇게 적었다. “매번 걸리는 훅은 아무도 안 쓴다.” 범위를 두 번 좁혀서, 셋업 단계가 실제로 읽는 파일만, 그리고 이번 커밋에서 바뀐 항목만 보게 했다.

검사를 넣은 뒤에는 반증을 돌렸다. 실제로 났던 사고 세 건을 일부러 다시 만들어 넣었더니 모두 차단됐고, 정상 상태에서는 조용했다. 그리고 이 훅은 자기를 도입하는 커밋을 한 번 막았다. 반증용으로 망가뜨려 둔 FX 맵을 되돌리지 않고 커밋하려 했던 것이다.

“늑대 소년이 되면 아무도 안 본다”

그날 밤 경고 하나가 두 번 연속 틀렸다. 생성물 짝 검사는 “입력이 바뀌었는데 산출물이 스테이지에 없다”만 보고 울렸다. 그런데 산출물이 이미 최신이면 스테이지에 없는 게 정상이다. 9월 22일 0시 15분 커밋 51301302f의 제목이 이 글의 소제목이다.

고친 방법은 단순하다. 실제로 산출물을 다시 생성해서 내용을 비교한다. 달라지면 “낡았다”고 경고하고, 같으면 조용하다. 생성기가 1초 남짓이라 훅에서 돌려도 된다. 재생성 자체가 실패하면 그것도 따로 경고한다. “최신이다”와 “확인하지 못했다”를 구별하려는 것이다.

이 수정에도 반증을 두 방향으로 돌렸다. 산출물을 낡게 만들면 경고가 나오는지, 최신이면 경고가 0줄인지. 그런데 첫 수정본에 import 하나가 빠져 있었고, 반증이 그걸 잡았다. 반증을 안 돌렸다면 훅이 모든 커밋에서 오류로 죽는 걸 모르고 넘어갔을 것이다.

PallMark 일곱 클래스의 3D 외형을 가로로 나란히 놓은 확인 이미지 클래스 일곱 개의 외형을 한 줄로 뽑은 확인 이미지. 이 중 둘이 캐릭터 선택 칸에서 비어 있었다

클래스 하나가 등장해야 하는 16자리

같은 날 밤, 같은 모양의 사고가 하루에 세 번 났다. 새로 넣은 신관과 자객이 코드에만 등록되고 배선 JSON과 생성 에셋에서 빠졌다. 컴파일과 시뮬레이션은 그 파일을 읽지 않으니 게이트는 전부 초록이었다.

그래서 커밋 722936e89에서 클래스가 등장해야 하는 자리 16곳을 전수 목록으로 만들었다. 자리마다 “없으면 어떻게 되나”를 적었더니 두 부류로 나뉘었다. 무기 파지 정보처럼 예외로 죽는 자리가 있고, 외형·프리뷰·아이콘·소리처럼 조용히 비는 자리가 있다. 조용히 비는 쪽이 더 무섭다. 이 대조를 Unity 없이 도는 검사로 붙이자 숨어 있던 구멍이 나왔다.

  • 신관·자객의 캐릭터 선택 프리뷰가 비어 있었다.
  • 감시자의 시작 활은 표현 쪽이 존재하지 않는 아이템 id를 가리켜서 외형이 없었다.
  • 성기사와 신관의 스킬 효과음 이름이 해석되지 않아 소리가 안 났다.
  • 역병사제의 고정 패시브 그룹 23개에 아이콘이 없어 레벨업 카드가 빈칸이었다.

검사 결과는 클래스 7개, 오류 0, 경고 8이었다. 검사 줄을 하나씩 지워 보는 반증 30개도 함께 넣었다. 앞으로 클래스를 추가할 때는 이 16자리 목록을 채우도록 작업 명세에도 되먹였다.

남은 교훈

검사는 사고가 난 곳에 하나씩 붙여야 오래 산다. 미리 상상해서 만든 검사는 오탐이 많고, 오탐이 많으면 곧 무시당한다. 그리고 검사도 코드라서 반증 없이는 믿을 수 없다. 게이트 쪽에서 비슷하게 배운 이야기는 혼자 돌리는 QA 글에 적었다. PallMark는 Steam 출시를 목표로 개발 중이다.

#git 훅#품질 관리#Unity#자동 검사#PallMark

함께 읽으면 좋은 글

전체 글 →