9.4.4 자동 포매팅(Black, Prettier) 적용 후 변경률 기반의 이상 징후 탐지
앞서 9.4.1장 부근에서 언급했듯, 코딩 컨벤션의 미학적 디테일(들여쓰기, 따옴표 위치, 줄바꿈 등)을 LLM에게 프롬프트로 가르쳐서 교정하려는 것은 비효율의 극치다. 현대의 파이프라인은 이 역할을 Black(Python)이나 Prettier(JavaScript/TypeScript)와 같은 무자비한(Opinionated) ’자동 포매터(Auto-Formatter)’에게 전적으로 위임한다.
포매터는 논쟁을 허용하지 않는다. 자신이 가진 AST 파싱 룰에 따라 코드를 완전히 분해한 뒤, 텍스트를 가장 완벽하게 정렬된 형태로 하향식(Top-down) 렌더링을 덮어씌운다. 그러나 영리한 오라클 설계자는 이 포매팅 도구를 단순히 코드의 화장(Make-up) 용도로만 쓰지 않는다. 포매터가 코드를 덮어쓰기 **전과 후의 ‘변경률(Mutation Rate)’**을 측정하면, 이 코드가 애초에 얼마나 심각한 구조적 결함을 안고 태어났는지 즉각적으로 탐지해 내는 훌륭한 이상 징후(Anomaly) 스캐너로 변모한다.
1. AST 포매팅에 붕괴되는 구조는 곧 ’나쁜 코드’다
Black이나 Prettier가 코드를 재배열할 때, 원본 코드에서 단지 여백(Spaces) 몇 개가 지워졌다면 이는 건강한 생성결과다. 하지만 만약 LLM이 뱉어낸 코드가 포매터를 거친 후 전체 코드 라인(LoC)의 60% 이상이 뒤집히거나, 블록의 형태 자체가 해체 수준으로 쪼개졌다면 어떨까?
이는 LLM이 프롬프트의 지시를 따랐다기보다는 확률적 출력에 취해 문자열을 마구잡이로 길게 이어 붙였거나(One-liner 남용), 파이썬의 중첩 스코프를 완전히 비상식적인 계단식(Staircase)으로 늘여놓았음을 반증한다.
- 포매팅 변경률이 지나치게 높다는 것은 곧, 인간 개발자의 인지적 예상 범위를 벗어난 기괴한 코드 구조(Alien Structure)를 띠고 있었다는 뜻이다.
- 이러한 코드는 포매터가 예쁘게 정렬해 주었다 하더라도, 그 로직 자체가 비정상적인 의식의 흐름(Stream of Consciousness)을 따라 생성되었을 확률이 매우 높다.
2. 편집 전후의 Git Diff 스코어 알고리즘 구현
오라클 미들웨어는 자동 포매팅 파이프라인 전후에 Git 알고리즘에서 착안한 텍스트 유사도 검사기(Levenstein Distance 또는 Diff Line Counter)를 배치하여 이 징후를 정량적으로 계산한다.
import difflib
import subprocess
def evaluate_formatting_mutation(original_code: str, file_path: str) -> float:
# 1. 포매팅 이전의 코드 보관
lines_before = original_code.splitlines()
# 2. 강제 포매팅(Black) 실행
subprocess.run(["black", file_path, "--quiet", "--fast"])
# 3. 포매팅 이후의 코드 로드
with open(file_path, "r") as f:
lines_after = f.read().splitlines()
# 4. 내장 difflib를 사용해 변경된 라인(mutation) 수 측정
diff = list(difflib.unified_diff(lines_before, lines_after))
mutated_lines = len([l for l in diff if l.startswith('+') or l.startswith('-')])
# 5. 총 라인 수 대비 변경률 계산
total_lines = max(len(lines_before), 1)
mutation_rate = (mutated_lines / total_lines) * 100
return mutation_rate
오라클은 এই 과정에서 산출된 mutation_rate에 대한 상한선(Ceiling)을 설정한다. 예를 들어 “변경률 40% 초과 시 검증 실패(Validation Fail)“라는 룰을 세운다.
3. 침묵적 실패(Silent Failure)의 방지
가장 위험한 경우는 포매터가 문법을 고쳐보려다가 도저히 해석이 안 되어 파싱 자체를 포기해 버리는(Parsing Failure) 단계다. Black이나 Prettier는 인풋 코드가 AST 구조를 완벽히 잃어버린 ‘깨진(Broken)’ 코드일 경우 텍스트를 건드리지 않고 에러코드와 함께 종료된다.
만약 오라클 파이프라인에서 “포매터 실행 완료 여부“를 단순히 패스(Pass) 해버린다면, 이 엉망인 코드는 다음 파이프라인으로 흘러 들어가 묵시적 실패(Silent Failure)를 유발하게 된다. 따라서 포매터의 Exit Code가 0이 아닐 경우, 오라클은 이를 **‘포맷 불가능한 문법(Unformattable Syntax)’**이라는 치명적 구조 오류로 간주하고, 즉시 파이프라인을 정지(Halt)시킨 뒤 LLM에게 문법 재조정 프롬프트를 보내야 한다.
포매터는 단순히 코드를 예쁘게 다듬는 브러쉬가 아니라, 코드가 가장 근본적인 ’구조의 상식’을 지키고 있는가를 가시적으로 증명해 내는 거대한 리트머스 시험지(Litmus Paper)임을 명심하라.