quad(Roblox DOMless UI 렌더러) v2 재작성을 위한 .claude/ 계획 구조를 세우고
핵심 아키텍처 결정을 정리함:
- quad v1 / rbvm / tbox / Fusion / Vide / 폐기된 quad2-try 프로토타입 리서치
- Store 책임 분리(base vs provider), process/retract 핸들러 디스패치 모델,
Ref 역할, Slot/Tween 설계 방향 등 핵심 결정 확정
- .claude/{base,research,qa-request,archive,feedback}, question.md, README.md
구조 마련 (code-docker/webmanager 패턴 참고)
- 루트 CLAUDE.md/HUMAN_TODO.md 작성
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.5 KiB
Store 의미론 — 부작용 허용, State 프리미티브 없음
상태: base — 확정된 설계 결정 두 가지. 원본: .claude/initreq/raw-userinput.md
"store는 부작용을 허용함" / "state는 어떻게 구현하는가" 절.
Store는 부작용을 허용하는 게 기본 디자인
부작용 없이(파라메터 패싱만으로) 쓰는 것도 물론 가능하지만, 라이브러리 차원에서 막지 않는다. 부작용 유무는 사용자가 직접 문서화하는 관례로 둔다 — 라이브러리가 순수성을 강제하지 않음.
다만 한 가지는 명확히 구분: 렌더 리턴 위에서 무언가를 observe하는 것은 그냥
부작용이다 (useEffect와 유사한 것으로 문서화). 이건 "허용되는 부작용"이 아니라
"당연히 부작용"이라는 뜻 — 문서화 시 이 경계를 분명히 할 것 (research/ purity-and-effects-plan.md와 연결됨).
별도 State 프리미티브는 만들지 않는다 (기본값)
클래스 자신이 필요한 state가 있으면 그냥 클래스 안에서 Store를 만들면 됨 —
Store는 부분집합으로 쪼개 전달하는 것도 충분히 가능하다고 보기 때문에, 굳이
"단일 값 저장용" State를 별도로 만들 필요성을 못 느낌. 나누고 싶으면 사용자가
알아서 나누면 됨(사용자 자유).
단서: 구현하다가 실제로 State가 있는 게 더 편해지는 지점이 나오면 그때 추가할 수 있음 — 지금은 "필요성이 확인 안 됐다"는 판단이지 "절대 안 만든다"는 확정이 아님. 구현 라운드에서 이 판단이 바뀌면 이 문서를 갱신할 것.
Store 값 설정 문법 — v1 인체공학 유지 (확정)
사용자 확인 완료: Store 값 설정은 __newindex 기반(myStore.key = value)을
그대로 유지 — ProfileService 등 Roblox 생태계에서 이미 익숙한 관용구라 바꿀
이유 없음. 마찬가지로 다음 두 인체공학도 유지:
- 괄호 생략(paren-less) 구조 — 필요 시 커링(
myStore "key"처럼 문자열 하나로 register를 얻는 v1 스타일)을 계속 허용. :체이닝 — 값을 바꾸는 연산에 한해 체이닝 문법 허용(base/ architecture.md의 "함수지향 디폴트,:는 예외적으로만" 원칙과 일치 — 체이닝이 자연스러운 곳 중 하나가 바로 이 store 값 변경).
base/architecture.md의 "복사 구현 지양, 팩토리 함수로 대체" 원칙과 함께 읽을
것 — v1의 문제는 metatable 체이닝으로 매번 새 테이블을 할당하며 "불변 빌더"를
흉내낸 것이었지, : 체이닝 문법 자체나 커링 문법 자체가 아니었음. v2는 문법
인체공학(사용자가 좋아하는 부분)은 유지하되 내부 구현(체이닝이 아니라 팩토리
함수)만 바꾼다.
여러 스토어 값을 묶어 처리하는 것 (dependency array) — 연구 필요
useEffect처럼 여러 store 값을 디펜던시로 묶어 파생값을 계산하고 싶다는
요구가 있음(v1의 myStore "a,b" 콤마-조인 문자열 방식은 폐기 대상 —
base/quad-v1-architecture.md의 "문자열 DSL" 문제점 참고). 단, v1의
:Add/:With/:Tween 같은 이름 붙은(named) 체이닝 연산은 만들지 않기로
확정 — 대신 일반 함수를 받아 처리하는 쪽이 일관적이라는 판단. 구체적인 API
모양(Store.Combine({a,b}, function(a,b) ... end)류)은 아직 미정 —
research/bind-system-plan.md 참고.