# 브리핑 문서
## **문서 출처:**
"Use_a_C__style_guide_for_clean_and_scalable_game_code_Unity_6_edition.pdf" (Unity Technologies, 2025)
## **개요:**
이 보고서는 Unity Technologies에서 발행한 "Use a C# style guide for clean and scalable game code Unity 6 edition" E-book 발췌문을 검토하여 주요 주제와 중요한 아이디어 및 사실을 요약합니다. 이 가이드는 Unity 개발에서 깨끗하고 유지보수 가능한 C# 코드를 작성하기 위한 권장 사항을 제공하며, 팀 개발 시 일관성을 유지하는 데 중점을 둡니다.
## **주요 주제 및 중요한 아이디어/사실:**
1. **깨끗한 코드의 중요성:**
- 이 가이드의 핵심은 "읽기 쉽고 유지보수 및 재사용이 효율적인 코드"인 깨끗한 코드의 필요성을 강조합니다.
- 코드가 일단 작동하면, 리팩토링 및 정리 프로세스를 시작해야 합니다.
- "당신의 미래 팀원들 – 그리고 미래의 당신 – 은 감사할 것입니다."
1. **팀 개발 원칙:**
- 팀으로 개발할 때 일관된 코딩 스타일을 따르는 것이 중요합니다.
- "컴퓨터가 이해할 수 있는 코드는 누구나 작성할 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 작성한다."
- **KISS (Keep It Simple, Stupid) 원칙:** 가장 간단한 문제 해결 방법을 찾는 것을 목표로 합니다. 불필요한 복잡성을 피합니다.
- "단순함은 궁극의 정교함이다." - 레오나르도 다빈치
- "모든 것은 가능한 한 간단하게 만들어야 하지만, 더 이상 간단하게 만들 수는 없다." - 알베르트 아인슈타인
- **YAGNI (You Aren't Gonna Need It) 원칙:** 필요할 때만 기능을 구현합니다. 나중에 필요할지도 모르는 기능에 대해 미리 걱정하지 않고, 지금 당장 필요한 가장 간단한 것을 구축합니다. Unity Scripting API의 기존 솔루션을 활용하는 것이 좋습니다. "당신이 쓸 수 있는 최고의 코드는 코드가 전혀 없는 것이다."
- **문제 주변을 코딩하지 마십시오:** 문제를 해결하기 위해 코드를 추가하기보다 근본 원인을 조사해야 합니다.
- **매일 점진적으로 개선:** 코드 정리 및 유지보수를 개발자의 일상적인 작업의 일부로 간주해야 합니다. 코드베이스는 지속적인 유지보수가 필요하며 이를 위한 시간을 할애해야 합니다.
- **완벽이 아닌 좋음을 목표로:** 코드가 프로덕션 표준을 충족하면 커밋하고 다음 작업으로 넘어갈 때입니다. 리팩토링은 자신이나 다른 사람에게 이점을 제공할 것이라고 생각될 때만 수행해야 합니다.
- **계획하되, 적응:** 소프트웨어 엔지니어링은 유기적인 프로세스이므로 계획대로 진행되지 않을 때를 대비하고 적응할 준비를 해야 합니다.
- **일관성 유지:** 팀 전체가 동일한 스타일 가이드에 동의하고 적용해야 합니다.
- **스타일 가이드 준수:** 이 가이드와 같은 C# 스타일 가이드를 따르는 것이 좋습니다.
1. **이름 규칙 (Naming Conventions):**
- 이름은 단순히 레이블이 아니라 변수, 클래스, 메서드의 의미를 전달합니다. 좋은 이름은 코드를 읽는 사람이 아이디어를 이해하는 방식에 영향을 미칩니다.
- "컴퓨터 과학에서 어려운 두 가지는 캐시 무효화와 이름 짓기다." - Phil Karlton
- **식별자 이름:** 형식, 멤버, 변수, 네임스페이스에 할당하는 모든 이름입니다. 특수 문자(백슬래시, 기호, 유니코드 문자)를 피해야 합니다.
- **카싱 용어:카멜 케이스 (camelCase):** 첫 글자는 소문자이고 단어의 시작은 대문자로 구분합니다 (예: examplePlayerController). 지역 변수 및 메서드 매개 변수에 사용됩니다.
- **파스칼 케이스 (PascalCase):** 모든 단어의 시작이 대문자입니다 (예: ExamplePlayerController). Unity 개발에서 클래스, public 필드, 메서드 이름에 사용됩니다.
- **스네이크 케이스 (snake_case):** 단어 사이에 밑줄(_)을 사용합니다 (예: example_player_controller).
- **케밥 케이스 (kebab-case):** 단어 사이에 대시(-)를 사용합니다 (예: example-player-controller). UI Toolkit USS에 권장됩니다.
- **헝가리언 표기법:** 변수 또는 함수 이름이 의도나 유형을 나타냅니다 (예: int iCounter). Unity 개발에서는 흔하지 않습니다.
- **필드 및 변수:**변수 이름은 명확하고 모호하지 않아야 하며 사물이나 상태를 나타내므로 **명사**를 사용해야 합니다 (bool 유형 제외).
- **Booleans는 동사로 시작:** true 또는 false 값을 나타내므로 의미를 더 명확히 하기 위해 동사로 접두사를 붙입니다 (예: isDead, hasDamageMultiplier).
- **의미 있는 이름 사용:** 약어를 피하고 (수학 제외), 의도를 드러내는 이름을 선택해야 합니다. AI 도구를 사용할 때 추가 컨텍스트를 제공하여 코드 생성 및 제안의 정확도를 높일 수 있습니다.
- **public 필드는 파스칼 케이스 (MyPropertyName), private 변수는 카멜 케이스 (myPrivateVariable):** public 필드의 대안으로 public getter가 있는 Properties를 사용할 수 있습니다.
- **접두사 또는 특수 인코딩 사용 고려:** private 멤버 변수에 밑줄 _, 상수에 k_, static 변수에 s_와 같은 접두사를 사용하여 변수에 대한 정보를 한눈에 알 수 있도록 할 수 있습니다. this 키워드를 사용하여 멤버 변수와 지역 변수를 구별할 수도 있습니다.
- **필드는 기본값으로 자동 초기화:** 명시적으로 기본값으로 설정하는 것은 불필요합니다.
- **상수 변수 이름은 k_ 접두사와 파스칼 케이스 사용:** public const int k_MaxItems = 100;
- **접근 수준 수정자 일관되게 지정 (또는 생략):** MSFT 가이드라인은 private를 명시적으로 지정하는 것을 권장하지만, 일부 가이드라인은 불필요한 접근 지정자 (private)를 생략하는 것을 주장합니다. 팀에서 일관성을 정해야 합니다.
- **변수 선언은 줄당 하나:** 가독성을 향상시킵니다.
- **불필요한 이름 피하기:** 클래스 이름이 Player인 경우, PlayerScore 또는 PlayerTarget과 같은 멤버 변수 이름은 피하고 Score 또는 Target으로 줄입니다.
- **불필요한 이니셜라이저 제거:** int의 = 0, 참조 타입의 = null 등을 제거합니다.
- **농담이나 말장난 피하기:** 시간이 지나면 읽기 어렵고 문맥을 드러낸다는 목표에 위배됩니다.
- **컨텍스트가 명확할 때 var 사용:** 좋은 이름과 함께 사용하면 모호성이 줄어들고 리팩토링이 간단해집니다.
- **Enums:** 값의 집합으로 정의된 특별한 값 형식입니다. Enum 이름과 값에 파스칼 케이스를 사용합니다. 일반적으로 전역적으로 만들기 위해 클래스 밖에 배치하고 단수 명사를 사용합니다 (System.FlagsAttribute가 있는 비트와이즈 Enum 제외).
- **클래스 및 인터페이스:**인터페이스 이름은 대문자 I로 시작하고 기능 설명하는 형용사를 붙입니다 (예: IKillable).
- **메서드 (Methods):** C#에서는 모든 실행 지침이 메서드의 컨텍스트에서 수행됩니다. "함수"와 "메서드"는 Unity 개발에서 종종 혼용되지만, C#에서는 클래스 내에 포함되므로 "메서드"가 더 적절한 용어입니다.
- 이름을 **동사** 또는 동사 구문으로 시작하여 수행하는 작업을 반영합니다 (예: GetDirection, FindTarget).
- 매개변수는 **카멜 케이스**를 사용합니다.
- bool을 반환하는 메서드는 **질문**의 형태로 만들어야 합니다 (예: IsGameOver).
- **부작용 피하기:** 메서드는 이름에 광고하는 것만 수행해야 합니다. 스코프 밖의 것을 수정하는 것을 피해야 합니다.
- **플래그를 전달하는 대신 다른 메서드 만들기:** 플래그에 따라 두 가지 모드로 작동하도록 메서드를 설정하지 않고, 구별되는 이름을 가진 두 개의 메서드를 만듭니다.
- **이벤트 및 이벤트 핸들러:**이벤트 처리 메서드 (옵저버)에 주체 이름과 밑줄(_)로 접두사를 붙이는 것을 고려합니다 (예: GameEvents_OpeningDoor).
- **네임스페이스 (Namespaces):** 클래스, 인터페이스, enum 등이 다른 네임스페이스 또는 전역 네임스페이스의 기존 것과 충돌하지 않도록 합니다.
- **파스칼 케이스**를 사용하고 특수 기호나 밑줄을 사용하지 않습니다.
- 파일 상단에 using 지시어를 추가하여 반복적인 네임스페이스 접두사 입력을 피합니다.
- 점(.) 연산자를 사용하여 하위 네임스페이스를 만들 수 있습니다 (예: MyApplication.GameFlow).
- 일부는 프로젝트의 폴더 구조를 반영하는 네임스페이스를 선호합니다.
1. **형식 (Formatting):**
- "코드를 쉽게 작성하고 싶다면, 읽기 쉽게 만들어라." - Robert C. Martin
- 형식은 추측을 줄이고 코드 명확성을 향상시키는 데 도움이 됩니다. 표준화된 스타일 가이드를 따르면 코드 검토가 코드의 모양보다는 기능에 초점을 맞추게 됩니다.
- **속성 (Properties):** 클래스 값을 읽거나 쓰거나 계산하는 유연한 메커니즘을 제공합니다. public 멤버 변수처럼 동작하지만 실제로는 get 및 set 메서드라고 하는 특별한 메서드입니다.
- 단일 줄 읽기 전용 속성에는 **표현식 본체 속성 (=>)**을 사용합니다.
- 그 외의 모든 것은 이전의 { get; set; } 구문을 사용합니다. 명시적인 backing 필드를 지정하지 않고 public 속성을 노출하고 싶다면 **자동 구현 속성**을 사용합니다.
- 쓰기 접근을 원하지 않는다면 setter를 private으로 만듭니다.
- **직렬화 (Serialization):**[SerializeField] 속성을 사용하여 private 필드를 Inspector에 노출시킬 수 있습니다.
- 직렬화 가능한 클래스 또는 구조체를 사용하여 Inspector를 구성할 수 있습니다.
- **중괄호 또는 들여쓰기 스타일:Allman 스타일:** 여는 중괄호를 새 줄에 배치합니다. 이 가이드의 예시에서 사용됩니다.
- **K&R 스타일:** 여는 중괄호를 이전 헤더와 같은 줄에 유지합니다.
- 팀 전체가 동일한 들여쓰기 및 중괄호 스타일을 따라야 합니다.
- **균일한 들여쓰기:** 일반적으로 4개 또는 2개의 공백입니다. Visual Studio와 같은 IDE에서 탭을 공백으로 변환하는 옵션을 제공합니다.
- **단일 줄 문장에도 중괄호 생략하지 마십시오:** 일관성이 높아져 코드를 읽고 유지보수하기가 더 쉬워집니다.
- **중첩된 여러 줄 문장에서 중괄호 제거하지 마십시오:** 혼란을 유발할 수 있으며 명확성을 위해 중괄호를 적용해야 합니다.
- **switch 문 표준화:** 긴 if-else 체인을 switch 문으로 대체하는 것이 좋습니다. case 문을 들여쓰고 default case를 포함하는 것이 일반적으로 권장됩니다.
- **EditorConfig:** 여러 개발자가 다른 편집기와 IDE를 사용할 때 팀 전체에서 작동하는 코딩 스타일을 정의하는 데 도움이 됩니다.
- **수평 간격 (Horizontal spacing):**코드 밀도를 줄이기 위해 **공백 추가:** 가독성을 향상시킵니다.
- 함수 인자 사이에 쉼표 뒤에 **하나의 공백** 사용.
- 괄호와 함수 인자 뒤에 **공백 추가하지 마십시오**.
- 함수 이름과 괄호 사이에 **공백 사용하지 마십시오**.
- 대괄호 안에 **공백 피하십시오**.
- 제어 흐름 조건 전에 **하나의 공백** 사용.
- 비교 연산자 전후에 **하나의 공백** 사용.
- **짧은 줄 유지:** 표준 줄 너비 (80-120자)를 결정하고 긴 줄을 더 작은 문장으로 나눕니다.
- **들여쓰기/계층 유지:** 코드를 들여쓰기하여 가독성을 높입니다.
- 가독성을 위해 필요한 경우가 아니면 **열 정렬 사용하지 마십시오:** 변수를 정렬하지만 유형과 이름을 연결하기 어렵게 만들 수 있습니다.
- **수직 간격 (Vertical spacing):**의존적이거나 유사한 메서드를 **함께 그룹화:** 코드는 논리적이고 일관적이어야 합니다.
- 변수 선언과 메서드, 클래스와 인터페이스 등과 같이 **별개의 부분을 구분**하기 위해 수직 공백을 사용합니다.
- **Region:** #region 지시어는 C# 파일의 코드 섹션을 축소하고 숨길 수 있도록 합니다. 그러나 이 가이드의 일반적인 클래스 조언을 따르면 클래스 크기가 관리 가능하며 #region 지시어는 불필요합니다. (많은 개발자가 region을 코드 스멜 또는 안티 패턴으로 간주합니다.)
1. **클래스 (Classes):**
- "컴퓨팅의 짧은 역사에서 완벽한 소프트웨어를 작성한 사람은 없다. 당신이 첫 번째가 될 가능성은 낮다."
- 작고 단일 책임 원칙을 따르는 클래스로 코드를 분할합니다.
- **단일 책임 원칙 (Single-responsibility principle):** 클래스는 하나의 책임만 가져야 합니다.
- **리팩토링 예시:** Paddle 클래스를 PaddleData, PaddleInput, PaddleMovement, PaddleAudio와 같은 작은 클래스로 분할하여 각자 단일 책임을 갖도록 합니다.
1. **주석 (Comments):**
- "코드는 유머와 같다. 설명해야 한다면 나쁜 것이다." - Cory House
- 잘 배치된 주석은 코드의 가독성을 높입니다. 과도하거나 경솔한 주석은 반대 효과를 가져올 수 있습니다.
- KISS 원칙을 따르고 코드를 이해하기 쉬운 논리적 부분으로 나누면 대부분의 코드는 주석이 필요하지 않습니다. 잘 명명된 변수와 함수는 스스로 설명합니다.
- 유용한 주석은 "무엇"이 아닌 "**왜**"를 설명합니다. 명백하지 않은 결정을 내렸거나 설명이 필요한 까다로운 로직이 있다면 유용한 주석이 필요합니다.
- **나쁜 코드를 대체하기 위해 주석 추가하지 마십시오:** 복잡한 로직을 설명하기 위해 주석을 추가해야 한다면 코드를 더 명확하게 재구성해야 합니다.
- **제대로 명명된 클래스, 변수 또는 메서드는 주석 대신 사용됩니다:** 코드가 자명하다면 불필요한 주석을 제거하여 노이즈를 줄입니다.
- 가능하다면 주석을 **별도의 줄에 배치**하고 코드 줄 끝에 배치하지 마십시오.
- 대부분의 상황에서 **이중 슬래시 (//)** 주석 태그를 사용합니다.
- 직렬화된 필드에 대한 주석 대신 **툴팁**을 사용합니다.
- public 메서드 또는 함수 앞에 **summary XML 태그**를 사용할 수 있습니다.
- 주석 구분 기호 (//)와 주석 텍스트 사이에 **하나의 공백**을 삽입합니다.
- **법적 면책 조항 추가:** 라이선스 또는 저작권 정보에 대한 주석은 적절합니다.
- **주석 스타일 지정:** 주석에 대한 통일된 모양을 유지합니다 (예: 모든 주석을 대문자로 시작하고 마침표로 끝냄).
- 주석 주변에 **별표 또는 특수 문자의 형식화된 블록을 만들지 마십시오.**
- **주석 처리된 코드 제거:** 테스트 및 개발 중에 주석 처리하는 것은 일반적이지만, 주석 처리된 코드를 남겨두지 마십시오. 소스 제어를 활용합니다.
- **TODO 주석 최신 상태 유지:** 작업을 완료하면 TODO 주석을 제거합니다. 오래된 주석은 방해가 됩니다. TODO에 이름과 날짜를 추가하여 책임과 문맥을 더할 수 있습니다. YAGNI 원칙을 기억하고 구현할 때까지 TODO 주석을 삭제합니다.
- **일지 피하기:** 주석은 개발자의 일지를 쓰는 곳이 아닙니다.
1. **UI Toolkit 명명 규칙:**
- UXML 및 스타일 시트 클래스에 **BEM (Block Element Modifier)** 명명 규칙을 권장합니다.
- BEM은 CSS 및 최신 웹 개발에서 널리 사용되며 UI Toolkit의 영감의 원천입니다.
- block-name__element-name--modifier-name 형식으로 구성됩니다.
- **블록 이름 (block-name):** 높은 수준의 구성 요소를 나타냅니다 (예: navbar-menu).
- **요소 (element-name):** 블록의 자식 또는 일부이며 의미적으로 블록에 묶여 있습니다 (예: __shop-button).
- **수정자 (modifier-name):** 블록 또는 요소의 변형 또는 상태를 나타냅니다 (예: --small).
- 이 예시들은 하이픈으로 구분하는 **케밥 케이스**를 사용합니다. 팀은 가장 적합한 명명 체계를 결정해야 하지만 프로젝트 초기에 선택하고 나중에 일관성을 유지해야 합니다.
- **효과적인 명명 규칙 팁:**이름을 짧고 명확하게 (모호하지 않게) 유지합니다.
- 다른 프로젝트에서 요소를 사용하는 경우, 기존 사용자 클래스 이름과의 충돌을 피하기 위해 클래스에 **접두사**를 붙이는 것을 고려합니다.
- 생성자에서 AddToClassList()를 사용하여 요소 인스턴스에 관련 USS 클래스를 추가합니다.
1. **일반적인 함정 (Common pitfalls):**
- 깨끗한 코드는 우연이 아니라 팀으로 생각하고 코딩하려는 개인의 의도적인 작업입니다.
- **코드 스멜:** 프로젝트에 문제가 있는 코드가 잠재적으로 있음을 나타내는 신호입니다.
- **모호한 이름:** 클래스, 메서드, 변수는 명확하고 단순한 이름이 필요합니다.
- **불필요한 복잡성:** 클래스에 대한 모든 가능한 요구를 예상하려고 할 때 발생합니다 (God 객체, 긴 메서드, 큰 클래스). 큰 단일 클래스를 작고 전담적인 부분으로 분할합니다.
- **유연성 부족:** 작은 변경으로 다른 곳에서 여러 변경이 필요하다면 단일 책임 원칙을 위반하고 있지 않은지 다시 확인해야 합니다.
- **과도한 주석:** 코드를 설명하는 데 도움이 되지만 개발자는 과도하게 사용할 수 있습니다. 잘 명명된 메서드나 클래스는 주석 없이도 의도를 드러낼 수 있습니다.
1. **결론 및 추가 자료:**
- 스타일 컨벤션 외에도 코드를 작고 모듈식 부분으로 분할하여 확장 가능하게 만들어야 합니다.
- 개발 과정에서 코드를 계속해서 다시 작성할 것으로 예상해야 합니다.
- 깨끗하고 체계적이며 읽기 쉬운 코드베이스 작성에 관심이 있다면 다른 E-book "Level up your code with design patterns and SOLID" 및 그 동반 샘플 프로젝트를 확인하십시오.
- **참고 자료:** "Refactoring: Improving the Design of Existing Code", "Test-Driven Development".
- "말은 싸구려다. 코드를 보여줘라." - Linus Torvalds (스크립트 템플릿 섹션 시작에 인용)
1. **부록: 스크립트 템플릿 (Script templates):**
- 새로운 C# 파일을 생성할 때 사용되는 미리 정의된 코드 스니펫입니다.
- Assets/ScriptTemplates 폴더에 있으며 사용자 정의할 수 있습니다.
- #SCRIPTNAME#과 #NOTRIM#과 같은 키워드를 포함합니다.
- 스크립트 템플릿 파일 이름은 PriorityNumber–MenuPath–DefaultName.FileExtension.txt 형식을 따릅니다.
- 특정 Unity 프로젝트에 적용하려면 Assets/ScriptTemplates 폴더에 복사합니다.
1. **부록: 테스트 및 디버깅 (Testing and debugging):**
- 자동화된 테스트는 코드 품질을 향상시키고 버그 수정에 소요되는 시간을 줄이는 효과적인 도구입니다.
- **테스트 주도 개발 (TDD):** 소프트웨어 개발 중에 단위 테스트를 생성하는 개발 방법론입니다. 새로운 기능이 작동하기 전에 각 테스트 케이스를 작성합니다.
1. **TDD 워크플로우 (빨간색 -> 초록색 -> 리팩토링):**새로운 기능을 위한 **실패하는 테스트**를 작성합니다.
2. 이 테스트가 통과할 수 있는 최소한의 **코드**를 작성합니다.
3. 모든 테스트가 통과할 때까지 새 코드를 수정합니다.
4. 새 코드를 **리팩토링**합니다. 스타일 가이드를 따르고 불필요한 코드를 제거합니다.
5. 각 리팩토링 후 자동화된 테스트 스위트를 실행합니다.
6. 이 과정을 새로운 기능을 추가할 때마다 **반복**합니다.
- **Unity Test Framework (UTF):** 에디터 (Edit Mode 또는 Play Mode 사용) 및 대상 플랫폼에서 단위 테스트를 수행할 수 있습니다. 패키지 관리자를 통해 설치할 수 있습니다.
- **UTF 일반 워크플로우:**새로운 테스트 스위트 (Test Assembly) 생성.
- 테스트 (C# 스크립트) 생성 및 로직 추가.
- 테스트 실행 (Test Runner UI 또는 JetBrains Rider 사용).
- Play Mode 테스트를 에디터 또는 독립 실행형으로 추가합니다.
**결론적으로,** 이 발췌문은 Unity 개발 팀에게 깨끗하고 확장 가능한 코드를 작성하기 위한 포괄적인 가이드라인을 제공합니다. 핵심 원칙은 단순성, 일관성, 의미 있는 명명, 적절한 형식, 그리고 코드베이스의 지속적인 개선입니다. 또한, 자동화된 테스트 및 리팩토링의 중요성을 강조하며, 팀원들이 이러한 관행을 채택하고 유지보수하는 데 도움을 줄 수 있는 구체적인 기술과 도구 (예: EditorConfig, UI Toolkit 명명 규칙)를 제시합니다.