XR Library 1.0
Digital Twin 가상공장 개발 용 라이브러리입니다.
주요 기능 및 특징
-
코어 (
UVC.Core)- 애플리케이션의 핵심 로직과
SingletonScene과 같은 디자인 패턴을 지원하여 안정적인 개발 기반을 제공합니다.
- 애플리케이션의 핵심 로직과
-
데이터 관리 (
UVC.Data)- 데이터 모델링 (
UVC.Data.Core.DataObject):DataObject클래스는 애플리케이션에서 사용되는 모든 데이터의 기반이 됩니다.IDataObject인터페이스를 구현하며, 데이터의 고유 ID(Id), 이름(Name), 활성화 상태(Enable) 등 공통 속성을 정의합니다. 이를 상속하여 AGV, 설비 등 다양한 종류의 데이터를 표준화된 방식으로 관리할 수 있습니다. - 데이터 통신: HTTP, MQTT 등 다양한 프로토콜을 지원하는 Wrapper를 제공하여 외부 시스템과의 데이터 연동을 용이하게 합니다.
- 데이터 모델링 (
-
팩토리 (
UVC.Factory)- 동적 객체 생성:
AGVManager와 같이DataObject를 기반으로 씬에 필요한 객체(디지털 트윈, 컴포넌트 등)를 동적으로 생성하고 관리합니다. - 알람 및 재생:
AlarmManager,PlaybackService등을 통해 애플리케이션의 상태 변화에 따른 알람 및 시뮬레이션 재생 기능을 제어합니다.
- 동적 객체 생성:
-
UI 시스템 (
UVC.UI)- 메뉴 & 툴바:
TopMenuController등을 통해 상단 메뉴, 사이드 메뉴, 툴바 등 다양한 형태의 메뉴 시스템을 제공합니다. - 모달 & 알림:
Modal클래스를 통해 Alert, Confirm, Toast 등 사용자에게 정보를 전달하고 상호작용하는 모달 창을 손쉽게 생성합니다. - 목록: 검색, 정렬, 드래그 앤 드롭 기능이 포함된 고성능 목록 UI를 제공합니다.
- 상태 표시:
UILoading로딩 아이콘,Tooltip툴팁 등 사용자에게 현재 상태를 명확하게 전달하는 UI 컴포넌트를 지원합니다. - 커맨드 패턴 (
UVC.UI.Commands):ICommand인터페이스를 통해 UI 이벤트와 비즈니스 로직을 분리하여 코드의 유지보수성을 높입니다.
- 메뉴 & 툴바:
-
유틸리티
- 로깅 (
UVC.Log):log4net을 기반으로 한 강력한 로깅 시스템을 제공하여 디버깅 및 운영 효율성을 높입니다. - 다국어 (
UVC.Locale): 텍스트 기반의 다국어 시스템을 지원하여 손쉽게 글로벌 애플리케이션을 제작할 수 있습니다.
- 로깅 (
사용한 Assets
-
Best MQTT_3.0.4
-
Best HTTP_3.015
-
7Zip lzma LZ4 fastLZ zipgzip brotli multiplatform plugins_2.9.2
-
DOTween Pro_1.0.380
-
Easy Performant Outline 2D 3D URP HDRP and Built-in Renderer_3.6.2
-
In-game Debug Console_1.8.2
-
Shapes2D - Procedural sprites and UI_1.13
-
Newtonsoft.Json_3.2.1
- Window > Package Manager > + > Add packacge by name > com.unity.nuget.newtonsoft-json
-
sqlite3.dll
- sqlite3.dll 파일 Plugins 폴더에 넣기. x86, x64 체크
-
UniTask_2.5.10
- Window > Package Manager > + > Add packacge from git URL > https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask
-
log4uni_1.2.2
- https://github.com/HolyShovelSoft/log4uni 다운로드 압축해제 > Assets > Plugins 폴더에 복사
-
NuGetForUnity_4.5.0
- Window > Package Manager > + > Add packacge from git URL > https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity
- Menu > Nuget > Manage Nuget Packages > MessagePack 3.1.4
아키텍처 (MVVM/MVC)
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ View │◄────│ ViewModel │◄────│ Model │
│ (UXML/USS) │ │ (Presenter) │ │ (Service) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
└── 이벤트 전달 ──────┘
| 레이어 | 책임 | 금지 사항 |
|---|---|---|
| View | 표시/레이아웃, 이벤트 라우팅 | 비즈니스 로직, 상태 보유 |
| ViewModel/Presenter | 상태 관리, 데이터 변환, 바인딩 속성 | Unity API 직접 호출 (테스트 용이) |
| Model/Service | 도메인 로직, 데이터 접근 | UI 참조 |
- MVVM: UI 상태/양방향 동기화가 많을 때
- MVC: 입력 → 도메인 액션 → UI 반영 흐름이 단순할 때
필수 규약
- 파일 선두에
#nullable enable, 모든 참조형에?명시 - 비동기는
UniTask+CancellationToken사용 (Task/코루틴 지양) - 느슨한 결합: 인터페이스/이벤트로 연결
메모리 관리
이벤트 구독/해제
private EventCallback<ClickEvent>? _onClick;
void OnEnable() {
_onClick = OnButtonClick;
_button?.RegisterCallback(_onClick);
}
void OnDisable() {
_button?.UnregisterCallback(_onClick);
}
체크리스트
RegisterCallback<T>↔UnregisterCallback<T>대칭 확인CancellationTokenSource는OnDestroy에서Cancel/Dispose- VisualTreeAsset/USS 동일 리소스 반복 로드 방지 (캐싱)
- 클로저/람다 캡처로 인한 누수 점검
- 오브젝트 풀:
IPoolable.OnRent/OnReturn훅, 반환 시DOTween.Kill()
주석 원칙 (C# XML)
/// <summary>
/// 사용자 데이터를 비동기로 로드합니다.
/// </summary>
/// <param name="userId">사용자 ID.</param>
/// <param name="ct">취소 토큰.</param>
/// <returns>사용자 데이터 또는 null.</returns>
public async UniTask<UserData?> LoadUserAsync(string userId, CancellationToken ct)
- 클래스: 역할/책임/사용 예
- 메서드: 요약 + 파라미터/반환 (복잡 로직만 상세)
- 속성: 한 줄 요약
디자인 패턴 요약
| 패턴 | 사용 시점 |
|---|---|
| DI/Composition Root | 서비스/ViewModel 주입 일원화 |
| Event Aggregator | 컴포넌트 간 느슨한 통신 |
| Command + Undo | UI 액션에 되돌리기 필요 시 |
| Strategy | 정렬/필터 규칙 교체 |
| State/FSM | 모드 전환 (편집/선택/드래그) |
| Factory | 뷰/프리팹 생성 캡슐화 |
| Object Pool | 대량 아이템 재사용 |
| Repository | 데이터 소스 추상화 |
핵심 개발 원칙
- [cite_start]항상 TDD 사이클을 따릅니다: Red → Green → Refactor [cite: 4]
- [cite_start]가장 간단하게 실패하는 테스트를 먼저 작성합니다[cite: 4].
- [cite_start]테스트를 통과시키기 위한 최소한의 코드만 구현합니다[cite: 4].
- [cite_start]테스트가 통과한 후에만 리팩토링합니다[cite: 4].
- [cite_start]구조적 변경과 행위적 변경을 분리하여 Beck의 "Tidy First" 접근 방식을 따릅니다[cite: 4].
- [cite_start]개발 전반에 걸쳐 높은 코드 품질을 유지합니다[cite: 4].
- [cite_start]항상 한 번에 하나의 테스트를 작성하고, 실행시킨 다음 구조를 개선합니다[cite: 8].
TDD 방법론 가이드라인
- [cite_start]작은 기능 증분을 정의하는 실패하는 테스트를 작성하는 것으로 시작합니다[cite: 4].
- [cite_start]행위를 설명하는 의미 있는 테스트 이름을 사용합니다 (예: "ShouldSumTwoPositiveNumbers")[cite: 4].
- [cite_start]테스트 실패를 명확하고 유익하게 만듭니다[cite: 4].
- 테스트를 통과시키기 위한 충분한 코드만 작성합니다. [cite_start]더 이상은 안 됩니다[cite: 4].
- [cite_start]테스트가 통과하면 리팩토링이 필요한지 고려합니다[cite: 5].
- [cite_start]새로운 기능을 위해 사이클을 반복합니다[cite: 5].
- [cite_start]항상 모든 테스트(오래 실행되는 테스트 제외)를 매번 실행합니다[cite: 9].
Tidy First 접근 방식
- [cite_start]모든 변경 사항을 두 가지 유형으로 명확히 분리합니다[cite: 4]:
- [cite_start]구조적 변경 (STRUCTURAL CHANGES): 동작을 변경하지 않고 코드를 재배열하는 것 (이름 변경, 메서드 추출, 코드 이동)[cite: 4].
- [cite_start]행위적 변경 (BEHAVIORAL CHANGES): 실제 기능을 추가하거나 수정하는 것[cite: 4].
- [cite_start]구조적 변경과 행위적 변경을 동일한 커밋에 절대 섞지 않습니다[cite: 4].
- [cite_start]둘 다 필요한 경우 항상 구조적 변경을 먼저 수행합니다[cite: 4].
- [cite_start]변경 전후에 테스트를 실행하여 구조적 변경이 동작을 변경하지 않는지 확인합니다[cite: 4].
코드 품질 표준
-
[cite_start]중복을 철저히 제거합니다[cite: 6].
-
[cite_start]명명 및 구조를 통해 의도를 명확하게 표현합니다[cite: 6].
-
[cite_start]의존성을 명시적으로 만듭니다[cite: 6].
-
[cite_start]메서드를 작고 단일 책임에 집중하도록 유지합니다[cite: 6].
-
[cite_start]상태와 부작용을 최소화합니다[cite: 6].
-
[cite_start]가능한 가장 간단한 솔루션을 사용합니다[cite: 6].
-
리팩토링 가이드라인
-
[cite_start]테스트가 통과할 때만 리팩토링합니다 ("Green" 단계)[cite: 6].
-
[cite_start]확립된 리팩토링 패턴을 올바른 이름으로 사용합니다[cite: 6].
-
[cite_start]한 번에 하나의 리팩토링 변경만 수행합니다[cite: 6].
-
[cite_start]각 리팩토링 단계 후에 테스트를 실행합니다[cite: 6].
-
[cite_start]중복을 제거하거나 명확성을 향상시키는 리팩토링을 우선시합니다[cite: 7].
예시 워크플로우
새로운 기능을 구현할 때:
- [cite_start]기능의 작은 부분에 대한 간단한 실패 테스트를 작성합니다[cite: 7].
- [cite_start]이를 통과시키기 위한 최소한의 코드를 구현합니다[cite: 7].
- [cite_start]테스트가 통과하는지 확인하기 위해 테스트를 실행합니다 (Green)[cite: 7].
- [cite_start]필요한 구조적 변경을 수행합니다 (Tidy First), 각 변경 후에 테스트를 실행합니다[cite: 7].
- [cite_start]구조적 변경을 별도로 커밋합니다[cite: 7].
- [cite_start]다음 작은 기능 증분을 위한 다른 테스트를 추가합니다[cite: 7].
- [cite_start]기능이 완료될 때까지 반복하며, 행위적 변경을 구조적 변경과 별도로 커밋합니다[cite: 7].
[cite_start]이 프로세스를 정확하게 따르며, 항상 빠른 구현보다 깔끔하고 잘 테스트된 코드를 우선시합니다[cite: 7].
C# 특정 지침 (Unity 환경)
- Unity 컴포넌트 라이프사이클:
Awake,Start,Update,FixedUpdate,LateUpdate,OnEnable,OnDisable,OnDestroy와 같은 Unity 컴포넌트 라이프사이클 메서드의 사용 목적을 명확히 이해하고, 각 메서드에서 수행해야 할 작업의 종류를 제한합니다. - 컴포넌트 기반 아키텍처: 각 Unity 컴포넌트가 단일 책임을 갖도록 설계합니다. 관련된 기능은 별도의 컴포넌트로 분리합니다.
- GameObject 및 Transform 접근:
GetComponent<T>()호출을 최소화하고, 필요한 컴포넌트는Awake또는Start에서 캐시하여 성능을 최적화합니다. - Coroutines 및 Events: 비동기 작업에는 코루틴을 사용하되, 완료 시 콜백이나 이벤트를 사용하여 느슨한 결합을 유지합니다. UnityEvent 또는 C# 이벤트/델리게이트를 적극 활용합니다.
- 스크립터블 오브젝트(ScriptableObjects): 데이터와 로직을 분리하기 위해 스크립터블 오브젝트를 활용하여 게임 데이터, 설정, 자원 등을 관리합니다.
- 메모리 관리: 불필요한 GC(Garbage Collection) 할당을 피하기 위해
new키워드 사용을 최소화하고, 컬렉션 사용 시 재사용 가능한 풀링 기법을 고려합니다. - Physics 상호작용: 물리 계산은
FixedUpdate에서 수행하며,Rigidbody를 통해 물리적 상호작용을 처리합니다. - 씬 관리: 씬 로딩 및 언로딩 시 발생하는 의존성 문제를 최소화하기 위해 씬 간의 통신 방법을 명확히 정의합니다.
- 네임스페이스 사용: 코드의 가독성과 충돌 방지를 위해 적절한 네임스페이스를 사용합니다.
- 람다식 및 LINQ: 필요할 때 람다식과 LINQ를 사용하여 코드를 간결하게 만들 수 있지만, 성능 영향을 고려하여 과도한 사용을 피합니다.
- null 체크: Unity 오브젝트에 대한
null체크는 일반 C# 객체와 다르게 동작할 수 있으므로,== null연산자 사용 시 Unity의 오버로드된 연산자를 이해하고 사용합니다. - 에디터 확장: 개발 워크플로우를 개선하기 위해 Custom Editor 또는 EditorWindow와 같은 Unity 에디터 확장을 고려할 수 있습니다.