ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 하네스 엔지니어링 9단계 베스트 프랙티스 #8. 측정과 회고
    IT 2026. 4. 27. 22:20
    하네스 엔지니어링 9단계 베스트 프랙티스 #8. 측정과 회고

    시리즈 맥락 복기 — 마지막 편입니다

    긴 여정의 마지막 편입니다. 여기까지 오면서 우리는 지도(#0), 규칙(#1), 지형도(#2), Skill(#3), Hook(#4), 자동 트리거(#5), HITL(#6), 감사 로그(#7)를 차례로 쌓아 올렸습니다. 이제 남은 건 "이 모든 것이 실제로 잘 작동하고 있는가"를 숫자로 검증하는 단계입니다.

    1. #0 업무 프로세스 매핑
    2. #1 프로젝트 규칙 설정
    3. #2 Code Wiki 작성
    4. #3 Skill 정의
    5. #4 검증(Hook)
    6. #5 자동 트리거 + 완료 조건
    7. #6 HITL 정책
    8. #7 감사 로그
    9. #8 측정 + 회고 ← 이번 편

    이 단계의 의미 — Step 8은 하네스의 '계기판'

    Step 8은 말에 채운 마구를 다 정비한 뒤, "지금 시속 몇 km로 달리고 있는가"를 보는 계기판입니다. 계기판 없이 달리면 속도 조절을 못 하고, 엔진이 과열되어도 모릅니다. 같은 이유로 자동화도 측정 지표 없이는 개선 방향을 못 정합니다.

    해결하려는 문제

    • "자동화 한 것 같은데 시간이 왜 안 줄지?": Before/After를 측정하지 않으면 개선 효과가 체감되지 않습니다.
    • 좀비 상태 파일: 파이프라인이 도중에 죽으면 상태 파일이 남아서 다른 세션까지 영향을 줍니다.
    • 세션 간섭: 터미널 두 개에서 동시에 에이전트를 돌릴 때 한쪽의 진행 상태가 다른 쪽을 막는 사고.

    효과 — 측정이 바꾸는 것

    측정이 되면 "이 파이프라인은 하루 평균 X번 돌고, 성공률은 Y%" 같은 문장을 쓸 수 있게 됩니다. 그러면 "다음에 어디를 개선할까"가 감이 아니라 숫자로 정해집니다. 개인 경험상 측정을 시작한 이후, 자동화 품질이 주관적 체감 → 객관적 지표로 바뀌면서 개선 속도가 눈에 띄게 빨라졌습니다.

    베스트 프랙티스 1 — 파이프라인 상태 추적

    각 Skill이 PostToolUse 훅에서 상태 파일을 업데이트합니다. 상태 파일은 파이프라인이 지금 몇 단계까지 진행됐는지를 기록하는 스냅샷입니다.

    # calendar_sync.py — 단계 완료 추적 예시
    def track_bash(cmd, data):
        if "calendar_sync.main sync" in cmd:
            state = {
                "step1_sync": True,
                "step2_voice": False,
                "step3_ai_organizer": False,
                "step5_git": False,
                "step6_notify": False,
                "claude_pid": find_claude_pid(),
            }
            save_state("calendar_sync", state)
            return True
    

    이 상태 파일 덕분에 두 가지가 가능해집니다.

    • Stop 훅이 미완료 감지: "6단계 중 3단계에서 끊긴 파이프라인이 있다"고 경고.
    • 측정 가능: "step5_git까지 간 비율"을 집계하면 각 단계의 실패율이 나옵니다.

    베스트 프랙티스 2 — 세션 격리로 충돌 방지

    터미널 A와 터미널 B에서 동시에 에이전트를 쓰면, 한쪽 세션의 상태 파일이 다른 쪽 세션의 종료를 차단하는 사고가 생깁니다. 이를 세션 격리로 해결합니다.

    def find_claude_pid():
        pid = os.getpid()
        while pid > 1:
            try:
                comm = Path(f"/proc/{pid}/comm").read_text().strip()
                if comm == "claude":
                    return pid
                ppid = int(Path(f"/proc/{pid}/stat").read_text().split()[3])
                pid = ppid
            except Exception:
                break
        return None
    
    def is_same_session(state):
        stored = state.get("claude_pid")
        current = find_claude_pid()
        if stored and current and stored != current:
            return False
        return True
    

    훅은 Claude Code의 자식 프로세스로 실행됩니다. /proc 트리를 거슬러 올라가 claude 프로세스의 PID를 찾아, 이를 세션 식별자로 사용합니다. 상태 파일에 기록된 PID와 지금 훅이 속한 세션의 PID가 다르면 "다른 세션의 상태"로 보고 무시합니다.

    베스트 프랙티스 3 — 2시간 TTL로 좀비 파일 정리

    세션이 비정상 종료되면 상태 파일이 남습니다. 이를 방치하면 다음 세션의 판단을 흐립니다. 간단한 TTL 로직으로 해결합니다.

    def is_stale(name):
        path = STATE_FILES[name]
        try:
            return time.time() - path.stat().st_mtime > STALE_SECONDS  # 2시간
        except Exception:
            return True
    

    Stop 훅이 실행될 때마다 이 함수를 돌려, 2시간 이상 업데이트되지 않은 상태 파일을 삭제합니다. 사람이 청소할 필요가 없어집니다.

    측정 지표 — 감사 로그로 계산하기

    #7의 감사 로그 JSONL과 상태 파일을 조합하면, 이런 지표들을 바로 뽑을 수 있습니다.

    지표 측정 방법 무엇을 알려주는가
    파이프라인별 실행 횟수 jq '.pipeline' audit.jsonl | sort | uniq -c 어느 Skill이 많이 쓰이는가
    차단된 위험 명령 수 jq 'select(.tags[]=="blocked")' | wc -l HITL 정책이 얼마나 방어했는가
    일일 작업량 날짜 필터 + count 에이전트 활용도
    세션당 평균 명령 수 session별 그룹핑 count 세션당 작업 밀도
    단계별 실패율 상태 파일의 step_N true 비율 파이프라인 병목 지점
    테스트 통과율 pytest 결과 파싱 TDD 품질 지표

    Before / After 비교 구조

    diagram

    그림에 나온 네 가지 지표(실행 횟수 · 차단 수 · 실패 단계 · 통과율)가 각각 Before/After 비교에 어떻게 쓰이는지 구체적 예시로 풀어보겠습니다.

    ① 실행 횟수 — "얼마나 자주 쓰이는 자동화인가"

    Before: 일정 동기화를 손으로 할 때는 주 2~3회 정도 겨우 했습니다. 귀찮고 시간 드니까요. 이때의 "실행 횟수"는 사람 기억에 의존해야 하고, 기록도 없습니다.

    After: 감사 로그에 파이프라인 실행 이벤트가 남으니 jq '.pipeline' audit.jsonl | sort | uniq -c 한 줄로 지난 한 달 수치가 바로 나옵니다.

      147 calendar_sync
       42 photo-enhance
        8 vlm-analysis
    

    해석: 일정 동기화가 하루 평균 5회 — 즉 기존 주 2회에서 일 5회로 15배 증가했다는 결론이 숫자로 나옵니다. "자동화했더니 귀찮은 게 없어져서 더 자주 쓴다"는 체감이 실제 수치로 확인되는 순간이죠.

    ② 차단 수 — "HITL 정책이 얼마나 사고를 막아줬나"

    Before: Deny 정책이 없으니 사고가 나면 사후에 복구해야 합니다. 복구 비용은 측정돼도, 예방된 사고는 측정 불가능했죠.

    After: 감사 로그에서 tags: ["blocked"]인 이벤트를 집계합니다.

    jq 'select(.tags[]=="blocked")' audit.jsonl | wc -l
    # 결과: 7
    

    해석: 지난 달 7번의 위험 명령이 차단됐다는 뜻입니다. 차단된 명령 내용을 함께 확인하면 더 생생합니다.

    jq -r 'select(.tags[]=="blocked") | .cmd' audit.jsonl
    # git reset --hard HEAD~3
    # rm -rf ~/.cache/models
    # git push --force origin main
    # ...
    

    이 중 한두 건이라도 실제 실행됐다면 복구에 몇 시간 걸렸을 일입니다. 즉 차단 수는 "예방된 사고의 대리 지표"가 됩니다.

    ③ 실패 단계 — "파이프라인 어디서 자꾸 막히는가"

    Before: 작업이 중간에 끊겼을 때 "몇 단계에서 주로 멈추는가"는 아예 측정 대상이 아니었습니다. 다시 수동으로 돌릴 뿐이었죠.

    After: 상태 파일(/tmp/.calendar_pipeline_state 등)에 각 단계의 완료 여부가 남습니다. Stop 훅이 실행될 때 미완료 상태를 로그에 찍어두면, 한 달 치를 집계할 수 있습니다.

    단계             완료 횟수    미완료 횟수
    step1_sync        147          0
    step2_voice       145          2
    step3_organizer   140          7     ← 여기!
    step5_git         139          8
    step6_notify      139          8
    

    해석: step3(내용 정리)에서 자꾸 끊긴다는 사실이 숫자로 드러납니다. 이 단계가 병목이니, #3 Skill 정의 편으로 돌아가 이 Skill의 워크플로우를 재설계할 근거가 됩니다. "그냥 자꾸 안 되네"가 아니라 "step3 실패율 5%"가 개선 타깃이 됩니다.

    ④ 통과율 — "품질 게이트가 실제로 잘 작동하는가"

    Before: 커밋을 푸시할 때 테스트를 돌렸는지, 린트는 봤는지 전부 기억에 의존했습니다. "대충 되는 것 같아서 올렸다"가 흔했죠.

    After: #4 Hookpytest 결과를 감지해 상태 파일에 test_ran, test_passed를 기록합니다. 이걸 집계하면 통과율이 나옵니다.

    commit 시도       120회
      test_ran=true    118회    (98%)
      test_passed=true 112회    (93%)
      → 6회는 테스트 실패로 commit 차단됨
    

    해석: TDD 규칙이 실제로 지켜지고 있다는 것이 숫자로 확인됩니다. 동시에 6건은 테스트 실패로 Hook이 잘 작동해 차단해준 것. Before 시절엔 이 6건이 그대로 푸시되어 CI에서 깨졌을 가능성이 있습니다. 통과율은 "내가 얼마나 규율 있게 일하는가"를 객관화한 지표이기도 합니다.

    네 지표를 한 줄로 읽는 법

    위 예시를 조합하면 한 달 치 회고를 이렇게 요약할 수 있습니다.

    "이번 달 자동화 파이프라인은 총 197회 실행(실행 횟수). 위험 명령 7건이 HITL로 차단(차단 수). 일정 동기화 step3에서 7번 끊겼으니 해당 Skill을 손볼 것(실패 단계). 커밋 시 테스트 통과율 93%로 규율은 잘 유지됨(통과율)."

    이 한 문단이 "Before/After 비교"의 실제 모습입니다. 감사 로그와 상태 파일이 없었다면 이 중 어느 것도 숫자로 말할 수 없었겠지만, 있으니 회고가 감이 아니라 근거 있는 개선 계획으로 바뀝니다.

    회고 루프 — 측정값을 정책으로 환원하기

    측정만 하고 끝나면 의미가 없습니다. 지표가 다음 주기의 정책 조정으로 이어져야 합니다.

    • Ask가 잦다면 → 해당 패턴을 Allow로 승격 검토 (#6 HITL)
    • 특정 단계 실패율이 높다면 → 해당 Skill의 워크플로우 재설계 (#3)
    • 차단 이력이 0건이라면 → Deny 패턴이 과하게 넓은지 점검 (#6)
    • 한 파이프라인이 거의 안 돈다면 → 트리거가 잘못됐는지, Skill description이 모호한지 재검토 (#5, #3)

    자주 빠지는 실수

    • 측정 지표는 많을수록 좋다는 착각: 지표가 10개를 넘으면 보지 않게 됩니다. 핵심 3~5개만 대시보드에 띄우세요.
    • Before 측정을 건너뜀: 자동화 전에 걸리던 시간을 안 재두면 비교할 기준이 없어집니다. "30분" 같이 대략이라도 기록.
    • 회고 없이 측정만: 측정값을 보고 나서 정책을 바꾸지 않으면 측정 자체가 의미를 잃습니다.

    시리즈를 마무리하며

    9단계 시리즈를 요약하면 다음 표 한 장에 담깁니다.

    Step 핵심 한 줄
    #0 프로세스 매핑 수동 구간을 "동사"로 표시하면 자동화 후보가 보인다
    #1 프로젝트 규칙 계층형 CLAUDE.md — 전역 상속 + Constraint 명시
    #2 Code Wiki 아키텍처 + 도메인 용어 + ADR로 "안 읽히는 것"만 문서화
    #3 Skill 정의 트리거 + 번호 붙인 워크플로우 + 환경변수를 한 파일에
    #4 검증(Hook) Dispatcher 패턴 · 10초 타임아웃 · exit(2)로 차단
    #5 자동 트리거 cron·GitHub·메시지 + 기계적 완료 조건
    #6 HITL 정책 위험도 = 비가역성 × 영향 범위 + 이중 방어
    #7 감사 로그 JSONL + 자동 태깅 · 실패해도 작업 안 막음
    #8 측정 + 회고 상태 추적 + 세션 격리 + 감사 로그 기반 정량 측정

    한 줄 요약: "측정되지 않는 자동화는 개선되지 않는다. 9단계의 마지막은 계기판이다."


    이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.

Designed by Tistory.