# CLAUDE.md — Claude Code Instructions: Unity & C# Development Standards 이 문서는 Claude가 Unity 및 C# 프로젝트에서 코드를 작성, 리팩토링, 코드 리뷰할 때 반드시 준수해야 하는 **최우선 개발 표준(System Instructions)**입니다. --- ## 프로젝트 개요 Unity 프로젝트 (ClaudeCodeTest) ## 개발 환경 - **엔진**: Unity 6 - **언어**: C# (.NET) - **플랫폼**: Windows 11 --- ## 목차 (Table of Contents) 1. [AI 핵심 행동 지침 (Core Directives)](#1-ai-핵심-행동-지침-core-directives) 2. [1순위: UI Toolkit 개발 표준 (UI Toolkit)](#2-1순위-ui-toolkit-개발-표준-ui-toolkit) - [2.1 핵심 원칙](#21-핵심-원칙) - [2.2 이벤트 콜백 등록 규칙](#22-이벤트-콜백-등록-규칙) - [2.3 UXML/USS 파일 네이밍 규칙](#23-uxmluss-파일-네이밍-규칙) - [2.4 커스텀 VisualElement (Unity 6)](#24-커스텀-visualelement-unity-6) - [2.5 아키텍처 (MVVM/MVC)](#25-아키텍처-mvvmmvc) 3. [2순위: 코드 품질 및 위생 (Code Quality)](#3-2순위-코드-품질-및-위생-code-quality) 4. [3순위: 현대적 C# 및 아키텍처 (Modern C# & Architecture)](#4-3순위-현대적-c-및-아키텍처-modern-c--architecture) 5. [4순위: 성능 최적화 및 금지 패턴 (Performance)](#5-4순위-성능-최적화-및-금지-패턴-performance) 6. [5순위: 유니티 폴더 구조 표준 (Folder Structure)](#6-5순위-유니티-폴더-구조-표준-folder-structure) 7. [6순위: 품질 자동화 (Quality Automation)](#7-6순위-품질-자동화-quality-automation) 8. [코드 자체 검증 체크리스트 (Self-Review)](#8-코드-자체-검증-체크리스트-self-review) --- ## 1. AI 핵심 행동 지침 (Core Directives) Claude는 코드를 출력하기 전, 다음 3가지 핵심 규칙이 적용되었는지 반드시 확인합니다. - **안전성 (Safety)**: 모든 파일 상단에 `#nullable enable`을 포함하고 컴파일 경고가 발생하지 않도록 코드를 작성하라. - **취소 가능성 (Cancellability)**: 모든 `UniTask` 비동기 메서드에는 `CancellationToken`을 필수로 적용하라. - **성능 (Performance)**: `Update()` 등 매 프레임 호출되는 Hot Path 내에서는 가비지(GC)를 유발하거나 무거운 Unity API를 절대 호출하지 마라. --- ## 2. 1순위: UI Toolkit 개발 표준 (UI Toolkit) ### 2.1 핵심 원칙 - **UI Toolkit(UIElements) 필수 사용.** uGUI(Canvas 기반)는 레거시로 취급한다. - **UXML(구조)과 USS(스타일)를 분리**하고, C# 코드에서 인라인 스타일 지정을 지양한다. - 파일 선두에 `#nullable enable`, 모든 참조형에 `?` 명시. - 비동기는 `UniTask` + `CancellationToken` 사용 (Task/코루틴 지양). - 느슨한 결합: 인터페이스/이벤트로 레이어 간 연결. ### 2.2 이벤트 콜백 등록 규칙 > ⚠️ **중요**: `RegisterValueChangedCallback` 대신 `RegisterCallback>`를 사용한다. > > `RegisterValueChangedCallback`은 확장 메서드로 `UnregisterCallback`과 대칭이 맞지 않아 이벤트 해제가 어렵다. ```csharp // ❌ 잘못된 예: 해제가 어려운 방식 field.RegisterValueChangedCallback(OnValueChanged); // field.UnregisterValueChangedCallback(OnValueChanged); // 이런 메서드 없음! // ✅ 올바른 예: 대칭적인 등록/해제 field.RegisterCallback>(OnValueChanged); field.UnregisterCallback>(OnValueChanged); private void OnValueChanged(ChangeEvent evt) { // evt.newValue, evt.previousValue 사용 } ``` | 메서드 | 권장 | 이유 | |--------|------|------| | `RegisterValueChangedCallback` | ❌ | 해제용 메서드 없음 | | `RegisterCallback>` | ✅ | `UnregisterCallback` 대칭 | ### 2.3 UXML/USS 파일 네이밍 규칙 > ⚠️ **중요**: UXML과 USS 파일명은 반드시 다르게 지정해야 한다. > > `Resources.Load(path)`는 확장자 없이 경로를 받기 때문에, 동일한 경로에 UXML과 USS가 모두 존재하면 로드 충돌이 발생할 수 있다. ```csharp // ❌ 잘못된 예: 동일한 경로명 사용 private const string UXML_PATH = "UIToolkit/Window/UTKAccordionListWindow"; private const string USS_PATH = "UIToolkit/Window/UTKAccordionListWindow"; // Resources.Load(UXML_PATH); // .uxml 로드 // Resources.Load(USS_PATH); // .uss 로드 실패 가능 // ✅ 올바른 예: USS 파일명에 접미사 추가 private const string UXML_PATH = "UIToolkit/Window/UTKAccordionListWindow"; private const string USS_PATH = "UIToolkit/Window/UTKAccordionListWindowUss"; // 파일 구조: // - UTKAccordionListWindow.uxml // - UTKAccordionListWindowUss.uss ``` | 파일 유형 | 네이밍 패턴 | 예시 | |-----------|-------------|------| | UXML | `{ComponentName}.uxml` | `UTKAccordionListWindow.uxml` | | USS | `{ComponentName}Uss.uss` | `UTKAccordionListWindowUss.uss` | ### 2.4 커스텀 VisualElement (Unity 6) Unity 6에서는 레거시 `UxmlFactory`/`UxmlTraits` 방식을 사용하지 않고, 소스 생성기 기반의 `[UxmlElement]`와 `[UxmlAttribute]`를 사용한다. **필수 규칙:** - 클래스에 `[UxmlElement]` 어트리뷰트 추가 - 클래스를 `partial`로 선언 (소스 생성기 요구사항) - UXML 속성은 `[UxmlAttribute]`로 **케밥 케이스 소문자** 명시 ```csharp // ✅ 올바른 예: Unity 6 방식 [UxmlElement] public partial class UTKCodeBlock : VisualElement { [UxmlAttribute("title")] public string Title { get; set; } [UxmlAttribute("is-enabled")] public bool IsEnabled { get; set; } [UxmlAttribute("border-width")] public int BorderWidth { get; set; } } // ❌ 잘못된 예: 레거시 방식 (사용 금지) public class UTKCodeBlock : VisualElement { public new class UxmlFactory : UxmlFactory { } public new class UxmlTraits : VisualElement.UxmlTraits { ... } } // ❌ 잘못된 예: 케밥 케이스 미사용 [UxmlAttribute] // Unity 6에서 UXML 속성 매핑 실패 public string Text { get; set; } [UxmlAttribute("Text")] // 대문자는 UXML과 불일치 public string Text { get; set; } ``` UXML 사용 예: ```xml ``` ### 2.5 아키텍처 (MVVM/MVC) ``` ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ View │◄────│ ViewModel │◄────│ Model │ │ (UXML/USS) │ │ (Presenter) │ │ (Service) │ └─────────────┘ └──────────────┘ └─────────────┘ │ │ └── 이벤트 전달 ──────┘ ``` | 레이어 | 책임 | 금지 사항 | |--------|------|-----------| | View | 표시/레이아웃, 이벤트 라우팅 | 비즈니스 로직, 상태 보유 | | ViewModel/Presenter | 상태 관리, 데이터 변환, 바인딩 속성 | Unity API 직접 호출 (테스트 용이성 확보) | | Model/Service | 도메인 로직, 데이터 접근 | UI 참조 | - **MVVM**: UI 상태/양방향 동기화가 많을 때 - **MVC**: 입력 → 도메인 액션 → UI 반영 흐름이 단순할 때 --- ## 3. 2순위: 코드 품질 및 위생 (Code Quality) ### 3.1 명명 규칙 (Microsoft C# Standard) | 대상 | 규칙 | 예시 | |------|------|------| | 클래스, 구조체, 인터페이스(`I` 접두사 필수), 메서드, 프로퍼티, 이벤트, 상수(`const`) | PascalCase | `PlayerController`, `IMovable`, `MaxSpeed` | | 프라이빗(Private) 필드 | `_camelCase` (`_` 접두사 필수) | `_health`, `_rigidbody` | | 로컬 변수, 매개변수 | camelCase | `playerSpeed`, `cancellationToken` | ### 3.2 코드 설계 원칙 - **접근 제어**: 모든 필드와 메서드는 명시적 지시가 없는 한 `private`으로 캡슐화하라. - **예외 처리 강제**: 논리적 오류나 유효하지 않은 상태에서는 `Debug.Log` 등으로 넘기지 말고, 즉시 `throw new Exception(...)` (또는 적절한 예외 타입)을 던져라. - **불변성 보장**: 생성자 할당 이후 변경되지 않는 필드는 `readonly`, 컴파일 타임 상수는 `const`로 선언하라. - **자기 설명적 코드**: 매직 스트링 대신 `nameof()`를 사용하며, 인라인 주석 없이도 이해할 수 있도록 명확한 식별자 명칭을 사용하라. --- ## 4. 3순위: 현대적 C# 및 아키텍처 (Modern C# & Architecture) ### 4.1 C# 9 최신 문법 활용 - **식 본문 멤버 (Expression-bodied)**: 단일 행 로직은 괄호 `{}` 대신 화살표 `=>`를 사용하라. - **Null 관리**: 복잡한 Null 체크 대신 Null 병합 연산자(`??`, `??=`)와 조건부 액세스(`?.`)를 적극 활용하라. - **패턴 매칭**: 타입 검사 및 캐스팅 시 `is` 키워드 및 `switch` 식(Expression)을 사용하라. - **데이터 객체**: 단순 데이터 보관용 타입은 `record`를 사용하고, `init` 키워드를 통해 불변성을 확보하라. ### 4.2 비동기 및 아키텍처 (UniTask & DI) **CancellationToken 필수 전파:** - 생성하는 모든 `UniTask` 비동기 메서드는 매개변수로 `CancellationToken`을 받아야 한다. - 내부의 모든 비동기 호출(e.g., `UniTask.Delay`)에 해당 토큰을 넘겨주어, 객체 파괴 시 안전하게 작업이 취소되도록 하라. - MonoBehaviour 환경에서는 기본 토큰으로 `this.GetCancellationTokenOnDestroy()`를 획득하여 전달하라. **데이터 컨트롤러 패턴:** - 데이터 모델의 직접적인 수정을 금지한다. 반드시 `Controller` 혹은 `Service` 계층을 통해서만 데이터를 조작하게 설계하라. **구독 해제 보장:** - 이벤트나 신호(Signal)를 구독한 객체는 소멸 시점(`Dispose`, `OnDestroy`)에 반드시 구독을 해제하라. --- ## 5. 4순위: 성능 최적화 및 금지 패턴 (Performance) ### 5.1 Update 루프 (Hot Path) 내 금지 사항 - **캐싱 의무화**: `Update` 내에서 `GetComponent` 계열 메서드 호출을 절대 금지한다. `Awake` 또는 `Start`에서 미리 캐싱하여 사용하라. - **GC 억제**: Hot Path에서는 LINQ 구문(`Where`, `Select` 등) 사용을 지양하고 전통적인 `for` 루프를 작성하라. - **무거운 탐색 금지**: `GameObject.Find`, `FindObjectOfType`, `FindWithTag` 사용을 절대 금지한다. DI(의존성 주입) 또는 인스펙터 참조를 사용하라. ### 5.2 유니티 비추천 패턴 (Anti-patterns) - **타입 불안정성**: `SendMessage`, `Invoke`, `StartCoroutine("string")` 등 문자열 기반의 호출 방식을 사용하지 마라. - **안전한 컴포넌트 접근**: `GetComponent` 호출 후 `null`을 체크하는 대신, `TryGetComponent`를 사용하여 성능을 확보하라. --- ## 6. 5순위: 유니티 폴더 구조 표준 (Folder Structure) AI가 새로운 스크립트나 에셋을 생성할 때, 다음 구조를 기본으로 준수하여 경로를 설정하라. ``` Assets/ ├── Scripts/ │ ├── {프로젝트명}/ # 프로젝트별 코드 │ │ ├── Config/ # 설정, 상수 │ │ ├── Manager/ # 매니저 클래스 │ │ ├── Command/ # Command 패턴 (Undo/Redo) │ │ └── ... │ └── UVC/ # 공통 라이브러리 ⭐ │ ├── Core/ # DI, Injector, Singleton │ ├── Data/ # DataMapper, MQTT/HTTP 통신 │ ├── Pool/ # 오브젝트 풀링 │ ├── UI/ # uGUI 컴포넌트 (Modal, Tab) │ └── UIToolkit/ # UI Toolkit 컴포넌트 ⭐ ├── Resources/ │ ├── {프로젝트명}/ # 프로젝트별 리소스 │ │ ├── Materials/ │ │ ├── Models/ │ │ └── Prefabs/ │ └── UIToolkit/ # 공통 UI 리소스 ⭐ │ ├── Common/ # 공통 스타일 (USS) │ ├── List/ # 리스트 컴포넌트 (UXML) │ ├── Modal/ # 모달 컴포넌트 (UXML) │ ├── Property/ # 속성 편집기 (UXML) │ └── Window/ # 윈도우 컴포넌트 (UXML) ├── Plugins/ # 서드파티 (Best.HTTP, DOTween 등) ├── Sample/ # 샘플 씬 └── Scenes/ # 앱 씬 ``` --- ## 7. 6순위: 품질 자동화 (Quality Automation) ### 7.1 .editorconfig 권장 설정 ```ini dotnet_diagnostic.CS1591.severity = error # 공개 멤버 문서 주석 필수 dotnet_analyzer_diagnostic.category-Nullable.severity = error dotnet_diagnostic.IDE0060.severity = warning # 미사용 매개변수 ``` ### 7.2 CI 규칙 - XML 문서 누락 / nullable 경고 → **빌드 실패** 처리 - 에디트 모드 테스트와 플레이 모드 테스트를 **분리하여 실행** --- ## 8. 코드 자체 검증 체크리스트 (Self-Review) Claude는 응답을 생성하기 전 내부적으로 다음 사항을 점검하십시오. - [ ] 파일 최상단에 `#nullable enable`을 선언했는가? - [ ] 프라이빗 변수명에 `_` 접두사를 붙였는가? - [ ] 에러 상황을 `Debug.Log`가 아닌 `throw Exception`으로 처리했는가? - [ ] 작성한 모든 UniTask 비동기 함수에 CancellationToken이 적용되었는가? - [ ] 매 프레임 실행되는 코드(`Update`)에 가비지나 오버헤드(LINQ, GetComponent)가 없는가? - [ ] 새 스크립트는 `Assets/Scripts/{프로젝트명}/` 또는 `Assets/Scripts/UVC/` 하위 올바른 경로에 배치했는가? - [ ] 새 UXML/USS 리소스는 `Assets/Resources/UIToolkit/` 하위 올바른 경로에 배치했는가? - [ ] UXML 파일명과 USS 파일명이 다르게 지정되었는가? (USS는 `{Name}Uss.uss` 형식) - [ ] UI 코드에서 `RegisterValueChangedCallback` 대신 `RegisterCallback>`를 사용했는가? - [ ] 커스텀 VisualElement에 `[UxmlElement]`, `partial`, `[UxmlAttribute("케밥-케이스")]`를 적용했는가? - [ ] uGUI(Canvas) 컴포넌트를 새로 사용하지 않았는가? --- ## Unity 일반 주의사항 - `Library/` 폴더 내 파일은 절대 수정하지 말 것 (Unity 자동 관리) - `.meta` 파일은 Unity가 자동 생성하므로 직접 편집 자제 - 씬 파일(`.unity`)이나 프리팹(`.prefab`) 수정 시 Unity Editor에서 확인 필요 - Unity 생명주기 메서드 순서: `Awake` → `OnEnable` → `Start` → `Update` → `OnDisable` → `OnDestroy`