index

막연한 불안을 구체적 자신감으로 바꾼 방법

· 10min

막연한 불안을 구체적 자신감으로 바꾼 방법


시리즈의 마지막 글이다. 입력 전환부터 시대 풍경, C1 해부, C0 재구현까지 왔다. 남은 질문 — 이 과정에서 뭘 배웠는가.

경쟁사 코드를 읽으면 “베끼기”로 오해받기 쉽다. 하지만 실제로 해보니, 리버스엔지니어링은 내 시스템의 위치를 외부 좌표계로 측정하는 것에 가까웠다. CT처럼 외부에서 빛을 쏴야 내부가 보인다.


1. 내 시스템이 얼마나 완성됐는지 모르고 있었다

C1 리버스엔지니어링 이전에는 내 프로젝트의 artifact 시스템에 막연한 불안감이 있었다. “다른 데는 더 잘 만들었겠지.” “내 구현은 부족할 거야.” 리서치 후 발견한 것은 정반대였다.

점진적 업데이트 도구와 렌더러 위임 패턴은 이미 동작하고 있었고, Confidence routing 로직도 설정만 바꾸면 활성화할 수 있는 상태였다.

Gap 분석이라고 하면 보통 “없는 것 목록”을 떠올린다. 하지만 더 가치 있는 것은 “있는 것 확인”이었다. 경쟁사 코드를 외부 좌표계로 삼아 내 시스템을 측정하고 나니, 막연한 불안이 구체적인 자신감으로 바뀌었다. 그리고 진짜 gap이 몇 개 안 된다는 것을 알았을 때, 그 소수의 gap에 집중할 수 있게 됐다.


2. 프로토콜 선택에는 구체적 이유가 있다

“C1은 왜 JSON 대신 XML을 택했을까?” 이 질문에 처음에는 “구식 기술을 고집한 건가”라고 생각했다. SDK를 열어보고 나서 이해했다.

XML은 태그가 열리는 순간 시맨틱을 전달한다. <artifact type="table">이 도착하면 아직 데이터가 없어도 테이블 스켈레톤을 마운트할 수 있다. JSON은 완전한 문자열이 와야 타입을 판별할 수 있다. skeleton-first rendering이라는 구체적인 UX 요구사항이 XML이라는 프로토콜 선택을 강제한 것이다.

반면 SSE 이벤트별로 완전한 JSON을 보내는 시스템이라면? 파싱 문제가 없으니 XML의 복잡성이 불필요하다. “왜 이 선택을 했는가”뿐 아니라 “왜 이 선택을 하지 않았는가”를 이해하게 된 것이 더 큰 수확이었다.

프로토콜 선택은 취향이 아니라 제약의 함수다. 어떤 UX를 목표로 하느냐가 어떤 데이터 포맷을 쓰느냐를 결정한다.


3. 깊이 파면 철학이 움직인다

C1을 처음 봤을 때는 “우리와 철학이 다르다”고 생각했다.

1-phase 접근 (C1)2-phase 접근 (내 시스템)
LLM 응답을 풍부하게 렌더링구조를 먼저 설계하고, Agent가 데이터를 채움
LLM → XML → 렌더링설계(structure) → 채움(data)
UI 결정권: AIUI 결정권: 빌더 + Agent
실시간 채팅 중심HITL 검토/승인 중심

처음에는 이 차이가 넘을 수 없는 벽이라고 판단했다. “철학이 다르니까 통합은 불가능하다.”

그런데 C1의 내부를 깊이 파고, skeleton-first rendering의 UX 효과를 체감하면서 — 내 설계 방향 자체가 움직이기 시작했다. “AI가 자유롭게 UI를 결정한다”는 게 무책임한 게 아니라, 잘 설계된 가드레일 안에서는 오히려 사용자 경험이 좋아진다는 걸 C1이 증명하고 있었다. 결국 나는 C1의 1-phase 접근을 상당 부분 차용하기 시작했다.

교훈: 처음의 “철학이 다르다”는 판단이 틀린 것은 아니었다. 하지만 그 판단에서 멈추지 않고 깊이 들어간 덕분에, 내 철학 자체가 진화했다. 경쟁사 코드를 읽는 것의 진짜 효과는 gap을 메우는 것이 아니라, 내가 서 있는 위치를 재조정하는 것일 수 있다.


4. 좋은 패턴은 구현체가 달라도 동형(isomorphic)이다

C1의 artifact_diff와 내가 만든 점진적 업데이트 도구는 구현이 완전히 다르다.

  • C1: XML 태그 + LLM 스트리밍 중 diff 파싱.
  • 내 접근: JSON tool call response + 완료 후 반영.

하지만 해결하려는 문제는 동형이다 — “이미 마운트된 artifact를 전체 교체 없이 점진적으로 업데이트하는 방법.”

C1에는 replace, append, remove 세 연산이 있다. 내 시스템에는 appendset만 있고 remove가 없었다. 이것은 C1을 보기 전에는 인식하지 못한 gap이었다. “내 시스템에 없는 것”을 발견하려면, “같은 문제를 다르게 푼 시스템”을 봐야 한다.

여기서 배운 것: 경쟁사 코드를 읽을 때 구현 방식이 아닌 “무슨 문제를 풀려고 했는가”를 먼저 보면, 내 시스템에 적용 가능한 부분이 보인다. 구현은 따라 하지 않아도, 문제 정의는 가져올 수 있다.


5. Reasoning 시각화는 UX가 아니라 감사의 문제다

C1의 thinkComponent가 처음에는 UX 기능처럼 보였다. “에이전트의 사고 과정을 예쁘게 보여주는 것.” 하지만 HITL 중심의 시스템에 놓으면 전혀 다른 의미가 된다.

HITL 시나리오에서 운영자가 에이전트의 결과를 승인/거부할 때, reasoning이 없으면 근거 없이 버튼만 누르는 것이다. 에이전트가 판단 근거를 기록하고 보여주는 것은 UX 개선이 아니라 감사 추적(audit trail)이다 — 규제 대응과 사후 검증의 기반이 된다.

같은 기능(thinkComponent)이 한 시스템에서는 UX이고, 다른 시스템에서는 거버넌스가 된다. 기능의 의미는 그것이 놓이는 맥락에 따라 결정된다.


6. 리버스엔지니어링의 올바른 자세

이번에 실제로 거친 순서가 있다.

먼저 **“이건 뭔가”**부터 시작했다. 패키지 구성, 의존성, API 표면 매핑. C1의 경우 4개 패키지와 htmlparser2, immer, Recharts, TipTap이 핵심이었다.

그 다음 **“쓸 수 있나”**를 판단했다. 블랙박스, React 전용, LLM 제한 — “부적합” 결론이 나왔다. 대부분의 기술 평가는 여기서 끝난다. “안 맞으니까 안 쓰면 돼.”

하지만 가장 가치 있는 건 그 다음이다. “뭘 배울 수 있나.” SDK 바이너리를 열고, 타입 정의에서 설계 의도를 역산하고, 내 시스템과 1

매핑해서 gap 목록을 만들었다. 도구가 맞지 않아도, 그 도구를 만든 사람들의 생각은 배울 수 있다.


맺으며

시리즈는 입력의 전환(Configuration→Conversation)에서 출발해, Generative UI의 풍경을 그리고, C1의 파이프라인을 해부하고, 그것을 오픈소스로 재구현하는 데까지 왔다. 추상에서 구체로, 구체에서 실천으로.

하나만 가져간다면 이것이다: 좋은 리버스엔지니어링은 내 시스템의 현재 위치를 외부 좌표계로 측정하는 것이다. 경쟁사의 기능을 베끼는 게 아니라, 내 시스템의 다음 스텝을 확인하는 것. 그리고 그 과정 자체를 기록으로 남기는 것 — 코드보다 오래 살아남는 것은 “왜 이렇게 만들었는가”라는 맥락이다.