R3S
R3S는 R3를 사용할 때 반복되는 코드를 Roslyn Source Generator로 자동 생성해
보일러플레이트를 크게 줄여주는 SDK입니다.
핵심은 매우 간단합니다.
-
필드/메서드에 Attribute를 붙인다.
-
Generator가 프로퍼티 노출, 커맨드 실행 메서드, Subscribe 연결 코드를 만든다.
-
런타임 코드는 더 짧고 읽기 쉬워진다.
R3S는 기본적으로 R3를 익힌 프로그래머를 대상으로 제작되었습니다.
R3의 동작 원리와 관련 펑션은 해당 WIKI에서 다루지 않습니다.
왜 사용해야 하나요?
-
압도적인 라인 절약 : 반복적인 래퍼/구독/Dispose 코드를 직접 작성하지 않아도 됩니다.
-
실수 방지 진단 :
R3Gen001~012진단으로 partial, Awake/OnDestroy 호출 누락 등을 컴파일 시점에 잡습니다. -
규칙 기반 일관성 : 네이밍과 라이프사이클 규칙이 고정되어 팀 코드 품질을 유지하기 쉽습니다.
보일러플레이트 절감 비교
동일한 ViewModel 코드 비교
public class PlayerViewModel : MonoBehaviour
{
private readonly ReactiveProperty<int> _hp = new(100);
public ReadOnlyReactiveProperty<int> Hp => _hp;
private readonly ReactiveProperty<int> _mp = new();
public ReactiveProperty<int> Mp => _mp;
private readonly Subject<Unit> _onDead = new();
public Observable<Unit> OnDead => _onDead;
private readonly ReactiveCommand<Unit> _attack = new();
public Observable<Unit> Attack => _attack;
public void ExecuteAttack() => _attack.Execute(Unit.Default);
private CompositeDisposable _disposable = new();
private void Awake()
{
_hp.Subscribe(OnHpChanged).AddTo(_disposable);
}
private void OnHpChanged(int hp) => Debug.Log(hp);
private void OnDestroy() => _disposable.Dispose();
}
[AutoDispose]
public partial class PlayerViewModel : MonoBehaviour
{
[ReactiveProperty]
private ReactiveProperty<int> _hp = new(100);
[ReactiveProperty(ReadOnly = false)]
private ReactiveProperty<int> _mp = new();
[Subject]
private Subject<Unit> _onDead = new();
[ReactiveCommand]
private ReactiveCommand<Unit> _attack = new();
[AutoSubscribe(nameof(_hp))]
private void OnHpChanged(int hp) => Debug.Log(hp);
private void Awake() => R3Awake();
private void OnDestroy() => R3OnDestroy();
}
Generator 자동 생성 코드
// PlayerViewModel.R3Generated.cs (auto-generated)
public partial class PlayerViewModel
{
private CompositeDisposable _disposable = new();
public ReadOnlyReactiveProperty<int> Hp => _hp;
public ReactiveProperty<int> Mp => _mp;
public Observable<Unit> OnDead => _onDead;
public Observable<Unit> Attack => _attack;
public void ExecuteAttack() => _attack.Execute(Unit.Default);
private void R3Awake()
{
_hp.Subscribe(OnHpChanged).AddTo(_disposable);
}
private void R3OnDestroy() => _disposable.Dispose();
}
효율 지표
핵심
총 3가지의 명확한 기능을 제공합니다.
1. 코드를 얇게 유지 : 사용자가 작성하는 코드는 필드 선언 + 어트리뷰트 + 엔트리, 아웃 총 3가지만 남습니다.
매우 간단하고 얇은 컨베션만 따르면 내부의 모든 기능을 100% 활용할 수 있습니다.
2. 명확한 소유권 보장 : Generaotr가 생성한 코드와 사용자 코드가 충돌할 여지가 존재하지 않습니다.
만에 하나, 충돌할 가능성이 발생한 경우에는 R3Gen001 ~ 012 오류가 이를 컴파일 단계에서 감지합니다.
3. 우상향 효율성 : 코드 규모가 커질수록 격차가 매우 크게 벌어집니다.
필드가 10개인 클래스라면 기존 방식은 60 ~ 80 라인, R3S 방식은 20라인 수준이 됩니다.
지원하는 자동화 범위
-
[ReactiveProperty] -
[ReactiveCommand] -
[Subject] -
[AutoSubscribe] -
[AutoDispose]