Architecture Drift Score: 당신의 문서는 진실을 말하고 있습니까? - Archyl Blog

Architecture Drift Score는 문서화된 아키텍처 중 얼마나 많은 부분이 코드베이스에 아직 존재하는지를 나타내는 0에서 100까지의 수치입니다. 이 글은 그 메커니즘입니다. 수식, 분모에 들어가는 것, 의도적으로 제외되는 것, 이 검사가 볼 수 없는 것, 그리고 CI에서 강제하는 방법.

Architecture Drift Score: 당신의 문서는 진실을 말하고 있습니까?

아무도 감사할 수 없는 지표는 아무도 근거로 삼아서는 안 되는 지표입니다. 그래서 이 글은 그 산술 자체입니다. Architecture Drift Score가 어떻게 만들어지는지, 무엇이 분모에 들어가는지, 무엇을 의도적으로 빼는지, 그리고 이 검사가 볼 수 없는 네 가지.

이 점수는 하나의 질문에 답합니다. 문서화된 아키텍처 중 코드베이스에 아직 존재하는 비율은 얼마입니까? 0에서 100까지의 수치이며, Git 프로바이더에 대한 단 한 번의 요청으로 계산됩니다. 경로에 AI는 없고, 파일 내용도 읽지 않습니다.

산술이 아니라 문제 자체가 궁금하다면, 아키텍처 드리프트 가이드가 드리프트란 무엇인지, 왜 발생하는지, 그리고 그것을 감지하는 다른 방법들을 다룹니다. 거기서 시작한 다음 돌아오세요. 이 페이지는 당신이 이미 수치를 원하고 있으며, 그것을 믿어도 되는지 알고 싶어 한다고 가정합니다.

수치 읽기

Archyl에서 아무 프로젝트나 열고, 헤더의 하트비트 아이콘을 클릭한 다음, "Compute Drift Score"를 누르세요. 몇 초 안에 수치가 나옵니다:

  • 90-100% — 우수. 문서가 코드베이스와 정확하게 일치합니다.
  • 70-89% — 양호. 대체로 정확하며, 일부 격차가 있습니다.
  • 50-69% — 보통. 상당한 드리프트가 감지되었습니다. 업데이트할 시간입니다.
  • 50% 미만 — 당신의 문서는 허구입니다.

이 구간들은 무엇이 조치할 가치가 있는지에 대한 우리의 판단이지, 무언가를 측정한 결과가 아닙니다. 그 아래에 있는 수치는 정확합니다.

수치가 계산되는 방식

모델의 모든 요소는 버킷으로 분류되고, 점수는 살아남은 비율입니다:

score = floor( (matched + 0.5 × partial) / total × 100 )

total = matched + partial + missing_in_code + new_in_code
  • matched — 모델은 존재한다고 말하고, 리포지토리도 동의합니다.
  • missing_in_code — 문서화되었지만 찾을 수 없습니다. 디렉토리가 사라진 Container, 파일이 삭제된 코드 요소.
  • new_in_code — 리포지토리에는 있지만 모델에는 없습니다. 문서화되지 않았다는 뜻이며, 이는 반대 방향의 드리프트이고 정확히 같은 무게로 당신에게 불리하게 작용합니다.

partial은 절반의 크레딧을 가지며, 차이를 동반한 채 일치하는 요소를 위해 예약되어 있습니다. 현재의 검사는 이를 만들어내지 않습니다. 모든 요소가 나머지 세 가지 중 하나로 분류되므로, 실제로 점수는 matched의 비율입니다. 한 번도 작동하지 않는 항이 들어 있는 수식은 당신이 스스로 발견할 것이 아니라 우리에게서 들어야 할 종류의 것이기에 알려드립니다.

두 번의 실행을 비교할 때 중요한 세부 사항이 두 가지 있습니다. 결과는 반올림이 아니라 절사되므로 89.9는 89로 보고됩니다. 그리고 문서화되지 않은 요소는 분모를 키웁니다. 새 서비스 세 개를 문서화하지 않고 추가하면, 이미 써 둔 내용 중 거짓이 된 것은 하나도 없는데도 점수가 떨어지는 이유가 이것입니다.

실제로 무엇을 검사하는가

드리프트 분석은 설계상 경량입니다 — Git 프로바이더에 대한 단 한 번의 재귀적 트리 요청만으로, AI 없이, 파일 내용 가져오기 없이 수행됩니다. 다섯 가지 차원에서 아키텍처를 검증합니다:

Systems — 리포지토리 이름이 문서화된 시스템과 일치합니까? AI 디스커버리 파이프라인과 동일한 PascalCase 명명 규칙을 사용하며, 퍼지 매칭을 통해 EkoAuthzauthz라는 이름의 리포지토리와 일치합니다.

Containers — 리포지토리의 최상위 디렉토리가 문서화된 Container에 해당합니까? frontend/FrontendWebApp과 일치합니다. backend/BackendApiServer와 일치합니다. 소스 디렉토리가 없는 인프라 Container(데이터베이스, 큐, 모니터링)는 제외됩니다. 드리프트가 아니라 외부 서비스에 대한 유효한 문서이기 때문입니다. 이 제외가 무엇을 대가로 치르는지는 다음 섹션에서 다룹니다.

Components — 각 Container 하위의 컴포넌트는 여전히 유효합니까? 상위 Container의 디렉토리가 존재하면 해당 컴포넌트는 유효한 것으로 간주됩니다. Container 디렉토리가 사라졌다면 모든 컴포넌트에 플래그가 지정됩니다.

Code Elements — 이것이 가장 정밀한 검사입니다. C4 model의 모든 코드 요소에는 filePath가 있습니다. 각 파일이 여전히 리포지토리에 존재하는지 확인합니다. 파일이 이름 변경되었나요? 클래스가 삭제되었나요? 모듈이 이동되었나요? Drift Score가 즉시 감지합니다.

Relationships — 관계는 소스와 타겟 요소 모두가 검증을 통과한 경우에 유효합니다. 어느 한쪽 엔드포인트가 드리프트한 경우 해당 관계에 플래그가 지정됩니다.

결과는 요소별 분류로, 무엇이 일치하고, 무엇이 누락되었으며, 무엇이 새로운지를 정확히 보여줍니다 -- 불투명한 점수가 아닌, 조치 가능한 보고서입니다.

분모에서 제외되는 것

점수는 그것이 세기를 거부하는 것들만큼만 정직합니다. 세 가지 제외이며, 모두 의도적입니다:

외부 시스템과 사람. 외부 시스템이나 사람으로 타입이 지정된 것은 비교 전에 양쪽 모두에서 제거됩니다. Stripe, 당신의 아이덴티티 프로바이더, 그리고 "고객"은 System Context 다이어그램에 속하며, 그중 어느 것도 당신의 리포지토리에 나타나는 일은 없습니다. 이들을 누락으로 세는 것은 올바른 다이어그램을 그린 데 대한 벌이 될 것입니다.

소스 디렉토리가 없는 인프라 Container. 어떤 디렉토리와도 일치하지 않는 문서화된 Container는 드리프트로 계산되는 대신 Container 집계에서 제거됩니다. 당신의 PostgreSQL 인스턴스, Kafka 클러스터, Datadog 계정은 모두 정당한 Container이며, 그중 어느 것도 폴더가 아닙니다.

이 규칙에는 대가가 있고, 당신은 그것을 알아야 합니다. 당신이 삭제한 실제 서비스 디렉토리 역시 Container 집계에서 제외됩니다. 검사는 "데이터베이스"와 "지난 스프린트에 제거한 서비스"를 구분할 수 없기 때문입니다. 그 컴포넌트들은 제외되지 않습니다. 상위 Container가 일치하지 않았기 때문에 여전히 누락으로 해석됩니다. 그래서 제거된 서비스는 점수에 분명히 나타납니다 -- 다만 당신이 찾을 것이라 예상하는 곳보다 한 단계 아래에서.

기록된 파일 경로가 없는 코드 요소. 모델의 코드 요소에 filePath가 없으면 검증할 것이 없으므로, 추측하는 대신 건너뜁니다. 당신에게 유리하게도, 불리하게도 계산되지 않습니다. 생성된 경로와 벤더 경로(vendor/, node_modules/, dist/, target/, __pycache__/ 및 나머지 익숙한 목록)는 이 모든 과정이 실행되기 전에 파일 트리에서 걸러집니다.

경량성이 중요한 이유

드리프트 감지를 위해 전체 AI 디스커버리 파이프라인을 실행하지 않기로 의도적으로 결정했습니다. 그 이유는 다음과 같습니다:

속도. AI 분석은 대규모 리포지토리에서 수 분이 걸립니다. 드리프트 스코어링은 수 초입니다. 파이프라인을 늦추지 않고 모든 push에서 실행할 수 있습니다.

결정론. AI는 모델 온도, 프롬프트 변형, 토큰 제한에 따라 동일한 코드베이스에서 다른 결과를 생성할 수 있습니다. 파일 경로의 존재는 이진적입니다 -- 파일이 있거나 없거나입니다. 점수는 재현 가능합니다.

비용. AI 토큰 소비 없음. API 속도 제한 도달 없음. 원한다면 하루에 100번 실행하세요.

단순성. 알고리즘은 감사 가능합니다. 파일 경로 확인, 디렉토리 이름 매칭, 관계 검증. 블랙박스가 없습니다.

점수가 볼 수 없는 것

이 속성들은 하나같이 같은 거래로 얻어진 것입니다. 이 검사는 구조를 읽지, 코드를 읽지 않습니다. 네 가지 결과가 따라오며, 그중 어느 것도 우리가 숨길 생각인 버그가 아닙니다.

동작의 드리프트는 보이지 않습니다. 두 서비스가 이름과 디렉토리를 유지한 채, 둘 사이의 동기 HTTP 호출이 큐 메시지로 바뀌어도 점수는 움직이지 않습니다. 구조적으로는 아무것도 변하지 않았기 때문입니다. 이것이 가장 큰 사각지대이고, 값싼 해결책은 없습니다. 이를 잡으려면 코드를 읽거나 사람과 함께 모델을 검토해야 합니다.

이동은 삭제와 완전히 똑같아 보입니다. 코드 요소는 대소문자를 구분하는 정확한 파일 경로로 검증됩니다. internal/auth/token.go를 한 줄도 건드리지 않고 internal/identity/token.go로 옮기면 그 요소는 누락으로 보고됩니다. 문서화된 경로가 틀렸으니 기술적으로는 맞는 보고이며, 이는 디렉토리 이름을 바꾸는 리팩토링이 겁이 날 만한 모양새로 점수를 떨어뜨리지만 실제로는 요소당 한 줄 수정으로 해결된다는 뜻이기도 합니다.

컴포넌트 정확도는 상속되는 것이지 검증되는 것이 아닙니다. Container의 디렉토리가 존재하면 그 아래의 모든 컴포넌트는 유효한 것으로 간주됩니다. 검사는 절대 그 안을 들여다보지 않습니다. 그래서 여전히 존재하지만 속을 들어내고 다시 쓴 Container는 컴포넌트 수준에서 깨끗하다고 평가되며, 그 수치는 당신의 레벨 3 다이어그램에 대해 근거가 뒷받침하는 것보다 더 확신하고 있는 셈입니다.

이름 매칭은 관대합니다. Systems와 Containers는 세 번의 패스로 이름을 매칭합니다. 대소문자를 무시한 정확 일치, 그다음 양방향 부분 문자열 포함, 그다음 PascalCase와 kebab-case를 분리한 뒤의 토큰 겹침입니다. EkoAuthzauthz라는 리포지토리와 일치하고, BackendApiServerbackend라는 디렉토리와 일치합니다. 이것이 사소한 이름 차이가 드리프트로 보고되는 것을 막아 주며, 당신의 모델에 유리한 쪽으로 오차를 냅니다. 엄격한 판독을 원한다면 대표 수치 대신 요소별 분류를 사용하세요.

종합하면, 이 점수는 당신의 모델이 여전히 같은 시스템을 설명하고 있는지에 대해서는 좋은 척도이고, 그것을 올바르게 설명하고 있는지에 대해서는 약한 척도입니다. 높은 점수는 "구조적 놀라움은 없다"로 받아들여야지 "문서가 옳다"로 받아들이면 안 됩니다.

스냅샷이 아닌 트렌드를 추적하세요

단일 점수는 유용합니다. 트렌드는 강력합니다.

모든 드리프트 계산은 전체 분류와 함께 저장됩니다. Overview 탭은 시간에 따른 점수의 막대 차트를 보여줍니다. 아무 막대나 클릭하면 해당 이력 보고서를 로드하고 정확히 무엇이 변경되었는지 확인할 수 있습니다.

이를 통해 드리프트 스코어링은 일회성 감사에서 지속적인 건강 메트릭으로 변환됩니다. 다음을 확인할 수 있습니다:

  • 지난주 리팩토링이 문서 정확도를 개선했는가, 악화시켰는가?
  • 드리프트가 시간이 지남에 따라 악화되고 있는가, 그리고 워크플로에서 바꾼 것 중 그것을 늦춘 것이 있는가?
  • 어떤 스프린트에서 가장 많은 미문서화 변경이 도입되었는가?

CI에서 강제하세요

강제하지 않는 메트릭은 무시하게 될 메트릭입니다. 그래서 GitHub Action을 구축했습니다.

on:
  push:
    branches: [main]

jobs:
  drift:
    runs-on: ubuntu-latest
    steps:
      - uses: archyl-com/actions/drift-score@v1
        with:
          api-key: ${{ secrets.ARCHYL_API_KEY }}
          organization-id: ${{ secrets.ARCHYL_ORG_ID }}
          project-id: 'your-project-uuid'
          threshold: '70'

threshold: '70'을 설정하면 아키텍처 문서의 정확도가 70% 아래로 떨어지면 액션이 실패합니다. 작업 요약에는 전체 분류가 포함된 포맷된 테이블이 표시됩니다 -- PR 체크에서 직접 확인할 수 있습니다.

점수를 PR 코멘트로 게시할 수도 있습니다:

- uses: archyl-com/actions/drift-score@v1
  id: drift
  with:
    api-key: ${{ secrets.ARCHYL_API_KEY }}
    organization-id: ${{ secrets.ARCHYL_ORG_ID }}
    project-id: 'your-project-uuid'

- uses: actions/github-script@v7
  if: github.event_name == 'pull_request'
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '## Architecture Drift: ' +
              '${{ steps.drift.outputs.score }}%\n' +
              'Matched: ${{ steps.drift.outputs.matched-count }}' +
              ' / ${{ steps.drift.outputs.total-elements }}'
      })

모든 개발자가 머지 전에 자신의 변경 사항이 드리프트에 미치는 영향을 확인합니다. 아키텍처 문서는 테스트, 린팅, 보안 스캔과 함께 CI 파이프라인의 일급 시민이 됩니다.

MCP: 자신의 정확도를 아는 AI 에이전트

Claude Code, Cursor 또는 Archyl의 MCP 서버를 사용하는 MCP 호환 AI 에이전트를 사용하고 있다면, 드리프트 스코어링이 도구로 제공됩니다:

compute_drift_score({ projectId: "..." })
get_drift_score({ projectId: "..." })
get_drift_history({ projectId: "..." })
get_drift_details({ scoreId: "..." })

이는 AI 에이전트가 작업을 시작하기 전에 문서 정확도를 확인할 수 있다는 의미입니다. get_agent_context 도구는 이미 전체 C4 model, ADR, 준수 규칙을 제공합니다. 이제 해당 문서가 얼마나 신뢰할 수 있는지도 확인할 수 있습니다.

45%의 드리프트 점수를 보는 에이전트는 받은 아키텍처 컨텍스트에 신중해야 한다는 것을 압니다. 95%를 보는 에이전트는 문서화된 구조를 확신을 가지고 신뢰할 수 있습니다. 이것은 문서 품질에 따라 행동을 조정하는 자기 인식 AI 에이전트의 기반입니다.

Webhook 알림: 드리프트 발생 시 알림 받기

두 가지 새로운 Webhook 이벤트로 대시보드를 확인하지 않고도 정보를 받을 수 있습니다:

  • drift.score_computed — 드리프트 점수 계산이 완료될 때마다 발생합니다. 가시성을 위해 Slack 채널로 전송하세요.
  • drift.score_degraded — 이전 계산 대비 점수가 10포인트 이상 하락하면 발생합니다. 이것은 조기 경보 시스템입니다 -- 아키텍처가 빠르게 드리프트하고 있습니다.

Archyl의 Webhook 설정에서 구성하세요. Slack, Microsoft Teams, Discord, 그리고 모든 범용 HTTP 엔드포인트에서 작동합니다.

REST API

완전한 프로그래밍 제어를 원하는 팀을 위해:

# 계산 트리거
curl -X POST https://api.archyl.com/api/v1/drift/compute \
  -H "X-API-Key: $API_KEY" \
  -H "X-Organization-ID: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "your-project-uuid"}'

# 최신 점수 가져오기
curl https://api.archyl.com/api/v1/drift/latest?projectId=...

# 점수 이력 가져오기
curl https://api.archyl.com/api/v1/drift/history?projectId=...&limit=20

계산은 비동기적입니다 -- POST는 점수 ID와 함께 즉시 반환되며, statuscompleted가 될 때까지 폴링합니다. GitHub Action은 이를 자동으로 처리합니다.

이 점수는 루프의 어디에 있는가

점수는 하나의 순환 속 한 단계입니다. 에이전트와 사람이 모델을 읽고, 코드가 바뀌고, 점수가 격차를 측정하고, CI가 임계값을 지키고, 팀이 다시 맞춥니다. 측정 단계가 없으면 이 순환에는 피드백이 없고, 문서는 아무런 이의 제기 없이 드리프트합니다. 그 논거와, 애초에 드리프트를 감지해야 하는 나머지 이유는 가이드에 있습니다.

이 글이 책임지는 것은 측정 단계가 신뢰할 만하다는 점입니다. 그래서 수식이고, 제외 규칙이고, 볼 수 없는 네 가지입니다.

시작하기

  1. Archyl에서 아무 프로젝트나 엽니다
  2. 헤더 툴바의 하트비트 아이콘을 클릭합니다
  3. "Compute Drift Score"를 클릭합니다
  4. 지속적 모니터링을 위해 GitHub Action을 설정합니다
  5. drift.score_degraded 알림을 위한 Slack Webhook을 구성합니다

당신의 아키텍처 문서는 현실을 반영하거나 반영하지 않거나 둘 중 하나입니다. 이제 어느 쪽인지 알려주는 수치가 있고, 그 수치와 따져볼 수 있을 만큼의 산술도 있습니다.


이 클러스터의 나머지: 문제 자체와 다른 감지 방법은 아키텍처 드리프트 감지, 점수가 다시 미끄러지지 않게 하는 실천은 살아있는 아키텍처 문서. 정의: 아키텍처 드리프트. 제품 페이지: 드리프트 감지.