본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 22. 08:41

AI 에이전트에게 '이상적인 코드'를 생성하게 하기 위한 프론트엔드 규칙 설계 비망록

요약

AI 에이전트가 프론트엔드 개발 시 일관된 품질의 코드를 생성할 수 있도록 돕는 규칙 설계 가이드를 제시합니다. 하드 코딩 금지, 컴포넌트화 기준 설정, 시맨틱 스타일 적용 등 구체적인 제약 사항을 통해 개발 효율을 높이는 방법을 다룹니다.

핵심 포인트

  • AI 에이전트의 코드 품질 유지를 위한 명확한 목적 설정
  • 하드 코딩 및 any 타입 사용 금지를 통한 코드 안정성 확보
  • 컴포넌트화 및 공통화 기준 정립을 통한 유지보수성 향상
  • TailwindCSS 활용 시 시맨틱한 스타일 적용 규칙 설계

갑작스럽지만, 여러분은 프론트엔드 개발에서의 '규칙'에 대해 생각해 본 적이 있나요?

이번에 실무 중에서 규칙을 고민할 기회가 있었기에, 그 비망록으로서 기사를 정리했습니다.

이번에는 사내를 위한 규칙이라기보다, 'AI 에이전트에게 내가 이상적으로 생각하는 코드를 생성하게 하기 위한 규칙 설계'로서 임해보고자 합니다.

규칙을 세우자!라고 생각했을 때, 그저 막연하게 생각해서는 답이 나오지 않습니다.

프론트엔드 규칙이라고 하면 클래스 명명 규칙(Naming Convention)이나 코딩 가이드라인(Coding Guideline) 등 세세하게 생각할 수 있는 것이 산더미처럼 많습니다.

하지만 "왜 그것을 만들어야 하는가", "어떤 것을 만들어야 하는가"라는 목적을 명확히 하지 않으면, 나중에 중심이 흔들려 곤란해지게 됩니다.

목적을 찾는 가장 빠른 길은 "내가 생각하는 이상적인 모습(코드)"를 언어화하는 것입니다. 제가 생각하는 "이상적인 코드"는 다음과 같습니다.

  • 심플한 소스, 최소한의(낭비 없는) 코드
  • 유지보수가 용이함 (다시 보기 편함)
  • 컴포넌트(Component, 버튼 디자인 등)가 공통화되어 있음
  • 역할 단위로도 공통화되어 있음
  • 공식 문서의 규칙을 따르고 있음
    프라모델을 만드는 것처럼 조합해 나갈 수 있음

이 "이상적인 코드"를 달성하기 위해, 규칙의 목적을 다음의 2가지로 압축했습니다.

1: "누가 써도 (AI가 써도)" 동일한 구조와 동일한 품질이 되도록 한다.

2: 개발 시의 "불필요한 망설임"을 줄이고 효율을 높인다.

AI에게 적절한 코드를 출력하게 하기 위한 규칙(제약)을 고민하기 위해 다음과 같은 단계를 진행해 보았습니다.

불필요한 코드를 걷어낸다.

예)

  • 정보의 하드 코딩 (Hard Coding)
  • 유사 코드의 증식
  • any 타입과 as 어설션(Assertion) 금지 (라이브러리 사정으로 어쩔 수 없는 경우만 예외)

폴더 구성·타입 등 파츠의 형태를 맞춘다.

예)

  • 배치 장소(파일 구성)의 통일 (폴더 구성은 공식 문서를 참조한다)
  • 명명 규칙(Naming Convention)의 통일

무엇을 하나의 블록(컴포넌트화·공통화)으로 할지 기준을 정한다.

예)

  • "이용자 입장에서 같은 개념"이라면 컴포넌트화

이름을 붙였을 때 자연스럽게 의미가 전달되는 덩어리는 컴포넌트로 분리한다. - "변경 이유가 같다"면 공통화

동일한 유효성 검사 규칙(Validation Rule)이 여러 곳에 있는 경우, 사양 변경 시 전부 동시에 수정해야 하므로 공통화시킨다. - 역할 분담

컴포넌트 자체의 책임은 작고 심플하게 유지한다.

여기서부터는 실제로 책정한 규칙의 구체적인 예시와 기준을 기재하겠습니다.

이번에는 다음과 같은 프레임워크를 사용하는 것을 상정합니다.

  • vue.js
  • TailwindCSS

먼저, Step 1에서 AI가 멋대로 복잡한 코드나 오래된 표기법을 생성하는 것을 방지하고, 리뷰 부담을 줄이기 위한 "금지 사항(제약)"을 정의합니다.

정보나 수치의 직접 입력은 원칙적으로 금지합니다 (0 등 초기화를 위한 값은 예외). AI는 문맥을 무시하고 하드 코딩을 하기 쉽기 때문에, 문자열·수치·설정값은 반드시 utils/const.ts 등으로 상수화하게 합니다.

TypeScript의 이점을 죽이는 any와 강제적인 타입 추론(as)은 원칙적으로 사용하지 않습니다 (라이브러리 사정으로 어쩔 수 없는 경우만 예외).

CSS는 원칙적으로 쓰지 않고, Tailwind의 Utility Class를 사용합니다. bg-[#fff]와 같은 직접 입력도 금지하며, 고유한 색상은 반드시 tailwind.config에 정의하여 한곳에 모아 사용합니다.

bg-blue-500와 같이 구체적인 색상명에 의존한 클래스명 사용을 금지합니다. "파란색이라서"가 아니라 "주요 버튼이라서"라는 이유로 스타일을 적용해야 합니다. 기본 컬러 팔레트를 직접 입력하면 테마 변경 시 파탄 나기 때문에, 반드시 시맨틱(Semantic, 의미·역할)한 고유 정의 클래스(bg-primary 등)를 사용하게 함으로써 변경을 용이하게 합니다.

요구되지 않은 기능은 구현하지 않습니다. AI의 "지나치게 배려한 오버스펙(Over-spec) 구현"을 여기서 방지합니다. 또한, 과도한 코드는 유지보수 시 필요 여부의 판단을 흐리게 하여 버그의 온상이 될 수 있습니다.

요소를 조작할 때, AI는 아무렇지 않게 document.querySelector 나 getElementById를 쓰려고 합니다. Vue의 라이프사이클(Lifecycle)과 충돌하여 버그의 온상이 되므로, DOM 접근이 필요한 경우에는 반드시 Template Refs (ref="xxx")를 사용하게 합니다.

Vue의 공식 베스트 프랙티스 (Best Practices)에 따라, computed 내부에서 비동기 통신 (API 호출)을 수행하거나 다른 변수를 수정하는 '부작용 (Side Effects)'을 엄격히 금지합니다. computed는 순수한 값의 계산에만 전념하게 합니다.

Vue의 성능 최적화 (Performance Optimization) 관점에서, '변경되지 않는 거대한 데이터 (마스터 데이터나 긴 리스트)'에 대해 일반적인 ref를 사용하는 것을 금지합니다. 렌더링 오버헤드 (Rendering Overhead)를 줄이기 위해, 감시가 필요 없는 데이터에는 상수로서 let이나 const 사용을 검토하십시오.

XSS 취약성을 방지하기 위해, 사용자 입력이 포함된 콘텐츠를 v-html로 직접 렌더링하는 것을 금지합니다. 백엔드에서 반환된 HTML을 렌더링할 경우에는 반드시 새니타이즈 (Sanitize) 처리를 거치도록 강제합니다.

다음으로, Step 2에서 만든 파츠 (Parts)가 확실히 조합될 수 있도록, 명명 규칙 (Naming Convention)이나 파일 구성과 같은 '조인트 (Joint) 규격'을 통일합니다.

프로젝트 전체에서 일관성을 유지하고, AI가 파일의 위치를 헤매지 않도록 다음과 같은 구성을 따릅니다.

src/
├── components/
│ ├── parts/ # 범용 UI 부품 (BaseButton, Badge 등)
...

파일명이나 클래스명을 생성할 때는 다음 명명 규칙을 사용하십시오.

  • 상수: 모두 대문자인 스네이크 케이스 (Snake Case)
    (예: MAX_COUNT)
  • 함수: 시작은 동사를 사용하며, 원칙적으로 화살표 함수 (Arrow Function)로 정의
    (예: const getUserData = () => {})
  • 파일명: 파스칼 케이스 (PascalCase.vue)
    기저 컴포넌트 (Base Component)에는 접두사로 Base를 붙임
  • CSS 클래스 (커스텀 정의 시): 케밥 케이스 (Kebab Case)와 BEM 명명법을 채택
    상태를 나타내는 것은 is-를 붙임
  • BEM 명명법의 기본: Block (.form-group 등), Element (.form-label 등), Modifier (.required 등)로 구분함.

type으로 정의하며, 공통된 것은 types/index.ts에 배치합니다.

날짜를 직접 조작하려고 할 경우, 몇 가지 고려 사항이 있습니다.

복잡한 처리 또는 사양상 라이브러리 활용이 어려운 경우 등을 제외하고, 직접 new Date()를 사용하는 것은 피하며 dayjs 등을 활용합니다.

Tailwind 특유의 '클래스명이 옆으로 너무 길어져 가독성이 떨어지는 문제'를 해결하기 위해, 여러 가지 스타일 변형을 가진 UI (버튼이나 배지 등)에는 class-variance-authority (cva) 등의 패턴을 사용하여 클래스명을 추상화합니다.

div의 남용을 피하고, nav, main, article을 적극적으로 사용함으로써 구조를 알기 쉽게 하고 가독성도 향상시킵니다.

마지막으로, Step 3에서 어디까지를 하나의 블록 (Block)으로 다룰 것인지, 파츠 간의 연계는 어떻게 할 것인지에 대한 경계선을 정합니다.

컴포넌트화: PrimaryButton, UserCard와 같이 이름을 붙였을 때 자연스럽게 의미가 전달되는 것은 컴포넌트화 대상으로 합니다.

공통화: (예) 동일한 검증 규칙 (Validation Rule)이 여러 곳에 있는 경우 (사양 변경이 발생했을 때 전부 동시에 수정해야 하기 때문).

  • 3회 이상 사용될 것으로 예상됨
  • 독립된 기능·UI 부품임 (예: Badge.vue와 같이 단일 책임)
  • 다른 컴포넌트에서 재사용 가능함

단순히 겉모습이 같다는 이유만으로 컴포넌트를 공통화해서는 안 됩니다.

예를 들어 '상품 구매 버튼'과 '친구 초대 버튼'은 컨텍스트 (Context, 역할)가 완전히 다릅니다. 사양 변경으로 인해 '구매 버튼에만 품절 로딩을 표시하고 싶다'는 상황이 되었을 때, 공통화되어 있다면 복잡한 if 문 덩어리 (기술 부채)가 됩니다. AI에게는 '외형이 아니라, 변경 이유가 같은 것만 공통화한다'는 사고방식을 지키게 합니다.

컴포넌트 자신의 책임을 작게 유지하기 위해, 컴포넌트 내부의 @click이나 @focus 이벤트는 스스로 처리하지 않고, emit을 통해 상위 (Controller 계층)로 전달하여 처리하게 합니다.

컴포넌트 (.vue) 내부에 복잡한 비즈니스 로직 (Business Logic)이나 API 통신의 상세 내용을 직접 작성하는 것을 금지합니다. UI와 관계없는 데이터 페칭 (Data Fetching)이나 상태 관리는 반드시 useUser()와 같은 컴포저블 (Composables, 함수)로서 외부 파일로 분리하여, 컴포넌트를 클린하게 유지합니다.

규칙 설계의 사고방식에 대해 정리했습니다.

'규칙 설계'라고 하면 어렵게 느껴질 수 있지만, 이 3단계를 통해 구체화해 나감으로써 코드의 '흔들림'을 줄이고 편차를 경감시킬 수 있습니다.

또한 이 가이드라인을 따름으로써, 인간에게도, 구현을 담당하는 AI 에이전트에게도, 일관성 있는 '프라모델 같은' 개발이 가능해지지 않을까요.

여러분의 현장에서도 꼭 AI 에이전트를 향한 독자적인 '규칙 설계 (Rule Design)'에 도전해 보세요!

본 기사의 시도 과정에서 다음 기사를 참고하였습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0