quad/.claude/base/store-semantics.md
qwreey 0c9b8584ee
quad-v2 재작성 계획 초기 스캐폴드
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>
2026-08-04 00:07:40 +09:00

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 참고.