앱을 재설계하는 방법: 아무것도 바꾸지 마라
요약
디자인 시스템을 활용하여 앱의 시각적 일관성을 확보하면서도, 로직 변경 없이 효율적으로 UI를 재설계하는 방법론을 다룹니다. 타임박싱과 로직 변경 금지 규칙을 통해 개발 리소스를 최소화하며 성공적으로 리프레시를 완료한 사례를 소개합니다.
핵심 포인트
- 기존 로직을 유지하며 시각적/구조적 변경에만 집중하여 리스크 최소화
- 타임박싱(4주)을 적용하여 범위 확장(scope creep) 방지
- 디자인 시스템을 기반으로 한 점진적이고 일관된 UI 업데이트
- 기능 개발과 디자인 리프레시 사이의 균형 잡힌 프로젝트 관리
이렇게 프로젝트가 매끄럽게 진행되는 것을 본 적이 없습니다. 개발자 3명, 파트타임 디자인 헤드(fractional head of design) 1명, 6주라는 시간, 그리고 사실상 프로덕션 버그가 거의 없었습니다. 영웅적인 활약도, 초과 근무도 없었습니다. 그저 탄탄한 계획이 있었을 뿐입니다. 문제를 제한하고, 빌딩 블록(building blocks)을 수작업으로 정교하게 만든 뒤, LLM(대규모 언어 모델)이 안전하게 수작업(manual labour)을 수행하도록 하는 것이었습니다.
제안 (The pitch)
앱은 잘 작동했고 단순했으며, 사용자들은 심지어 '바보라도 쓸 수 있을 정도(idiot-proof)'라고 불렀지만, 솔직히 말해서 기능이 아주 많지는 않았습니다. 우리 중 누구도 그 앱을 진심으로 자랑스럽게 여기지 않았습니다. 디자인은 어디에서도 일관되지 않았고, 각 기능은 그때그때 유행하는 디자인 시스템(design system du jour)으로 구축되었습니다. 모든 수준과 모든 페이지가 고려되고 브랜드 사양(brand spec)에 맞춰 구축된 최신 완전 디자인 시스템은 사용되지 않은 채 선반 위에 조용히 먼지만 쌓여가고 있었습니다.
우리는 경쟁사보다 앞서 나가기 위한 새로운 기능들에 대해 대담한 계획을 가지고 있었지만, 그것들을 배치할 적절한 곳이 없었습니다. 어딘가에 끼워 넣을 수는 있겠지만, 맞지 않고 일관성 없는 디자인에 새 기능을 억지로 구겨 넣은 상태로 시장에 출시하는 것은 어렵습니다.
이 두 가지 문제를 해결하기 위해, 우리의 파트타임 디자인 헤드는 앱 전체의 리프레시(refresh)를 제안했습니다. 즉, 기존에 채택되지 않았던 디자인 시스템을 미래에 대한 명확한 비전과 함께 격상시키는 것이었습니다.
승인 (The buy-in)
디자인은 세련되고 아름다웠으며, 새로운 기능들이 핵심을 이루고 있었고, 추가적인 아이디어들도 덤으로 포함되어 있었습니다. 경영진은 아무런 불만 없이 승인했습니다. '우리가 현재 가진 것'과 '우리가 가질 수 있는 것' 사이의 격차는 보지 않을 수 없을 정도였습니다.
개발자들도 만족했습니다. 누구도 '프랑켄슈타인(Frankenstein)' 같은 앱을 유지보수하는 것을 즐기지 않기 때문입니다. 계획은 '결과적 일관성(eventual consistency)'이었습니다. 페이지를 수정하거나 흐름(flows)을 변경할 때마다 새로운 디자인 시스템으로 업그레이드하는 방식이었습니다. 하지만 그런 방식으로는 진전이 거의 없었습니다. 우리는 마침내 기존 작업을 멈추고 재설계에만 집중할 수 있는 명분을 얻었습니다.
하지만 우리는 이미 이러한 야심 찬 새로운 기능들을 위한 일정(timeframes)에 대해 걱정하고 있었습니다. 우리는 이제 앱 전체를 완전히 새로 고치는 작업(full app refresh)을 먼저 완료해야 하는 상황에 직면했습니다. 지난번 이 작업에 대한 추정치를 산출했을 때 4개월이라는 결과가 나왔는데, 기능적으로 볼 때 우리에게 남은 시간은 마이너스였습니다.
게다가, 제안서(pitch)가 모든 페이지를 다루지는 않았습니다. 경영진의 승인(exec buy-in)을 얻기 위해 앱 전체를 상세하게 목업(mocking up)하는 것은 낭비되는 노력이 될 것이었습니다. 우리는 일부 흐름(flows)에 대해서는 즉흥적으로 대응해야 했습니다.
그럼에도 불구하고 우리는 진행하기로 결정했습니다.
결정 (The call)
이 작업이 진행된다면, 우리는 타임박싱 (time-boxing)을 적용하기로 했습니다. 4주입니다. 4주 동안 가능한 한 많은 것을 구축한 다음, 사용자 수용 테스트 (UAT), 버그 수정, 그리고 출시를 진행합니다. 연장도 없고, 범위 확장 (scope creep)도 없으며, "딱 한 페이지만 더"도 없습니다.
이 계획이 실제로 미친 짓이 되지 않게 만든 단 하나의 규칙은 바로 로직 변경 금지였습니다. 시각적 및 구조적 변경만 허용되었습니다. 우리는 UI를 재구축하면서 동시에 동작(behaviour)까지 재고할 시간이 없었으며, 사용자들을 대상으로 UX 변경 사항을 테스트할 시간도 분명히 없었습니다. 또한 사용자들이 새로운 흐름을 혼란스러워하여 롤백 (rollback)을 해야 하는 위험도 감수할 수 없었습니다. 그것이 바로 고정 범위 프로젝트 (fixed-scope project)가 끝이 없는 프로젝트로 변질되는 전형적인 방식이며, 우리는 그럴 여유가 없었습니다.
계획 (The plan)
우리는 모든 흐름, 모든 페이지, 모든 기능에 대해 티켓 (ticket)을 작성했습니다. 그런 다음 사용량과 가치에 따라 순위를 매기고, 2번의 스프린트 (sprints) 분량의 작업 지점에 선을 그었습니다. 그 선이 우리의 진행 여부 (go/no-go)를 결정하는 기준이었습니다. 만약 우리가 그 선을 넘을 수 있다는 확신을 스스로에게 줄 수 없다면, 시작하지 않았을 것입니다. 스포일러를 하자면, 그 선 아래에 들어오는 작업량이 충분하여 진행할 가치가 있었습니다.
우리는 여전히 공식화된 디자인 시스템 (design system)이 없었고, 앱의 모든 페이지에 대한 디자인도 없었습니다. 우리는 작업을 진행하면서 시스템을 구축해야 하며, 디자인이 없는 페이지들은 그 시스템을 따르도록 만들어야 한다는 것을 알고 있었습니다.
우리는 디자인 전반에 걸쳐 나타나는 컴포넌트(components)들을 골라냈습니다. 공유되는 모든 요소는 재사용을 위해 별도로 추출되어 수작업으로 구축되었으며, 단순히 한 번만 제대로 보이게 만드는 것이 아니라 일관성 (consistency)을 강제하도록 만들어졌습니다. 임의의 부분 요소 (partials)도 없었고, 일회용 HTML도 없었습니다. 카드 레이아웃을 복사해서 "이번 한 번만" 패딩 (padding)을 수정하는 식의 작업도 없었습니다. 복사가 필요하다면, 그것은 컴포넌트 (component)가 되어야 했습니다.
핵심 작업 (The heavy lifting)
우리가 신뢰할 수 있는 기본 컴포넌트들 — 수작업으로 구축되고, 디자인과 일치하며, 팀 전체가 잘 이해하고 있는 것들 — 이 확보되자, 앱의 나머지 부분은 디자인의 문제가 아니라 조립 (assembly)의 문제가 되었습니다. 각 새로운 페이지에 대해 다음과 같이 지시했습니다: "Claude, 여기 현재 버전이 있고, 여기 우리가 원하는 대략적인 모습이 있어. 오직 이 컴포넌트들만 사용해." 때로는 디자인 참조 자료가 있었고, 때로는 없었지만 상관없었습니다. 콘텐츠는 변하지 않았고, 오직 그것이 렌더링 (rendered)되는 시스템만 변했기 때문입니다.
허용된 유일한 동작이 작고 엄격하게 범위가 정해진 빌딩 블록 (building blocks) 세트로 제한되었기에, Claude가 잘못된 것을 만들어낼 여지는 많지 않았습니다. 게다가 우리는 로직 (logic) 변경을 하지 않았기 때문에, Claude가 상황을 엉망으로 만들거나 버그 (bugs)를 유발하는 것도 상당히 어려웠습니다. 입력값에 대한 제약이 출력값에 대한 자율성 (autonomy)을 안전하게 만들어준 것입니다.
결실 (The payoff)
4주 후, 우리는 우리가 약속했던 모든 페이지와 흐름 (flow)을 모두 처리했습니다 — 그리고 그 이상까지도요. Claude는 우리가 디자인을 가지고 있지 않았던 페이지들, 그리고 우리가 정말로 존재한다는 사실조차 잊고 있었던 몇몇 페이지들을 만들어냈으며, 이 모든 것이 하나의 일관된 시스템으로 결합되었습니다. 사용자 수락 테스트 (UAT)에서는 몇 가지 사소한 버그가 발견되었지만, 우리를 주춤하게 만들 정도는 아니었습니다. 우리는 배포할 준비를 마쳤습니다.
반전 (The twist)
출시 전 최종 검토 단계에서 무엇이 채택되고 무엇이 제외되었는지 논의하던 중, 우리 디자이너가 계획에 포함되지 않았던 몇 가지 필수 사항들을 지적했습니다. 그것들은 재설계 (redesign) 작업이 아니라 기능 변경 (feature changes)이었기 때문입니다. 우리는 원래 티켓 (tickets)을 작성할 때 이 사항들을 발견했었고, 의도적으로 새로운 기능 로드맵 (roadmap)보다 우선순위를 낮게 설정해 두었던 것이었습니다.
그것들은 UAT (사용자 수용 테스트)를 위협하거나 일정을 망치지 않을 정도로 충분히 작았기에, 우리는 승낙했습니다. 하지만 그것들이 출시 (rollout)를 가로막게 두지는 않았습니다. 분명히 말씀드리자면, 만약 그것들이 UAT를 무효화하거나 출시 계획 기간보다 더 오래 걸릴 상황이었다면, 저는 그것들을 수행하도록 허락하지 않았을 것입니다. 출시를 미루고 귀중한 리스크 완화 (de-risking) 시간을 잃을 생각은 없었기 때문입니다. 우리는 10% 사용자에게 출시하기 전에 이것들이 완료되기를 기다리지 않았습니다. 단지 100%까지 출시하기 전까지만 준비되어 있으면 되었습니다.
반전의 반전
그때 앱이 혼란을 주지 않도록 기능적 변경이 필요한 가격 정책 변경 (pricing change) 건이 내려왔습니다. 그리고 다음 주라는 엄격한 마감 기한이 있었습니다. 우리는 기존 UI용으로 한 번, 새 UI용으로 또 한 번, 두 번 만드는 것을 원하지 않았기에 출시 과정을 압축했습니다. 10%, 50%, 100%로 단계적으로 진행하는 2주 대신, 며칠 후 10%에서 바로 100%로 넘어갔습니다.
심호흡
우리는 10%에게 출시했고, 내부 커뮤니케이션 (internal comms)을 통해 나머지 회사 구성원들에게 무엇이 다가오고 있는지 알렸습니다. 내부적으로는 기대감이 고조되었지만, 우리 사용자들은 어땠을까요? 아무도 한마디도 하지 않았습니다. 불만도, 의견도 없었습니다.
우리는 추가 기능들과 가격 정책 변경 작업을 마친 후, 외부 커뮤니케이션 (external comms)을 포함하여 모든 사용자에게 출시했습니다. 여전히 내부적으로는 긍정적인 반응뿐이었습니다. 고객 지원 티켓 (support tickets)의 급증도 없었고, 소셜 미디어에서의 언급도 없었습니다. 성공일까요?
일주일 후 우리는 작은 버그 하나를 발견했고 당일에 바로 수정했습니다. 그것이 출시 후 목록의 전부였습니다. 마지막 몇 가지 추가 작업들은 우리가 다음 단계로 넘어가는 동안 백그라운드에서 마무리되었습니다.
성공이었습니다.
저는 수많은 프로젝트를 운영해 왔고 더 많은 프로젝트에 참여해 왔습니다. 이토록 깔끔하게 진행된 경우는 드물었고, 이토록 빠르게 느껴진 적도 없었습니다. 4주의 개발, 1주의 UAT, 1주의 출시 및 몇 가지 추가 기능의 슬쩍 끼워넣기. 초과 근무도, 번아웃 (burnout)도 없이, 그저 탄탄한 계획이 있었을 뿐입니다. 우리는 당면한 과제에서 주의가 분산되지 않도록 했고, Claude가 자율적으로 작업할 수 있도록 안전하고 단순하게 만들었습니다.
제 인생에서 '스프린트 (sprint)'라는 단어를 이토록 문자 그대로 사용해 본 적은 없었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기