안전망을 절반만 만들고 끝냈다고 우기는 당신

솔직히 말해 보자. 지금 대부분의 AI 코드 생성 과정은 어떻게 생겼는가.

Cursor나 Claude Code로 코드를 생성한다. TypeScript 엄격 모드가 타입 불일치를 잡아주니 tsc --noEmit을 돌린다. 세미콜론 논쟁을 병합 과정에서 하고 싶지 않으니 ESLint를 돌린다. 순환 임포트가 창피하니 dependency-cruiser를 돌릴지도 모른다. 테스트가 통과한다. 배포한다.

그리고 그걸 결정론적 체계라고 생각한다.

아니다. 그건 타입-스타일 체계다. 유효하지 않은 상태를 막고 임포트 경계를 enforcement한 것은 진정으로 유용하다. 하지만 LLM이 방금 180줄짜리 함수를 생성했는데 그 순환 복잡도가 그래프 이론가를 울릴 정도라는 사실에는 아무것도 하지 않았다. 세 개의 서로 다른 module이 같은 헬퍼를 살짝 다른 변수명으로 복사했다는 것도 잡아내지 못했다. 에러 처리가 catch (e) { console.log(e) } 하나로 프라미스 체인 맨 아래에 게으른 문지기처럼 앉아 있다는 것도 눈치채지 못했다.

코드는 컴파일된다. 아키텍처는 깨끗하다. 코드는 여전히 객관적으로 형편없다.

그것이 바로 틈이다. AI가 생성한 코드는 구조적으로 유효하고 아키텍처적으로 준수하면서도 내부에서 조용히 썩어가는 바로 이런 쓰레기를 생산하는 데 특별한 재능이 있기 때문에, 이 틈은 중요하다.

사실 빠져있던 계층은 뭘까

건물이 구조 엔지니어의 검사를 통과하는 것과 건물에 사는 것이 쾌적한 것의 차이를 생각해 보자. 구조 검사는 건물이 무너지지 않는지 확인한다. 샤워 물이 싱크대로 빠지는지는 확인하지 않는다. 둘 다 중요하다. 서로 다른 업무다.

기존의 결정론적 체계는 구조 엔지니어다. 다음을 확인한다:

  • 타입: 이 값이 이 형태로 존재할 수 있는가?
  • 린트: 구문이 기본적인 위생을 지키는가?
  • 아키텍처 규칙: 임포트가 경계를 존중하는가?
  • 테스트: 정상 흐름이 충돌 없이 실행되는가?

확인하지 않는 것은 다음과 같다:

  • 복잡도: 이 함수가 너무 많은 분기를 가져 인간이 제대로 이해할 수 없는가?
  • 중복: LLM이 같은 논리를 사소한 변형만 넣어 네 군데에 생성했는가?
  • 명명: data가 의미 있는 변수명인가, 아니면 프로그래밍 버전의 어깨 으쓱임인가?
  • 에러 처리: 에러를 실제로 처리하는가, 아니면 잡아서 무시하는가?
  • 구조: 파일 구성이 이치에 맞는가, 아니면 쓰레기장인가?
  • 주석: 까다로운 부분이 설명되는가, 아니면 다음 개발자가 퇴화 의식을 치러야 하는가?
  • 크기: 이 파일이 400줄인 것이 필요해서인가, 아니면 아무도 모델에게 멈추라고 말하지 않아서인가?

이것들은 미적 취향이 아니다. 복잡도는 결함 밀도와 상관관계가 있다. 중복은 미래의 변경이 불일치하게 될 것을 보장한다. 나쁜 명명은 이후의 모든 수정에 인지 부하를 증가시킨다. 엉성한 에러 처리는 진단 흔적 없는 운영 환경 장애를 의미한다.

이 부분의 연구는 명확하다. 우리의 교차 차원 분석에서 계층화된 신뢰성 아키텍처는 각 계층이 이전 계층이 놓친 결함을 잡을 때만 작동한다고 밝혀졌다. 1계층이 타입 검사이고 2계층이 테스트인데, 코드가 유지보수 재앙인지는 아무도 확인하지 않는다면, 체계에 구멍이 있는 것이다. AI가 생성한 코드는 모델이 살기에는 악몽이지만 그럴듯해 보이는 구현을 생성하는 데 매우 능숙하기 때문에 이 구멍을 좋아한다.

무례한 이름을 가진 도구의 등장

fuck-u-code라는 도구가 있다 — 맞다, 실제로 그게 명령어다 — 이 도구는 개발 과정의 다른 어떤 것도 하지 않는 바로 그 일을 한다. 14개 언어에 걸쳐 결정론적 AST 기반 코드 품질 분석을 실행하고, 실제 문제와 상관관계가 있는 지표를 사용해 코드가 얼마나 형편없는지 정확하게 알려준다.

확인하는 것은 다음과 같다:

  • 복잡도: 순환 복잡도와 인지 복잡도 점수. 함수에 열일곱 개의 분기가 있다면 표시한다.
  • 크기: 파일과 함수의 줄 수. 타입이 올바르다고 250줄짜리 함수를 생성한 LLM을 면죄부 주지 않는다.
  • 주석: 주석 밀도와 품질. 주석이 덕목이라서가 아니라, 설명 없는 복잡한 논리는 유지보수 덫이기 때문이다.
  • 에러 처리: 에러를 잡는가, 다시 던지는가, 기록하는가, 아니면 조용히 삼키는가.
  • 명명: 변수와 함수명의 품질. data, temp, handler, process는 통과하지 못한다.
  • 중복: 파일 간 반복되는 코드 블록. LLM이 가장 좋아하는 묘기: 찾아서 바꾸기로 복사-붙여넣기.
  • 구조: 파일 구성과 module 응집도.

0에서 100까지의 전체 점수를 출력한다. 높을수록 좋다. 또한 파일별 “shit-gas 지수” — 높을수록 나쁨 — 를 출력해서 어떤 파일을 먼저 신경 써야 하는지 정확히 알 수 있다. 분석은 tree-sitter AST 구문 분석을 통해 완전히 오프라인으로 실행된다. 코드는 기계를 떠나지 않는다. 대부분의 프로젝트에서 1초도 걸리지 않는다.

그리고 이미 사용하지 않아서 화가 나야 할 부분은 이것이다: 비용이 0원이다.

도구가 철학을 구현한다

fuck-u-code를 흥미롭게 만드는 것은 무엇을 확인하는가만이 아니다. 내부적으로 어떻게 설계되었는가인데, 이 도구 자체가 속한 처리 과정의 완벽한 축소판이기 때문이다.

이 도구는 두 개의 명령어를 가진다:

fuck-u-code analyze .          # Deterministic AST analysis. Offline. Fast. Free.
fuck-u-code ai-review . -m gpt-4o   # AI review of the worst-scoring files. API call. Costs tokens.

순서를 주목하라. 기본값을 주목하라. 결정론적 분석이 항상 먼저 실행되는데, 이는 API 키가 필요 없고 돈이 들지 않으며 실행 간 변동이 없기 때문이다. AI 검토는 선택적인 두 번째 단계로, 최상위 N개의 최악 점수 파일만 본다.

이것이 바로 개발 과정이 가져야 할 정확한 아키텍처다.

모든 병합 요청을 Greptile이나 Claude Code에 보내 전체 의미론적 검토를 요청하지는 않는다. 그건 돈이 들고 시간이 걸리며 — 이전 글에서 밝혔듯 — 연속 실행에서 같은 문제를 표시할지도 안 할지도 모르는 확률론적 출력을 생산한다. 먼저 결정론적 관문을 실행한다. 구조적 재앙을 무료로, 밀리초 안에, 완벽하게 재현 가능하게 걸러낸다. 그리고 그때서야, 생존자들을 의미론적, 아키텍처적, 행위적 분석을 위해 비싼 AI 검토로 보낸다. 그것은 결정론적 도구가 할 수 없는 일이다.

fuck-u-code는 내부적으로 문자 그대로 이것을 구현한다. analyze 명령어는 1계층 품질 필터다. ai-review 명령어는 2계층 의미론적 심층 분석이다. 이 도구는 그것이 가능하게 하는 원칙의 실증이다.

경제적 논거는 거의 모욕적이다

잠시 돈 이야기를 해 보자. 여기서 현업의 현주소가 진정으로 짜증나는 지점이기 때문이다.

AI 코드 검토 플랫폼은 병합 요청당 또는 검토된 코드 줄당 과금한다. 비용이 엄청나지는 않다 — 요청당 1~2달러 정도 — 하지만 0은 아니고, 팀의 속도에 따라 증가한다. AI로 코드를 생성한다면 예전보다 속도가 높다는 뜻이고, 검토 비용도 예전보다 높다는 뜻이다.

한편, fuck-u-code는 14개 언어에 걸쳐 전체 codebase를 1초 이내에 분석하고 정확히 0원을 청구한다. 진정으로 문제가 되는 상위 20% 파일을 감지한다. CI가 소비할 수 있는 JSON이나 Markdown 보고서를 생성한다. 평균 점수가 설정한 임계값 아래로 떨어지면 빌드를 실패시킨다.

결정론적 품질 관문 없이 모든 병합 요청에 AI 검토를 실행한다면, 함수가 너무 복잡하다는 것을 발견하기 위해 API 토큰을 지불하는 셈이다. 그건 집이 더럽다고 구조 엔지니어를 고용하는 것과 같다. 엔지니어는 그 일에 자격이 있지만, 당신은 그들의 시간과 당신의 돈을 낭비하고 있다.

경제적으로 합리적인 처리 과정은 다음과 같다:

  1. AI가 코드를 생성한다
  2. 타입 검사, 린트, 아키텍처 규칙 (기존 체계)
  3. fuck-u-code analyze (빠진 품질 관문 — 0원, 1초 미만)
  4. AI 검토 (Greptile 등 — 하지만 3단계를 통과한 파일에만, 또는 3단계가 흥미로운 패턴을 감지할 때만)

이것은 이론이 아니다. 산술이다. 결정론적 관문은 결정론적 도구가 설계된 문제 유형을 잡는다. AI 검토는 의미론적 이해가 필요한 문제 유형을 잡는다. 각 도구는 자신이 잘하는 일을 한다. 아무도 구조적 위생에 토큰을 낭비하지 않는다.

MCP 통합: 작업 흐름을 위해 설계되었지, 뒤늦게 덧붙여지지 않았다

AI 보조 개발에 진심이라면 중요한 한 가지 세부 사항이 더 있다.

fuck-u-code는 MCP 서버를 함께 제공한다. Claude Code나 Cursor, 또는 다른 MCP 지원 도구를 사용한다면 에이전트에서 직접 fuck-u-code analyze를 호출할 수 있다. 에이전트는 AST 구문 분석이나 순환 복잡도를 알 필요가 없다. 도구를 호출한다. 도구가 구조화된 보고서를 반환한다. 에이전트가 그에 따라 행동한다.

이것이 중요한 이유는 고리를 닫기 때문이다. 코드를 생성한 바로 그 AI가 이제 그 코드의 품질에 대한 결정론적 피드백을 이해하고 행동할 수 있는 형식으로 받을 수 있다. 에이전트는 src/auth/login.ts의 shit-gas 지수가 100점 만점에 87점이라는 것을 보고 인간이 병합 요청을 보기 전에 refactor할 수 있다.

우리는 이전에 CI가 명세 기반 개발을 실현하는 enforcement 계층이라고 썼다. MCP 통합은 fuck-u-code가 단순한 CI 관문이 아니라는 뜻이다. 생성 과정이 실시간으로 참조할 수 있는 에이전트가 접근 가능한 품질 판정 기준이다.

실제로 적용하는 모습

마이그레이션 계획이 필요하지 않다. 5분이면 된다.

npm install -g eff-u-code
fuck-u-code analyze .              # 현재 점수 확인
fuck-u-code config init            # .fuckucoderc.json 생성

임계값을 설정하라. 최소 전체 점수를 고르고, 개별 파일의 최대 shit-gas 지수를 고른다. 커밋 전 hook에 추가하라:

# .husky/pre-commit
fuck-u-code analyze . --format json --output quality-report.json

또는 CI에 추가하라:

# .github/workflows/quality.yml
- name: Code Quality Gate
  run: |
    npm install -g eff-u-code
    fuck-u-code analyze . --format markdown -o quality.md
    # Parse the JSON and fail if overall score < threshold

가중치는 설정 가능하다. 팀이 주석보다 복잡도를 더 중시한다면 .fuckucoderc.json에서 지표 가중치를 조정하라. 테스트 파일을 제외하고 싶다면 --exclude를 사용하라. 기본값 10개 대신 최악의 상위 20개 파일을 보고 싶다면 -t 20을 사용하라.

그런 다음 구조적 재앙을 걸러낸 후, 흥미로운 파일을 AI 검토로 보내라:

fuck-u-code ai-review . -m gpt-4o -t 5   # 최악의 파일 5개만 검토

이것이 처리 과정이다. 생성. 타입 검사. 품질 관문. 생존자 AI 검토. 배포.

솔직한 결론

fuck-u-code가 codebase의 모든 문제를 해결할 거라고 가장하지는 않겠다. 경쟁 상태를 잡지 못할 것이다. 인증 논리에 미묘한 타이밍 공격이 있는지 알려주지 않을 것이다. property-based testing이나 mutation testing이나 형식 검증이나 이전 글에서 이야기한 다른 계층들을 대체하지 않을 것이다.

그것이 할 일은 현재 아무도 잡고 있지 않은 지루하고 예측 가능하며 비싼 문제들을 잡는 것이다. AI가 생성한 API 처리기가 300줄이고 에러 처리가 없다고 알려줄 것이다. 세 개의 서로 다른 서비스가 같은 검증 논리를 복사했다고 알려줄 것이다. 변수의 절반이 dataresult라서 창피해야 한다고 알려줄 것이다.

이것들은 경계 사례가 아니다. 품질 피드백 고리가 없는 빠른 코드 생성 과정의 기본 출력이다. LLM은 피로하지 않지만 부끄러움도 모른다. 좋은 코드와 나쁜 코드를 같은 자신감으로 생성할 것이고, 현재의 결정론적 체계는 품질이 아닌 유효성을 확인하도록 설계되었기 때문에 그걸 통과시킬 것이다.

유효성과 품질은 다른 것이다. 둘 다 필요하다.

fuck-u-code가 전부가 아니다. 이것이 대답하는 구체적인 질문은 이것이다: “AI가 생성한 구조적 쓰레기가 코드 검토에 도달하는 것을 막는 가장 싸고, 가장 빠르고, 가장 결정론적인 방법은 무엇인가?”

대답은: AST를 구문 분석하고, 지표를 채점하고, 빌드를 실패시키고, 모델에게 다시 시도하게 만드는 것이다.

비용은 없다. 1초도 걸리지 않는다. 그리고 당신이 몰랐던 안전 체계의 구멍을 막는다.