224 lines
7.3 KiB
Markdown
224 lines
7.3 KiB
Markdown
|
|
# {프로젝트명} — 코딩 컨벤션
|
||
|
|
|
||
|
|
> **버전**: v1
|
||
|
|
> **작성일**: {날짜}
|
||
|
|
> **담당**: 개발팀장
|
||
|
|
> **적용 범위**: {프로젝트명} 전 C# 코드
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. 네이밍 규칙
|
||
|
|
|
||
|
|
> 아래 규칙은 NerdNavis.Framework 아키텍처 설계안(네이밍 매핑표)을 기반으로 한다.
|
||
|
|
> `My*` 접두사, `u*` 접두사, `Mgr` 접미사는 **전면 금지** (수상한잡화점 패턴 계승 금지).
|
||
|
|
|
||
|
|
| 대상 | 규칙 | 예시 |
|
||
|
|
|------|------|------|
|
||
|
|
| **네임스페이스** | PascalCase | `{ProjectNamespace}.Core` |
|
||
|
|
| **클래스** | PascalCase | `GameManager`, `PlayerController` |
|
||
|
|
| **인터페이스** | `I` + PascalCase | `ISaveProvider`, `INetworkService` |
|
||
|
|
| **메서드** | PascalCase | `LoadData()`, `HandleDamage()` |
|
||
|
|
| **프로퍼티** | PascalCase | `CurrentHp`, `IsGameOver` |
|
||
|
|
| **private 필드** | `_` + camelCase | `_currentHp`, `_isInitialized` |
|
||
|
|
| **const / static readonly** | SCREAMING_SNAKE_CASE | `MAX_HP`, `DEFAULT_TIMEOUT` |
|
||
|
|
| **enum 타입** | PascalCase | `GameState`, `ItemType` |
|
||
|
|
| **enum 값** | PascalCase | `GameState.Playing`, `ItemType.Weapon` |
|
||
|
|
| **지역 변수** | camelCase | `int damage`, `string key` |
|
||
|
|
| **이벤트 구조체(EventBus용)** | PascalCase + `Event` 접미사 | `PlayerDiedEvent`, `StageCompleteEvent` |
|
||
|
|
|
||
|
|
**금지 패턴**:
|
||
|
|
- `My*` 접두사: `MyCoroutine` → `CoroutineRunner` 사용
|
||
|
|
- `u*` 소문자 접두사: `uScrollViewMgr` → `ScrollViewController`
|
||
|
|
- `Mgr` 접미사: `UIAtlasMgr` → `UIAtlasManager`
|
||
|
|
- `Base` 접미사 (추상 클래스): `CustomParserBase` → `abstract class CustomParser`
|
||
|
|
- `Info` 접미사 (데이터 클래스): `GachaGradeInfo` → `GachaGrade`
|
||
|
|
- `Handler` 접미사 (스케줄러): `SchedulHandler` → `GameScheduler`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. 파일 구조
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// 헤더 주석 (선택, 복잡한 파일만)
|
||
|
|
// 파일명: PlayerController.cs
|
||
|
|
// 네임스페이스: {ProjectNamespace}.Core
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEngine;
|
||
|
|
using NerdNavis.Core.Patterns; // Framework 참조는 using 으로만
|
||
|
|
|
||
|
|
namespace {ProjectNamespace}.Core
|
||
|
|
{
|
||
|
|
public class PlayerController : MonoBehaviour
|
||
|
|
{
|
||
|
|
// 1. 직렬화 필드 (Inspector)
|
||
|
|
[SerializeField] private int _maxHp = 100;
|
||
|
|
|
||
|
|
// 2. private 필드
|
||
|
|
private int _currentHp;
|
||
|
|
|
||
|
|
// 3. 프로퍼티
|
||
|
|
public int CurrentHp => _currentHp;
|
||
|
|
|
||
|
|
// 4. Unity 라이프사이클 메서드 (Awake > Start > Update > ...)
|
||
|
|
private void Awake() { }
|
||
|
|
private void Start() { }
|
||
|
|
|
||
|
|
// 5. public 메서드
|
||
|
|
public void TakeDamage(int amount) { }
|
||
|
|
|
||
|
|
// 6. private 메서드
|
||
|
|
private void Die() { }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**규칙**:
|
||
|
|
- 1파일 = 1클래스 (partial class 예외: 에디터 확장, 자동 생성 코드)
|
||
|
|
- 파일명 = 클래스명 (대소문자 포함 일치)
|
||
|
|
- 폴더 경로 ≈ 네임스페이스 구조
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. NerdNavis.Framework 사용 패턴
|
||
|
|
|
||
|
|
### 3.1 MonoSingleton<T> — MonoBehaviour 싱글톤
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// 씬 라이프사이클과 동기화되는 서비스에 사용
|
||
|
|
// Update/OnDestroy 훅이 필요한 경우
|
||
|
|
public class GameManager : MonoSingleton<GameManager>
|
||
|
|
{
|
||
|
|
// [SingletonOption(Persistent = true)] 로 DontDestroyOnLoad 제어
|
||
|
|
protected override void OnAwake()
|
||
|
|
{
|
||
|
|
// 초기화 코드
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 사용
|
||
|
|
GameManager.Instance.StartGame();
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.2 ServiceLocator — 순수 C# 서비스 DI
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// MonoBehaviour와 독립된 서비스, 인터페이스 바인딩, 테스트 Mock 주입 시 사용
|
||
|
|
// Bootstrap 씬에서 등록
|
||
|
|
ServiceLocator.Register<ISaveProvider>(new JsonSaveProvider());
|
||
|
|
ServiceLocator.Register<INetworkService>(new PlayFabNetworkService());
|
||
|
|
|
||
|
|
// 사용처
|
||
|
|
var save = ServiceLocator.Resolve<ISaveProvider>();
|
||
|
|
save.Save(playerData);
|
||
|
|
|
||
|
|
// 테스트 시 Mock 교체
|
||
|
|
ServiceLocator.Register<ISaveProvider>(new MockSaveProvider());
|
||
|
|
ServiceLocator.Clear(); // 테스트 후 정리
|
||
|
|
```
|
||
|
|
|
||
|
|
**주의**: 인터페이스 타입으로만 등록·조회 (구체 타입 바인딩 시 결합도 상승).
|
||
|
|
`Resolve` 실패 시 `ServiceNotRegisteredException` 발생 — silent null 금지.
|
||
|
|
|
||
|
|
### 3.3 CoroutineRunner — 전역 코루틴 관리
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// 키 기반 중복 제어, 일시정지·재시작 지원
|
||
|
|
// MonoBehaviour 없이 코루틴 실행 가능
|
||
|
|
|
||
|
|
// 시작 (키로 중복 방지)
|
||
|
|
CoroutineRunner.Start("LoadData", LoadDataCoroutine());
|
||
|
|
|
||
|
|
// 중지
|
||
|
|
CoroutineRunner.Stop("LoadData");
|
||
|
|
|
||
|
|
// 완료 시 자동 해제
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.4 Log — 중앙 로거
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// Debug.Log 직접 호출 금지 → Log 클래스 사용
|
||
|
|
Log.Info("GameManager", "게임 시작");
|
||
|
|
Log.Warn("DataManager", $"데이터 키 없음: {key}");
|
||
|
|
Log.Error("ServerManager", "서버 연결 실패", exception);
|
||
|
|
|
||
|
|
// 카테고리 필터링 → 빌드 변형별 로그 레벨 제어 가능
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3.5 EventBus — 타입 안전 이벤트
|
||
|
|
|
||
|
|
```csharp
|
||
|
|
// 이벤트 정의 (struct 권장)
|
||
|
|
public struct PlayerDiedEvent
|
||
|
|
{
|
||
|
|
public int PlayerId;
|
||
|
|
public string Cause;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 구독
|
||
|
|
EventBus.Subscribe<PlayerDiedEvent>(OnPlayerDied);
|
||
|
|
private void OnPlayerDied(PlayerDiedEvent e) { /* ... */ }
|
||
|
|
|
||
|
|
// 발행
|
||
|
|
EventBus.Publish(new PlayerDiedEvent { PlayerId = 1, Cause = "Fall" });
|
||
|
|
|
||
|
|
// 구독 해제 (OnDestroy에서 반드시 해제)
|
||
|
|
EventBus.Unsubscribe<PlayerDiedEvent>(OnPlayerDied);
|
||
|
|
```
|
||
|
|
|
||
|
|
**금지**: 문자열 키 이벤트 (`EventBus.Raw` 하위 특수 용도만 허용).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. 금지 사항
|
||
|
|
|
||
|
|
| 금지 항목 | 사유 | 대안 |
|
||
|
|
|-----------|------|------|
|
||
|
|
| **수치 하드코딩** | 수정 시 코드 수정 필요, 기획-개발 분리 파괴 | DataTable 참조 (04_데이터_파이프라인 참조) |
|
||
|
|
| **암호키 평문 하드코딩** | IL2CPP 빌드도 메모리 덤프로 추출 가능 (수상한잡화점 Critical) | 서버 측 키 관리 또는 런타임 유도 (02_기술스택 참조) |
|
||
|
|
| **`Resources.Load` 남용** | 빌드 시 모든 Resources/ 포함 → 빌드 크기 증가 | Addressables |
|
||
|
|
| **문자열 이벤트 키** | 컴파일 타임 검증 불가, 오타 런타임 버그 | `EventBus<TEvent>` 타입 이벤트 |
|
||
|
|
| **`Find` / `FindWithTag` 게임 로직** | 씬 오브젝트 의존, 테스트 불가 | 직접 참조 or ServiceLocator |
|
||
|
|
| **`My*` / `u*` 접두사** | 비표준, 가독성 저하 | 표준 네이밍 규칙(섹션 1) |
|
||
|
|
| **`Assembly-CSharp` 단일 어셈블리** | 컴파일 시간 증가, 의존성 관리 불가 (수상한잡화점 교훈) | asmdef 분리 (01_아키텍처_설계 참조) |
|
||
|
|
| **전역 네임스페이스** | 클래스명 충돌 위험 | `{ProjectNamespace}.*` 체계 |
|
||
|
|
| **`Debug.Log` 직접 호출 (배포 코드)** | 릴리스 빌드 로그 노출 | `Log.Info/Warn/Error` |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Git 커밋 메시지
|
||
|
|
|
||
|
|
```
|
||
|
|
{type}: {summary}
|
||
|
|
|
||
|
|
[optional body]
|
||
|
|
```
|
||
|
|
|
||
|
|
| type | 용도 |
|
||
|
|
|------|------|
|
||
|
|
| `feat` | 신규 기능 추가 |
|
||
|
|
| `fix` | 버그 수정 |
|
||
|
|
| `refactor` | 기능 변경 없는 코드 구조 개선 |
|
||
|
|
| `docs` | 문서 변경 |
|
||
|
|
| `test` | 테스트 추가/수정 |
|
||
|
|
| `chore` | 빌드·설정·의존성 변경 |
|
||
|
|
| `data` | 데이터 테이블 변경 |
|
||
|
|
|
||
|
|
**예시**:
|
||
|
|
```
|
||
|
|
feat: 전투 데미지 계산 서버 검증 구조 추가
|
||
|
|
fix: DataTable 로딩 완료 확인 타이밍 버그 수정
|
||
|
|
refactor: UIManager 씬 전환 로직 분리
|
||
|
|
data: CardList 밸런스 조정 반영 (기획팀 승인)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 변경 이력
|
||
|
|
|
||
|
|
| 버전 | 일자 | 작성자 | 내용 |
|
||
|
|
|------|------|--------|------|
|
||
|
|
| v1 | {날짜} | 개발팀장 | 템플릿 초안. Framework 3축(MonoSingleton·ServiceLocator·EventBus) 패턴 정립 |
|