흩어진 프론트엔드 컨벤션을 정리하고, ESLint와 AI로 실행 가능하게 만들기까지
들어가며
AI의 성능이 향상된만큼, 다양한 분야에서 그 활용 사례를 만날 수 있게 되었습니다. 모비두에서도 코드를 작성하고, 테스트를 만들고, 오류를 분석하거나 코드 리뷰를 보조하는 등 다양한 분야에서 AI를 사용하고 있습니다.
그러던 어느 날, 반복되는 일상 속에서 문득 불편함을 느끼게 된 부분이 있습니다.
왜 코드 리뷰에서 같은 컨벤션을 계속 설명하고 있을까?
여러 개발자가 함께 작업하면서 구현 방식은 조금씩 달라졌고, 팀의 기준은 최신화되지 않은 문서와 기존 코드, 과거의 리뷰, 개발자들의 기억 속에 흩어져 있었습니다. 그 결과 컨벤션을 알고 있는 것과 실제 개발 과정에서 일관되게 적용하는 것 사이에 간극이 생겼습니다.
이 글은 단순히 AI로 코드 리뷰를 자동화한 이야기가 아닙니다.
문서와 기존 코드, 과거 리뷰, 개발자의 기억 속에 흩어져 있던 프론트엔드 컨벤션을 다시 정리하고, 각 규칙을 ESLint가 검사할지, AI가 판단할지, 사람이 결정할지 나누어 실제 개발 과정에서 동작하게 만든 이야기입니다.
시작은 반복되는 코드 리뷰였다
언젠가부터 코드 리뷰에서 비슷한 말을 반복하고 있었습니다.
이 타입은 Form 타입과 분리해주세요.
렌더링에는watch대신useWatch를 사용해주세요.
이 API 호출은 도메인 훅으로 옮겨주세요.
이 폴더명은 팀에서 사용하는 방식과 다릅니다.
여러 개발자가 하나의 프로젝트를 함께 만들면 구현 방식이 조금씩 달라지는 것은 자연스럽습니다. 각자 경험한 프로젝트와 익숙한 설계 방식이 다르기 때문입니다. 문제는 이런 차이를 팀의 기준으로 맞추는 과정이 대부분 코드 리뷰에 남아 있었다는 점이었습니다.
컨벤션 문서가 아예 없었던 것은 아닙니다. 다만 일부 내용은 최신화되지 않았고, 실제로 사용하는 기준은 문서뿐 아니라 기존 코드와 과거 리뷰, 개발자들의 기억 속에 흩어져 있었습니다. 어떤 규칙은 코드에만 적용되어 있었고, 어떤 규칙은 반복되는 리뷰를 통해서만 공유됐습니다. 일부 개발자에게는 당연한 기준이 다른 개발자에게는 처음 듣는 규칙이기도 했습니다.
결국 개발자는 작업할 때마다 기존 코드를 살펴보며 현재 기준을 추측해야 했고, 서로 다른 구현은 리뷰 단계에서 뒤늦게 조정됐습니다. 리뷰어 역시 모든 규칙을 기억하고 매번 빠짐없이 확인하기는 어려웠습니다. 이 문제를 “문서를 더 잘 읽자”거나 “리뷰를 더 꼼꼼히 하자”는 방식으로 해결하고 싶지는 않았습니다.
사람의 기억과 집중력을 시스템의 필수 조건으로 두는 대신, 규칙이 필요한 순간에 먼저 작동하는 장치를 만들기로 했습니다.
파편화된 기준 모으기
자동화에 앞서 해야 할 일이 있었습니다. 먼저 무엇을 검사해야 하는지, 기준을 정리해야 했습니다. 기존 문서와 실제 코드, 반복적으로 작성됐던 리뷰 내용을 확인하면서 현재 팀에서 사용하는 기준을 모았습니다. 네이밍, TypeScript, Form, API, React Query, 번역, 폴더 구조처럼 여러 영역에 흩어진 기준을 정리했고, 1차로 17개의 검사 규칙을 만들었습니다.
여기서 말하는 17개는 기존 문서에 완성된 형태로 존재하던 규칙의 수가 아닙니다. 파편화되어 있던 기준을 수집하고, 정상 사례와 위반 사례를 정의한 뒤 검사 가능한 형태로 정리한 첫 번째 결과였습니다.
다음 문제는 이 규칙을 다시 사람의 기억에 맡기지 않는 것이었습니다.
정리한 컨벤션을 실제 개발 과정에서 동작하게 만들 수 없을까?
처음에는 방법도 단순하다고 생각했습니다.
17개의 규칙을 모두 AI에게 검사시키면 되지 않을까?
Claude가 규칙을 읽고 변경된 파일에서 위반을 찾도록 만들었습니다. 수정할 수 있는 항목은 수정안까지 제시하거나 직접 고치도록 했습니다. 처음 몇 번은 꽤 그럴듯했습니다. 하지만 같은 코드를 반복해서 검사해보자, 모든 규칙을 AI에게 맡기는 방식의 문제가 하나씩 드러나기 시작했습니다.
직접 운영하며 발견한 세 가지 문제
1. 모든 규칙을 AI에게 맡길 필요는 없었다
AI는 주변 코드를 읽고 맥락을 판단하는 데 강했습니다. 반면 같은 코드에서도 위반을 묶는 단위나 자동 수정 가능 여부가 실행마다 조금씩 달라졌습니다. 무엇보다 any 사용이나 금지된 import처럼 답이 정해진 문제까지 AI가 읽고 판단하고 있었습니다. AI가 검사할 수 있다는 이유만으로 모든 검사를 AI에게 맡길 필요는 없었습니다.
따라서 아래와 같이 규칙을 재분류했습니다.
담당 | 적합한 규칙 |
|---|---|
ESLint | 코드 구조만으로 결과가 확정되는 규칙 |
AI | 호출처, 타입의 역할, 렌더링 위치 등 맥락이 필요한 규칙 |
사람 | 여러 파일에 영향을 주거나 도메인 판단이 필요한 수정 |
예를 들어 watch() 사용 금지는 ESLint가 판별할 수 있습니다. 반면 직접 작성된queryKey가 팀의 팩토리 패턴을 위반했는지는 주변 파일까지 확인해야 하므로 AI가 더 적합했습니다.
답이 정해진 문제는 ESLint로, 문맥을 읽어야 하는 문제는 AI로 검사 주체를 구분했습니다.
2. 검사를 많이 실행한다고 더 좋은 자동화는 아니었다
처음에는 위해 AI가 ESLint 담당 규칙을 매번 재확인했습니다. 하지만 이는 동일한 규칙을 중복 탐색하는 반복적인 실행이였습니다. 따라서 소요 시간과 토큰 소모량을 더 개선할 수 있는 방법을 찾았습니다.
ESLint 를 AI 검사 전 실행하는 것에서 답을 얻을 수 있었습니다.
ESLint 오류가 있으면 AI는 시작하지 않습니다. 기계가 확실하게 처리할 수 있는 문제를 해결한 뒤에만 AI가 동작하도록 프로세스를 개선했습니다. 이로써 기존 대비 2분가량의 시간을 단축 시킬 수 있었습니다.
또한, AI 검사를 매 저장이나 커밋마다 실행하는 대신, 방식도 사용하지 않았습니다.명확한 검사는 커밋과 CI에서 자동으로 차단하고, AI 검토는 PR 전에 한 번 호출하도록 검토 과정을 변경했습니다.
AI가 만든 결과는 결국 사람이 읽고 판단해야 합니다. 너무 자주 실행하면 검토 피로가 쌓이고, 어느 순간 결과를 읽지 않은 채 승인할 가능성이 증가한다고 믿기 때문이었습니다.
3. 규칙이 늘어나면 동작이 무거워졌다
초기에 만들었던 컨벤션 스킬은 잘 동작했지만, 모든 절차가 하나의 SKILL.md에 들어 있었습니다. 변경 파일 수집, ESLint 실행, AI 검사, 결과 출력, 사용자 선택, 수정 절차까지 한 파일에서 처리했습니다. 파일은 156줄까지 늘어났고, 한 단계만 수정하려 해도 전체 흐름을 다시 확인해야 했습니다. AI가 읽은 변경 파일도 메인 대화 컨텍스트에 그대로 남았습니다. 큰 PR에서는 파일을 읽고 검사하는 데 4~5분이 걸리는 경우도 있었습니다.
구조를 점검하는 과정에서 더 근본적인 문제도 발견했습니다.
우리가 정리한 규칙은 잘 찾고 있는데, 실제 팀의 기준이 모두 검사 대상에 들어 있기는 할까?
컨벤션을 다시 전수 점검한 결과, 실제로 사용하고 있지만 ESLint와 AI 어디에서도 검사하지 않는 규칙이 있었습니다. 정해진 시험 문제는 잘 풀고 있었지만, 시험 범위 전체가 문제로 만들어진 것은 아니었습니다.
ESLint는 검사하고, Agent는 판단하고, 사람은 결정한다
따라서 실행 구조와 규칙 체계를 함께 정리한 2차 개선을 진행했습니다.
먼저 SKILL.md에는 전체 흐름만 남겼습니다. 세부 절차와 규칙은 별도 파일로 분리했고, 156줄이던 파일은 72줄로 줄었습니다. 파일을 가장 많이 읽는 의미 추론 단계는 convention-inferrer라는 별도 Agent로 분리했습니다.
Agent에는 변경된 파일 목록과 컨벤션 규칙을 전달했습니다. Agent는 변경 파일에서 검사를 시작하고, 판단에 필요한 경우에만 관련 타입이나 훅, 컴포넌트의 정의를 추가로 확인합니다. 지시는 다음처럼 단순하게 구성했습니다.
변경된 코드를 컨벤션 규칙에 따라 검사한다. 필요한 경우 연관 파일을 확인한다. 위반 위치와 판단 근거를 정리해 반환하되, 코드는 직접 수정하지 않는다.
검사 과정에서 읽은 코드 본문은 Agent의 컨텍스트에만 남기고, 메인에는 위반 결과만 반환하도록 했습니다.
이 모든 것을 반영한 뒤, 검사 주체별 역할은 다음과 같이 정리되었습니다.
ESLint는 검사하고, Agent는 판단하고, 사람은 결정한다.
Agent의 목표도 모든 지적을 확신하는 것이 아니라, 의심되는 항목을 빠뜨리지 않고 보여주는 것으로 설정했습니다. 자동으로 안전하게 수정할 수 있는 항목과, 사람의 판단이 필요한 항목을 구분해 리포트하되 최종 적용 여부는 개발자가 선택합니다.
56개의 새로운 규칙
컨벤션과 실제 코드를 다시 전수 점검한 결과, 검사 체계는 다음과 같이 확장됐습니다.
ESLint 검사 규칙: 22개
AI 의미 추론 규칙: 34개
정리된 컨벤션 중 검사 방식이 연결되지 않은 규칙: 0개
규칙 수가 늘었다고 모든 일을 AI에게 넘긴 것은 아닙니다.
완전히 정형화할 수 있는 규칙은 기계로 보내고, 문맥을 읽어야 하는 규칙만 AI에 남겼습니다.
AI 자동화를 확장하면서 오히려 AI가 필요 없는 영역을 더 많이 찾게 됐습니다.
테스트와 함께하는 점진적 적용
자동화가 동작한다는 이유만으로 곧바로 운영에 적용할 수는 없었습니다. 정상 코드를 위반으로 판단하지 않는지, 반복 실행에서도 비슷한 품질을 유지하는지 검증이 필요했습니다.
AI 검증을 위해, 서비스 코드와 분리된 fixture에 9개의 규칙 위반 사항을 적용하고, , Opus와 Sonnet 모델을 사용하여 세 차례씩 검증을 실행했습니다. 매 회차가 같은 조건에서 시작되도록 검사 후 fixture를 원래 상태로 복원했습니다.
항목 | Opus | Sonnet |
|---|---|---|
규칙 종류 검출 | 9/9 | 9/9 |
false positive | 0건 | 0건 |
평균 검출 시간 | 109초 | 140초 |
평균 비용 | 약 $0.99 | 약 $0.64 |
두 모델의 검출 품질은 같았고 Sonnet의 비용이 약 35% 낮았습니다. 이에 따라 의미 추론 Agent는 Sonnet으로 고정했습니다. 다만 안전하게 자동 수정할 수 있는지에 대한 판단은 일부 경계 사례에서 달랐습니다. 따라서 AI는 위반 후보와 수정안을 제시하고, 최종 적용 여부는 사람이 결정하도록 했습니다.
ESLint 커스텀 규칙은 RuleTester로 검증했습니다. 최종적으로 21개 테스트 스위트와 149개 테스트를 통과했으며,22개의 규칙을 의도적으로 위반한 통합 fixture에서도 위반된 규칙을 모두 검출했습니다. 불필요한 추가 오류는 없었습니다.
새 규칙을 적용한 뒤에는 기존 코드에서도 적지 않은 위반이 확인됐습니다.
Form 타입 관련 약 296건, 50개 파일
watch()사용 153건상수 네이밍 12건 등
이를 한 번에 수정하면 기능 개발과 QA 범위에 영향을 줄 수 있었습니다. 따라서 신규·변경 코드에는 즉시 규칙을 적용하고, 기존 코드는 해당 파일을 수정할 때 함께 개선하는 점진적 마이그레이션을 선택했습니다.
완벽한 과거를 한 번에 만드는 것보다, 앞으로의 코드가 더 이상 악화되지 않도록 하는 일을 먼저 시작했습니다.
최종 구조
현재 컨벤션 검사는 세 단계로 동작합니다.
실행 위치도 역할에 따라 나눴습니다.
시점 | 역할 |
|---|---|
코드 작성 중 | IDE ESLint 피드백 |
커밋 전 | Prettier, ESLint, TypeScript 검사 |
PR 전 |
|
CI | 신규·변경 코드에 ESLint 규칙 강제 |
마치며
이번 작업을 통해 흩어져 있던 팀의 기준을 56개의 검사 규칙으로 정리하고, 실제 개발 과정에서 반복적으로 동작하는 체계로 연결했습니다.
현재는 규칙의 성격에 따라 역할이 나뉩니다.
답이 명확한 규칙은 ESLint가 자동으로 확인합니다.
문맥이 필요한 규칙은 AI가 PR 전에 살펴봅니다.
영향 범위가 큰 수정과 최종 판단은 사람이 맡습니다.
AI는 문서만으로는 발견하기 어려운 코드의 맥락과 주변 구조를 함께 살펴볼 수 있었습니다. 덕분에 정적 분석만으로 확인하기 어려웠던 컨벤션까지 개발자가 PR을 올리기 전에 점검할 수 있게 됐습니다.
이번 작업에서 중요했던 것은 AI를 얼마나 많이 사용하는지가 아니라, AI의 강점을 기존 개발 도구와 어떻게 연결할 것인가였습니다. ESLint의 일관성, AI의 맥락 판단, 개발자의 최종 결정을 하나의 흐름으로 연결하면서 컨벤션은 더 이상 문서와 사람의 기억에만 머물지 않게 됐습니다.
이번 과정은 새로운 도구 하나를 추가하는 데서 끝나지 않았습니다.
각 도구가 가장 잘하는 일을 나누고, 그 결과가 실제 개발 과정에서 자연스럽게 이어지도록 만드는 것.
이것이 이번 컨벤션 자동화를 통해 얻은 가장 큰 결과였습니다.