<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>베풀장 블로그</title><description>바이브코딩, AI 개발 도구, 그리고 만드는 사람들의 이야기</description><link>https://blog.bepuljang.co.kr/</link><language>ko-KR</language><atom:link href="https://blog.bepuljang.co.kr/rss.xml" rel="self" type="application/rss+xml"/><item><title>믿게 만드는 소품, 디자인 픽션</title><link>https://blog.bepuljang.co.kr/speculative-design/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/speculative-design/04/</guid><description>아직 존재하지 않는 미래를 어떻게 실감하게 할까요. 영화 소품에서 빌려 온 &apos;디제틱 프로토타입&apos;과 디자인 픽션의 작동 방식, 그리고 이 언어가 광고로 흡수된 과정을 살펴봅니다.</description><pubDate>Mon, 09 Nov 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;미래에 대한 이야기는 잘 실감되지는 않습니다. 예를 들어, ‘2040년에는…’으로 시작하는 문장은 머리로는 이해되어도 몸으로 와닿지 않습니다. 앞선 글에서 고깔의 바깥쪽을 탐색하는 이유를 이야기했지만, 탐색한 미래를 사람들 앞에 꺼내 놓지 못하면 토론은 시작되지 않습니다.&lt;/p&gt;
&lt;p&gt;여기서 등장하는 방법이 디자인 픽션(Design Fiction)입니다. 즉, ‘어떻게 믿게 하는가’에 대한 내용인데, 스페큘러티브 디자인을 위해서는 먼저 디자인을 향유하는 사람들이 믿게 만드는 배경이 필요합니다.&lt;/p&gt;
&lt;h2 id=&quot;영화-소품에서-빌려-온-개념&quot;&gt;영화 소품에서 빌려 온 개념&lt;/h2&gt;
&lt;p&gt;이 말을 널리 알린 것은 SF 작가 브루스 스털링(Bruce Sterling)입니다. 2005년 저서 『Shaping Things』에서 이 표현을 썼고, 이후 ‘변화에 대한 불신을 유예시키기 위해 디제틱 프로토타입을 의도적으로 사용하는 것’이라고 정의했습니다.&lt;/p&gt;
&lt;p&gt;정의에 낯선 표현이 두 개 있습니다. ‘불신의 유예(Suspension of Disbelief)‘는 우리가 영화와 같은 매체를 볼 때 말이 안 되는 걸 알면서도 잠시 믿어 주는 태도를 뜻합니다. ‘디제틱 프로토타입(Diegetic Prototype)‘은 과학과 영화의 관계를 연구한 데이비드 커비(David Kirby)의 용어인데요, 디제시스(Diegesis)는 이야기 속 세계를 뜻합니다. 즉, 이야기 속 세계에서 실제로 작동하는 것처럼 등장하는 미래적인 기술을 말합니다.&lt;/p&gt;
&lt;p&gt;영화 속 인물이 어떤 장치를 대수롭지 않게 쓰는 장면을 떠올려 보면 쉽습니다. 설명도 감탄도 없이 일상의 물건처럼 쓰일 때, 관객은 그 기술이 필요한지, 믿을 만한지를 따지기 전에 그것이 존재하는 세계를 그저 전제로서 받아들이게 됩니다.&lt;/p&gt;
&lt;p&gt;줄리언 블리커(Julian Bleecker)는 2009년의 에세이에서 이 생각을 디자인 실천으로 끌어옵니다. 영화가 소품을 통해 미래를 믿게 만든다면, 디자이너는 소품을 직접 만드는 사람이니 같은 일을 할 수 있다는 것입니다. 즉, 소품을 통해 미래에 대한 상상을 가져온다는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;제품이-아니라-세계의-조각&quot;&gt;제품이 아니라 세계의 조각&lt;/h2&gt;
&lt;p&gt;디자인 픽션의 묘미는 거창한 미래상을 직접 그리지 않는 데 있습니다. 대신 그 세계에서 나왔을 법한 사소한 조각을 만듭니다.&lt;/p&gt;
&lt;p&gt;블리커가 공동 설립한 니어 퓨처 래버러토리(Near Future Laboratory)의 〈TBD Catalog〉가 좋은 예입니다. 기내 쇼핑 카탈로그를 흉내 낸 책자인데요, 미래 기술을 소개하는 대신 그 기술이 이미 흔해진 세상의 상품 목록처럼 꾸몄습니다. 상상의 기술을 조명하는 글이 아니라 일상적인 할인 상품으로 만나는 순간, 관람자는 디자이너가 상상한 미래의 단편을 보다 현실적으로 받아들이고 체감할 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://vimeo.com/107015105&quot;&gt;▶ Vimeo video&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;〈TBD Catalog〉 소개 영상, Near Future Laboratory (2014)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;또 다른 예로 사샤 폴플렙(Sascha Pohflepp)의 2006년 작업 〈Buttons: Blind Camera〉는 실제로 작동하는 물건입니다. 렌즈가 없는 이 카메라는 버튼을 누르면 사진을 찍는 대신, 같은 순간에 다른 누군가가 찍어 공유한 사진을 보여줍니다. 설명을 듣기 전에도 손에 쥐면 사진을 찍는다는 일과 소유한다는 일에 대해 생각하게 됩니다.&lt;/p&gt;
&lt;p&gt;이 사례들에서 공통으로 보이는 원칙은 세 가지 정도로 정리할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;완벽한 작동보다 그럴듯한 맥락을 만듭니다.&lt;/strong&gt; 사용 설명서, 영수증, 고객 불만처럼 일상의 형식을 빌려 옵니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;기술을 주인공으로 두지 않습니다.&lt;/strong&gt; 사람들이 그 기술과 함께 어떻게 살아가는지를 보여줍니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;낯섦을 적당히 남깁니다.&lt;/strong&gt; 너무 황당하면 외면당하고, 너무 익숙하면 그냥 제품 시안으로 읽힙니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;기법보다-질문에-집중하기&quot;&gt;기법보다 질문에 집중하기&lt;/h2&gt;
&lt;p&gt;그런데 이 방법에는 함정이 있습니다. 믿게 만드는 힘은 질문을 던지는 데에만 쓰이지 않기 때문입니다. 질문을 던지고 사변을 이끌어내고자 하는 목적과는 달리 기법이 잘못 사용되면 단순히 미래에 대한 상상을 전시하는 데 그치거나 광고로 끝날 수도 있습니다.&lt;/p&gt;
&lt;p&gt;저널리스트 팀 모건(Tim Maughan)은 2020년 MIT Technology Review 기고에서 이 과정을 추적합니다. 그가 든 예시 중 하나가 2011년 코닝(Corning)의 〈A Day Made of Glass〉입니다. 집과 거리의 모든 유리가 터치스크린이 되는 영상으로, 형식은 디자인 픽션과 닮았지만 비판적인 태도는 찾아보기 어렵다는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=6Cf7IL_eZ38&quot;&gt;▶ 코닝의 홍보 영상 〈A Day Made of Glass〉&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;〈A Day Made of Glass〉, Corning (2011)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;더 얄궂은 사례도 있습니다. 슈퍼플럭스(Superflux)의 2015년 단편 〈Uninvited Guests〉에서 노인은 자신을 감시하는 스마트 기기들을 따돌립니다. 모건은 2019년 아마존 에코 광고가 이 영화와 닮았다고 지적하는데요, 정반대로 광고 속 기기는 환영받습니다. 같은 문법이 정반대의 메시지를 전하는 것입니다.&lt;/p&gt;
&lt;p&gt;구별 기준은 결국 그 소품이 무엇을 남기느냐일 것입니다. 보고 나서 ‘갖고 싶다’가 남는다면 광고이고, ‘정말 이렇게 살아도 되는 걸까’가 남는다면 질문입니다. 물론 그 사이에는 넓은 회색 지대가 있습니다. 그러나 손바닥과 손등이 가깝지만 같아질 수는 없듯이, 비슷해 보여서 혼란스러울 수 있지만 본연의 목적인 미래에 대한 질문과 사변에 집중한다면 함정에 빠지지 않을 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 잠시 이론을 내려놓고 실제 작업들을 살펴봅니다. 시체로 충전하는 배터리와 파리를 잡아먹는 시계 같은 조금 기묘한 사물들이 등장합니다.&lt;/p&gt;
&lt;h2 id=&quot;참고한-자료&quot;&gt;참고한 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tim Maughan, &lt;a href=&quot;https://www.technologyreview.com/2020/02/21/905817/how-big-tech-hijacked-its-sharpest-funniest-critics/&quot;&gt;How big tech hijacked its sharpest, funniest critics&lt;/a&gt;, MIT Technology Review (2020)&lt;/li&gt;
&lt;li&gt;Julian Bleecker, “Design Fiction: A Short Essay on Design, Science, Fact and Fiction” (2009)&lt;/li&gt;
&lt;li&gt;Bruce Sterling, 『Shaping Things』 (2005)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>What is Speculative Design</category><category>스페큘러티브 디자인</category><category>디자인 픽션</category><category>프로토타입</category><category>미래</category></item><item><title>미래에 대한 사실 판단과 가치 판단</title><link>https://blog.bepuljang.co.kr/speculative-design/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/speculative-design/03/</guid><description>스페큘러티브 디자인을 설명할 때 빠지지 않는 미래의 고깔은 원래 미래학의 도구였습니다. 도표의 내력을 따라가며 &apos;선호되는 미래&apos;가 다른 범주와 어떻게 다른지 살펴봅니다.</description><pubDate>Sun, 08 Nov 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;이 시리즈의 첫 글에서 미래의 고깔을 소개했습니다. 현재에서 뻗어 나가는 미래를 유망한(Probable), 그럴듯한(Plausible), 가능성이 있는(Possible) 미래로 나누고, 그중 선호되는(Preferred) 미래로 나아가자고 제안하는 도표였지요. 스페큘러티브 디자인을 설명하는 자료라면 거의 빠지지 않는 그림이기도 합니다.&lt;/p&gt;
&lt;p&gt;이 도표는 디자이너가 만든 것이 아닙니다. 미래학(Futures Studies)에서 먼저 쓰던 도구이고, 그 내력을 살펴보면 첫 글에서 간단히 지나갔던 부분을 조금 더 정확하게 다시 쓸 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;미래의-고깔-그-내력&quot;&gt;미래의 고깔, 그 내력&lt;/h2&gt;
&lt;p&gt;호주의 미래학자 조지프 보로스(Joseph Voros)가 정리한 내력에 따르면, 1978년 노먼 헨치(Norman Henchey)는 미래를 가능한, 그럴듯한, 유망한, 선호되는 미래의 네 가지로 나누었습니다. 1990년에는 찰스 테일러(Charles Taylor)가 시간 축 위에서 범위가 넓어지는 ‘그럴듯함의 고깔(Cone of Plausibility)‘을 더했습니다. 우리가 아는 형태에 가까운 그림은 1994년 트레버 핸콕(Trevor Hancock)과 클레멘트 베졸드(Clement Bezold)가 헨치의 분류를 고깔로 옮기면서 나옵니다. 보로스는 2000년 무렵부터 이를 자신의 포사이트 작업에 쓰기 시작해 범주를 더 늘려 나갔습니다. 이렇게 여러 사람의 손을 거치며 우리가 아는 고깔이 만들어진 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;현재에서 시간이 흐를수록 넓어지는 고깔 도표. 가운데 선이 예상되는 미래이고, 안쪽부터 유망한, 그럴듯한, 가능한, 터무니없는 미래로 나뉜다. 선호되는 미래는 여러 구역에 흩어진 점들로 표시되어 있다.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;780&quot; src=&quot;https://blog.bepuljang.co.kr/_astro/futures-cone-detail.CQsh-K0k_Z1XEjpN.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Hancock &amp;#x26; Bezold(1994)와 Joseph Voros의 도표를 바탕으로 다시 그린 미래의 고깔&lt;/small&gt;&lt;/p&gt;
&lt;h2 id=&quot;얼마나-그럴-법한가&quot;&gt;얼마나 그럴 법한가&lt;/h2&gt;
&lt;p&gt;위를 토대로 그림을 자세히 살펴보면 이 도식의 정체가 분명히 드러납니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;예상되는(Projected):&lt;/strong&gt; 지금까지의 흐름을 그대로 연장한, 현 시점에서 그대로 예측되는, 이른바 기본값 미래입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;유망한(Probable):&lt;/strong&gt; 변화 없이도 일어날 ‘법한’ 미래입니다. 주로 현재의 추세를 근거로 삼습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그럴듯한(Plausible):&lt;/strong&gt; 지금 우리가 세상을 이해하는 방식에 비추어 일어날 ‘수 있는’ 미래입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;가능한(Possible):&lt;/strong&gt; 아직 우리에게 없는 지식에 따라 일어날 ‘가능성이 있는’ 미래입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;터무니없는(Preposterous):&lt;/strong&gt; 지금으로서는 불가능하다고 여겨지는 미래입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;안쪽으로 갈수록 현 시점의 추세에서 확실한 편이고 바깥으로 갈수록 확률이 낮아 보이는 미래가 됩니다. 이 다섯 범주는 결국 우리가 어떤 미래가 얼마나 그럴듯한지를 두고 구분하는 것이 됩니다.&lt;/p&gt;
&lt;p&gt;주의할 점은 이 판단 역시 지금의 우리가 내리는 것이라는 사실입니다. 어느 시대의 터무니없는 미래가 다음 시대의 일상이 되는 일은 드물지 않습니다. 그러니 고깔의 경계는 세계의 객관적인 구획이라기보다 우리 상상력의 현재 위치를 그려 놓은 것에 가깝습니다.&lt;/p&gt;
&lt;h2 id=&quot;선호는-다른-축에-있다&quot;&gt;선호는 다른 축에 있다&lt;/h2&gt;
&lt;p&gt;이제 ‘선호되는 미래’를 볼 차례입니다. 여기서 이 도표의 가장 중요한 지점이 나옵니다. 보로스는 위의 범주들이 대체로 무엇이 일어날 법한지에 대한 인지적 판단인 데 비해, ‘선호되는 미래’는 무엇이 일어나야 하는지에 대한 가치 판단이라고 말합니다.&lt;/p&gt;
&lt;p&gt;그래서 선호되는 미래는 고깔 안의 특정 구역에 고정되어 있지 않습니다. 누군가에게는 기본값 미래가 가장 좋을 수 있고, 다른 누군가에게는 오늘 터무니없어 보이는 미래가 가장 바람직할 수 있습니다. 사람의 가치관이 다양한 만큼 선호는 고깔 전체에 걸쳐 나타날 수 있는 것이지요. 그 반대편에는 일어나지 말아야 할 미래도 있습니다.&lt;/p&gt;
&lt;p&gt;시리즈 첫 글에서 개념을 다루면서 컨셉 디자인은 현실에 나타날 가능성에 방점을 찍는 반면, 스페큘러티브 디자인은 선호되는(Preferred) 미래를 이끄는 것으로 설명한 바 있습니다. 이 설명만으로는 그 구분이 혼란스러울 수 있지만, 이 글에서 다룬 두 가지 축으로 대비해보면 차이가 분명해집니다: 하나는 가능성(Probability)의 축 위에 있고 다른 하나는 가치의 축 위에 있으니, 현재를 통해 미래를 보여준다는 점이 비슷하게 여겨질 수 있지만 분명히 다른 목적과 관심을 가지고 있다는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;그래서-달라지는-것&quot;&gt;그래서 달라지는 것&lt;/h2&gt;
&lt;p&gt;이 구분은 말장난처럼 보이지만 실무적인 차이를 만듭니다. 미래를 이야기하는 회의에서 ‘이건 될 것 같다’와 ‘이렇게 되어야 한다’는 쉽게 뒤섞이기 때문입니다.&lt;/p&gt;
&lt;p&gt;‘앞으로 모든 상담은 AI가 맡게 될 겁니다’라는 문장은 전망처럼 들립니다. 하지만 그 안에는 그렇게 되는 것이 좋다는 판단이 슬며시 함께 들어가 있는 경우가 많습니다. 전망의 형식을 빌리면 가치 판단은 토론 없이 통과합니다. 이미 정해진 일은 찬성과 반대의 대상이 아니라, 디자인의 전제, 환경이 되어 버리기 때문입니다.&lt;/p&gt;
&lt;p&gt;미래의 고깔은 두 질문을 분리하게 해 줍니다. 그것은 얼마나 일어날 법한가. 그리고 별개로, 그것은 일어나야 하는가. 가능성이 낮아도 추구할 미래가 있고, 가능성이 높아도 막아야 할 미래가 있습니다. 스페큘러티브 디자인이 고깔의 바깥쪽을 자주 드나드는 것은 황당함을 즐겨서가 아니라, 기본값이 유일한 미래처럼 보이는 착시를 깨기 위해서라고 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;그렇다면 아직 오지 않은 미래를 어떻게 사람들 앞에 실감 나게 꺼내 놓을 수 있을까요. 다음 글에서는 그 방법으로 자주 쓰이는 디자인 픽션을 살펴봅니다.&lt;/p&gt;
&lt;h2 id=&quot;참고한-자료&quot;&gt;참고한 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Joseph Voros, &lt;a href=&quot;https://thevoroscope.com/2017/02/24/the-futures-cone-use-and-history/&quot;&gt;The Futures Cone, use and history&lt;/a&gt; (2017)&lt;/li&gt;
&lt;li&gt;Trevor Hancock, Clement Bezold, “Possible futures, preferable futures”, Healthcare Forum Journal (1994)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>What is Speculative Design</category><category>스페큘러티브 디자인</category><category>미래의 고깔</category><category>미래학</category><category>포사이트</category></item><item><title>답 대신 질문을 만드는 디자인</title><link>https://blog.bepuljang.co.kr/speculative-design/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/speculative-design/02/</guid><description>스페큘러티브 디자인은 어디에서 왔을까요. 1990년대 비판적 디자인과 던 &amp; 라비의 A/B 선언을 따라가며, 문제 해결이라는 디자인의 전제를 왜 의심하게 되었는지 살펴봅니다.</description><pubDate>Fri, 06 Nov 2026 01:25:06 GMT</pubDate><content:encoded>&lt;p&gt;앞선 글에서 스페큘러티브 디자인을 ‘사회와 시대 전반을 목적물로 두고 더 나은 길을 상상하고 제안하는 디자인’으로 소개했습니다. 그런데 이 개념이 처음부터 그런 큰 포부를 품고 등장한 것은 아닙니다. 출발점에는 그보다 훨씬 까칠한 질문이 있었는데요, 바로 ‘디자인은 정말 문제를 해결하기만 하면 되는가’라는 물음입니다.&lt;/p&gt;
&lt;p&gt;디자이너에게 문제 해결은 거의 정체성에 가까운 말입니다. 불편을 찾아내고, 원인을 분석하고, 더 나은 형태를 제안합니다. 저 역시 이 시리즈 바깥의 글에서 UX디자인을 그런 관점으로 이야기해 왔습니다. 그런데 이 틀에는 눈에 잘 띄지 않는 전제가 하나 숨어 있습니다. 문제가 이미 올바르게 정의되어 있고, 지금의 세계가 그 해결책을 받아들일 만한 전제 조건을 갖추고 있다는 믿음이지요.&lt;/p&gt;
&lt;h2 id=&quot;전자제품을-의심한-디자이너들&quot;&gt;전자제품을 의심한 디자이너들&lt;/h2&gt;
&lt;p&gt;이 전제에 정면으로 질문을 던진 사람들이 영국의 앤서니 던(Anthony Dunne)과 피오나 라비(Fiona Raby)입니다. 이들은 1990년대 중반부터 ‘비판적 디자인(Critical Design)‘이라는 개념을 다듬어 왔고, 던은 1999년 『Hertzian Tales』에서 전자제품을 미학적 경험과 비판의 대상으로 다루었습니다.&lt;/p&gt;
&lt;p&gt;여기서 ‘비판적’이라는 말은 흠을 잡는다는 뜻이 아닙니다. 어떤 제품이 은연중에 전제하는 생활 방식과 가치를 드러내어 다시 생각하게 만든다는 뜻에 가깝습니다. 우리가 쓰는 전자제품은 단지 기능을 수행하는 데서 끝나지 않고, 어떻게 살아야 하는지에 대한 생각까지 함께 실어 나르기 때문입니다.&lt;/p&gt;
&lt;p&gt;그 뿌리를 더 거슬러 올라가면 1970년대 이탈리아의 래디컬 디자인과 안티 디자인을 만나게 됩니다. 에토레 소트사스(Ettore Sottsass)의 1973년 작업 〈The Planet as a Festival〉이 그 앞선 시도로 자주 언급되는데요, 당장 만들 수 있는 물건이 아니라 다른 세계의 상을 그려 보이는 일 역시 디자인이 할 수 있음을 보여준 사례입니다.&lt;/p&gt;
&lt;h2 id=&quot;ab-두-개의-목록&quot;&gt;A/B, 두 개의 목록&lt;/h2&gt;
&lt;p&gt;이 생각을 가장 간결하게 정리한 것이 던과 라비의 ‘A/B’라는 목록입니다. 2013년에 낸 『Speculative Everything』의 서문에서도 이 책이 그 목록에서 출발했다고 밝히고 있습니다. 왼쪽 A에는 익숙한 디자인을, 오른쪽 B에는 그들이 제안하는 디자인을 나란히 놓는 형식입니다.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;/th&gt;&lt;th&gt;B&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;긍정적(Affirmative)&lt;/td&gt;&lt;td&gt;비판적(Critical)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;문제 해결(Problem solving)&lt;/td&gt;&lt;td&gt;문제 발견(Problem finding)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;답을 제공한다(Provides answers)&lt;/td&gt;&lt;td&gt;질문을 던진다(Asks questions)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;생산을 위한 디자인(Design for production)&lt;/td&gt;&lt;td&gt;토론을 위한 디자인(Design for debate)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;사게 만든다(Makes us buy)&lt;/td&gt;&lt;td&gt;생각하게 만든다(Makes us think)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 표를 볼 때 조심할 점이 있습니다. B가 옳고 A가 틀렸다는 주장으로 읽기 쉽지만, 이 목록은 비교를 통해 디자인의 가능한 범위를 넓혀 보려는 도구에 가깝습니다. 세상에는 여전히 잘 작동하는 문손잡이가 필요하고, 그 일은 A의 영역입니다. 다만 디자인이 할 수 있는 일이 A뿐이라고 여기는 순간, 우리는 어떤 질문은 아예 꺼낼 수 없게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;비판에서-추측으로&quot;&gt;비판에서 추측으로&lt;/h2&gt;
&lt;p&gt;그렇다면 비판적 디자인과 스페큘러티브 디자인은 어떻게 다를까요. 둘의 경계는 깔끔하지 않고 연구자마다 조금씩 다르게 구분하는데요, 스페큘러티브 디자인을 비판적 디자인의 한 갈래로 보고 그중 미래 제안에 초점을 맞춘 작업으로 설명하는 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;관점이 비슷하지만 시제의 차이를 들어 이해할 수 있습니다. 비판적 디자인이 ‘지금의 이 물건은 어떤 세계를 전제하고 있는가’를 묻는다면, 스페큘러티브 디자인은 ‘만약 세계가 달라진다면 어떨까’를 묻는다는 것입니다. ‘What if’라는 짧은 말이 이 작업의 문법이 되는 이유입니다.&lt;/p&gt;
&lt;p&gt;던과 라비는 이 ‘추측’이 ‘예측’과 다르다는 점을 분명히 합니다. 맞히는 것을 목표로 두지 않겠다는 것입니다. 대신 여러 가능성을 눈앞에 꺼내어 어떤 미래를 원하고 원하지 않는지를 함께 토론하게 만들고, 그렇게 현실이 고정된 것이 아니라 바꿀 수 있는 것이며, 바람직한 미래는 무엇인지, 그리고 그 미래를 맞이하기 위해서 어떤 점들이 개선될 수 있는지를 논의하고자 합니다.&lt;/p&gt;
&lt;h2 id=&quot;쓸모없음의-쓸모&quot;&gt;쓸모없음의 쓸모&lt;/h2&gt;
&lt;p&gt;이렇게 보면 스페큘러티브 디자인의 결과물이 왜 그토록 쓸모없어 보이는지도 이해가 됩니다. 디자인에 대한 일반적인 인식과 달리 살 수 없고, 양산되지 않으며, 때로는 불쾌하기까지 합니다. 예술과의 경계도 모호하기 때문에, 그것을 과연 디자인이라 부를 수 있느냐는 비판도 꾸준히 따라다닙니다.&lt;/p&gt;
&lt;p&gt;하지만 이것은 디자인의 개념과 본질이 확장되어 오고 있음에 대한 이해 부족에서 비롯되는 시각입니다. 디자인의 본질은 꾸준히 ‘판매’를 벗어나 개념적이고 사변적인 방향으로 발전해왔습니다. 그 가운데 바뀌지 않았던 것은 오로지 ‘목표 지향적’으로 ‘환경과 행동을 기획하고 변화를 유도한다’는 점이었지요.&lt;/p&gt;
&lt;p&gt;결국 팔아야 하는 물건은 사람들이 원하는 것을 넘어서기 어렵습니다. 그래서 시장의 바깥으로 나가야만 ‘사람들이 원해야 할 것은 무엇인가’라는 질문을 꺼낼 수 있고, 디자인은 그때 비로소 문제를 푸는 도구에서 문제를 다시 쓰는 도구가 됩니다. 즉, ‘판매’조차도 목표에 맞지 않는다면 후순위로 두는, 환경과 행동의 기획과 개선이라는 목표를 최우선으로 하는 디자인의 본성을 그대로 따르고 있다는 것입니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 이러한 이해를 바탕으로 앞서 간단히 소개했던 ‘미래의 고깔’을 다시 보고자 합니다.&lt;/p&gt;
&lt;h2 id=&quot;참고한-자료&quot;&gt;참고한 자료&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Anthony Dunne, 『Hertzian Tales』 (1999)&lt;/li&gt;
&lt;li&gt;Anthony Dunne, Fiona Raby, 『Speculative Everything』 (MIT Press, 2013)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>What is Speculative Design</category><category>스페큘러티브 디자인</category><category>비판적 디자인</category><category>디자인 역사</category><category>던 앤 라비</category></item><item><title>몇 달 뒤의 나를 위해 — 위키와 기록, 그리고 팀</title><link>https://blog.bepuljang.co.kr/about-umtri/05/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/about-umtri/05/</guid><description>나무만으로는 남지 않는 &apos;왜 이렇게 만들었는지&apos;를 위키에 남기는 방법, 쌓인 기록을 돌아보는 방법, 그리고 팀과 함께 쓰는 방법을 프롬프트 예시와 함께 정리합니다.</description><pubDate>Wed, 30 Sep 2026 15:58:04 GMT</pubDate><content:encoded>&lt;p&gt;프로젝트를 몇 달 하다 보면 이런 질문이 생깁니다.&lt;/p&gt;
&lt;p&gt;“결제는 왜 이렇게 복잡하게 되어 있지?”
“이 방법 예전에 한 번 해 봤던 것 같은데, 왜 그만뒀더라?”
“이 기능은 언제 추가했지?”&lt;/p&gt;
&lt;p&gt;나무는 &lt;strong&gt;무엇이 어디에 있는지&lt;/strong&gt;는 잘 보여 주지만, &lt;strong&gt;왜 그렇게 만들었는지&lt;/strong&gt;까지는 담지 못합니다. 마지막 편에서는 그 “왜”를 남기는 &lt;strong&gt;위키&lt;/strong&gt;와, 그동안 쌓인 기록을 돌아보는 방법, 그리고 여러 사람이 함께 쓰는 방법을 다룹니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;몇-달-뒤의-나는-남입니다&quot;&gt;몇 달 뒤의 나는 남입니다&lt;/h2&gt;
&lt;p&gt;직접 만든 프로젝트라도 몇 주만 지나면 낯설어집니다. AI가 코드를 써 준 바이브코딩이라면 더 그렇습니다. 내가 한 줄 한 줄 쓴 게 아니니까요.&lt;/p&gt;
&lt;p&gt;AI도 마찬가지입니다. 새 대화를 열 때마다 AI는 프로젝트의 지난 사정을 전혀 모릅니다. 그래서 예전에 문제가 있어서 버린 방법을 다시 제안하기도 합니다.&lt;/p&gt;
&lt;p&gt;이걸 막는 방법은 하나입니다. &lt;strong&gt;적어 두는 것.&lt;/strong&gt; 다만 사람이 매번 정리하기는 어려우니, AI에게 적게 하고 사람은 읽기만 하는 구조를 만들면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;위키-프로젝트의-백과사전&quot;&gt;위키: 프로젝트의 백과사전&lt;/h2&gt;
&lt;p&gt;Umtri의 &lt;strong&gt;위키&lt;/strong&gt;는 프로젝트의 백과사전입니다. 각 기능이 어떻게 동작하는지, 꼭 지켜야 할 규칙은 무엇인지, 프로젝트 안에서 쓰는 말이 무슨 뜻인지를 담습니다.&lt;/p&gt;
&lt;p&gt;위키는 &lt;strong&gt;AI가 쓰고, 사람은 읽습니다.&lt;/strong&gt; 배지 화면의 Overall 통계에서 &lt;strong&gt;Wiki&lt;/strong&gt; 숫자를 누르면 위키가 열립니다.&lt;/p&gt;
&lt;h3 id=&quot;목차부터-세우기&quot;&gt;목차부터 세우기&lt;/h3&gt;
&lt;p&gt;위키는 처음부터 차례로 읽으면 프로젝트 전체를 파악할 수 있게 짜여 있습니다. 맨 위에 &lt;strong&gt;개요&lt;/strong&gt;가 있고, 그 아래에 장(개념·구성·운영·용어 등), 그 아래에 항목이 놓입니다. 책처럼 번호가 붙습니다.&lt;/p&gt;
&lt;p&gt;처음에는 목차만 세워 달라고 하세요. Umtri는 프로젝트 종류(웹 서비스, 앱 서비스, 라이브러리)별로 권장 목차를 갖고 있어서, AI가 그걸 참고해 세웁니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app 위키를 웹 서비스 목차로 세워줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;지금 코드에서 확실히 알 수 있는 내용부터 채우고, 모르는 건 비워 둬.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“모르는 건 비워 둬”가 중요합니다. 추측으로 채운 문서는 틀린 줄도 모르고 믿게 되기 때문입니다.&lt;/p&gt;
&lt;h3 id=&quot;결정을-내릴-때마다-적게-하기&quot;&gt;결정을 내릴 때마다 적게 하기&lt;/h3&gt;
&lt;p&gt;위키가 진짜 힘을 발휘하는 건 &lt;strong&gt;결정을 내린 순간&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;쿠폰을 결제할 때가 아니라 주문을 만들 때 한 번만 적용하기로 했어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;그렇게 정한 이유(결제를 다시 시도하면 두 번 적용되는 버그)까지 위키에 적어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;처음엔 주문 상태를 1초마다 확인했는데, 서버 부담 때문에 5초로 바꿨어. 위키에 반영해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 적어 두면, 몇 달 뒤 누군가 “쿠폰을 결제 단계로 옮기면 더 깔끔하지 않을까?”라고 할 때 위키가 대답해 줍니다.&lt;/p&gt;
&lt;h3 id=&quot;위키를-읽고-시작하게-하기&quot;&gt;위키를 읽고 시작하게 하기&lt;/h3&gt;
&lt;p&gt;새 작업을 시작할 때 AI가 위키부터 읽게 하면, 지난 결정을 모르고 엇나가는 일이 줄어듭니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app 위키에서 결제 관련 문서를 읽고, 그 규칙을 지키면서 환불 기능을 추가해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;위키를 처음부터 읽고, 이 프로젝트를 처음 보는 사람에게 설명하듯 요약해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;위키는-일기가-아닙니다&quot;&gt;위키는 일기가 아닙니다&lt;/h3&gt;
&lt;p&gt;위키에는 “오늘 이걸 했다”를 덧붙이지 않습니다. &lt;strong&gt;지금 어떻게 되어 있는지&lt;/strong&gt;를 적는 곳이라, 내용이 바뀌면 옛 문장을 고쳐 씁니다. 대신 고칠 때마다 이전 내용이 &lt;strong&gt;리비전&lt;/strong&gt;으로 남아서, 언제든 예전 모습을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;그래서 위키를 열면 항상 “지금의 정답”이 있고, 지나온 과정은 리비전과 나무의 기록이 맡습니다. 이 규칙은 Umtri가 AI에게 알려 주니, 여러분이 따로 신경 쓸 필요는 없습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;쌓인-기록-돌아보기&quot;&gt;쌓인 기록 돌아보기&lt;/h2&gt;
&lt;p&gt;앞 편들에서 한 일들이 쌓이면 이런 걸 볼 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시간 슬라이더&lt;/strong&gt; — 프로젝트가 자라 온 순서를 처음부터 다시 재생합니다. 시즌을 골라 한 단계만 따로 볼 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;잎마다 붙은 커밋 기록&lt;/strong&gt; — 잎을 누르면 그 부품이 언제, 어떤 작업으로 바뀌어 왔는지 보입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;버그 기록&lt;/strong&gt; — 해결된 버그에는 “실제로 무엇을 했는지”가 남아 있습니다. 비슷한 문제가 다시 생기면 여기부터 찾아보세요.&lt;/p&gt;
&lt;p&gt;AI에게 물어봐도 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app에서 지난 한 달 동안 무엇이 바뀌었는지 정리해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;주문 쪽에서 예전에 비슷한 버그가 있었는지 찾아보고, 그때 어떻게 고쳤는지 알려줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;해결된 버그가 가장 많이 붙어 있는 곳이 어디야? 구조를 손봐야 할 곳이 있을까?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;팀과-함께-쓰기&quot;&gt;팀과 함께 쓰기&lt;/h2&gt;
&lt;p&gt;혼자 쓰던 배지를 다른 사람과 함께 볼 수도 있습니다. &lt;strong&gt;Settings → Organization&lt;/strong&gt;에서 팀을 만들고, 이메일로 팀원을 초대합니다.&lt;/p&gt;
&lt;p&gt;팀원의 역할은 세 가지입니다.&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;역할&lt;/th&gt;&lt;th&gt;할 수 있는 일&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Viewer&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;나무·버그·기록·위키 보기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Editor&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;위 내용 + 나무·버그·위키 고치기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Owner&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;위 내용 + 배지 설정, 팀원 초대·관리&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;기획자나 디자이너처럼 코드를 보지 않는 동료에게는 Viewer로 초대해 보세요. 나무와 위키만으로도 “지금 어디까지 만들어졌는지”를 파악할 수 있습니다. 새로 합류한 개발자에게는 위키를 처음부터 읽어 보라고 하면 됩니다.&lt;/p&gt;
&lt;p&gt;팀원의 AI도 같은 나무와 위키를 읽습니다. 누가 어떤 AI로 작업하든, 모두 같은 지도를 보고 일하게 됩니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;베타 기간에는 한 팀에서 편집할 수 있는 사람(Owner·Editor)이 3명까지입니다. Viewer는 제한이 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;시리즈를-마치며&quot;&gt;시리즈를 마치며&lt;/h2&gt;
&lt;p&gt;이 시리즈에서는 이런 순서로 Umtri를 살펴봤습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;프로젝트를 나무로 본다는 것&lt;/li&gt;
&lt;li&gt;AI와 연결하기&lt;/li&gt;
&lt;li&gt;옮겨심기와 시즌&lt;/li&gt;
&lt;li&gt;계획하고, 기록하고, 버그 다루기&lt;/li&gt;
&lt;li&gt;위키와 기록, 그리고 팀&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;바이브코딩의 장점은 속도입니다. 그 속도가 몇 달 뒤에도 유지되려면 “지금 이 프로젝트가 어떤 모습인지”, “왜 이렇게 되었는지”를 언제든 알 수 있어야 합니다. Umtri는 그걸 사람이 따로 정리하지 않아도, AI가 일하면서 함께 남기도록 돕습니다.&lt;/p&gt;
&lt;p&gt;아직 직접 해 보지 않았다면 &lt;a href=&quot;https://app.umtri.io/demo&quot;&gt;데모&lt;/a&gt;부터 열어 보세요. 가입 없이 바로 만져 볼 수 있습니다.&lt;/p&gt;</content:encoded><category>Umtri로 프로젝트 키우기</category><category>Umtri</category><category>위키</category><category>팀협업</category><category>바이브코딩</category></item><item><title>만들면서 기록하기 — 계획, 저장, 버그</title><link>https://blog.bepuljang.co.kr/about-umtri/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/about-umtri/04/</guid><description>새 기능을 나무에 계획으로 먼저 그려 보고, 만든 뒤에는 기록을 남기고, 버그가 생기면 영향이 어디까지 가는지 확인하는 흐름을 프롬프트 예시와 함께 안내합니다.</description><pubDate>Fri, 31 Jul 2026 15:50:33 GMT</pubDate><content:encoded>&lt;p&gt;나무를 심었다면 이제부터가 진짜입니다. 나무는 한 번 그리고 끝나는 그림이 아니라, 프로젝트와 함께 자라야 쓸모가 있습니다. 이번 편에서는 매일 쓰는 흐름 세 가지를 다룹니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;만들기 &lt;strong&gt;전에&lt;/strong&gt;: 계획을 나무에 먼저 그려 보기&lt;/li&gt;
&lt;li&gt;만든 &lt;strong&gt;뒤에&lt;/strong&gt;: 나무에 기록 남기기&lt;/li&gt;
&lt;li&gt;문제가 &lt;strong&gt;생기면&lt;/strong&gt;: 버그를 등록하고 영향 범위 확인하기&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-만들기-전에-계획을-나무에-먼저-그리기&quot;&gt;1. 만들기 전에: 계획을 나무에 먼저 그리기&lt;/h2&gt;
&lt;p&gt;Umtri에는 &lt;strong&gt;계획 모드(Plan Mode)&lt;/strong&gt;가 있습니다. 계획 모드에서 그린 가지와 잎은 &lt;strong&gt;아직 만들지 않은 계획&lt;/strong&gt;으로 표시되고, 기록에도 남지 않아서 몇 번이고 고칠 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.umtri.io/demo&quot;&gt;데모&lt;/a&gt;를 열어 계획 모드를 켜 보세요. 서버 쪽 줄기에 &lt;strong&gt;Notifications&lt;/strong&gt;(주문이 준비되면 손님에게 알림 보내기)라는 가지가 계획으로 그려져 있습니다. 다음에 만들 기능을 미리 그려 둔 것입니다.&lt;/p&gt;
&lt;h3 id=&quot;ai에게-계획을-그리게-하기&quot;&gt;AI에게 계획을 그리게 하기&lt;/h3&gt;
&lt;p&gt;새 기능을 부탁할 때, 바로 만들게 하지 말고 먼저 계획을 그리게 해 보세요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;손님이 주문한 커피가 준비되면 알림을 보내는 기능을 만들고 싶어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;바로 만들지 말고, 먼저 coffee-app 나무에 계획으로 그려줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;어느 줄기 아래에 어떤 가지와 잎이 생길지 보여줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI가 그린 계획을 화면에서 보면, AI가 여러분의 말을 제대로 알아들었는지 한눈에 확인할 수 있습니다. 긴 설명을 읽는 것보다 훨씬 빠릅니다. 이상한 곳이 있으면 이렇게 고쳐 달라고 하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;알림은 관리자 화면이 아니라 손님 앱 쪽이야. 계획을 다시 그려줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;내가-그린-계획을-ai에게-넘기기&quot;&gt;내가 그린 계획을 AI에게 넘기기&lt;/h3&gt;
&lt;p&gt;반대로 여러분이 앱에서 직접 계획을 그려 두고 AI에게 넘길 수도 있습니다. 계획 모드에서 가지를 누르고 &lt;strong&gt;Add Plan Node&lt;/strong&gt;로 잎을 추가하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app 나무에 계획으로 그려 둔 Notifications 가지를 읽고, 그대로 만들어줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;다 만들고 나면 잎마다 파일 경로를 적고 계획을 확정해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;계획을 &lt;strong&gt;확정(커밋)&lt;/strong&gt;하면 그 가지가 진짜 나무의 일부가 됩니다. 이때 잎에 실제 파일이 적혀 있어야 확정할 수 있습니다. “계획만 그려 놓고 실제로는 안 만든” 가지가 나무에 섞이지 않게 하려는 장치입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-만든-뒤에-나무에-기록-남기기&quot;&gt;2. 만든 뒤에: 나무에 기록 남기기&lt;/h2&gt;
&lt;p&gt;기능을 다 만들었다면 나무도 따라가야 합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;방금 만든 쿠폰 기능을 coffee-app 나무에 추가해줘. 파일 경로도 같이 적어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드를 정리하느라 파일을 옮기거나 이름을 바꿨을 때도 마찬가지입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;방금 결제 관련 파일들을 payments 폴더로 옮겼어. 나무에 적힌 파일 경로도 맞춰줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;주문 내역 화면을 없앴어. 나무에서도 정리해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;뿌리를 내린 나무에서는 가지를 지워도 흔적이 남습니다. 나중에 시간 슬라이더로 돌려 보면 “여기에 이런 가지가 있었다가 없어졌구나”를 볼 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;작업을-저장할-때마다-기록-붙이기&quot;&gt;작업을 저장할 때마다 기록 붙이기&lt;/h3&gt;
&lt;p&gt;git으로 작업을 한 번 저장하는 걸 &lt;strong&gt;커밋&lt;/strong&gt;이라고 합니다. 커밋할 때 Umtri에도 알려 주면, 그 커밋에서 바뀐 파일이 적힌 잎마다 “이날 이렇게 바뀌었다”는 기록이 붙습니다. 나중에 잎을 누르면 그 부품이 언제 어떻게 바뀌어 왔는지가 보입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;방금 한 커밋을 Umtri에도 기록해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;매번-말하기-귀찮다면-ai에게-규칙으로-맡기기&quot;&gt;매번 말하기 귀찮다면: AI에게 규칙으로 맡기기&lt;/h3&gt;
&lt;p&gt;“나무에도 추가해줘”, “커밋도 기록해줘”를 매번 말하기는 번거롭습니다. 대부분의 AI 도구는 프로젝트 폴더의 규칙 파일(Claude Code는 &lt;code&gt;CLAUDE.md&lt;/code&gt;, Codex는 &lt;code&gt;AGENTS.md&lt;/code&gt;)을 매번 먼저 읽습니다. 여기에 규칙을 적어 두면 AI가 알아서 챙깁니다.&lt;/p&gt;
&lt;p&gt;Umtri에는 이 규칙의 모범 답안이 준비되어 있어서, 이렇게만 부탁하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Umtri 커밋 동기화 규칙을 이 프로젝트의 CLAUDE.md에 추가해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 해 두면 AI가 커밋하기 전에 스스로 확인합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;새로 생긴 기능이 있으면 → 나무에 가지나 잎을 더합니다.&lt;/li&gt;
&lt;li&gt;파일을 옮겼으면 → 나무에 적힌 파일 경로를 고칩니다.&lt;/li&gt;
&lt;li&gt;이번 작업으로 고친 버그가 있으면 → 버그를 해결됨으로 바꿉니다.&lt;/li&gt;
&lt;li&gt;그리고 마지막으로 커밋을 기록합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;애매할 때는 AI가 여러분에게 물어봅니다. 엉뚱한 가지를 만드는 것보다 한 번 묻는 게 낫기 때문입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-문제가-생기면-버그-등록하고-영향-범위-보기&quot;&gt;3. 문제가 생기면: 버그 등록하고 영향 범위 보기&lt;/h2&gt;
&lt;h3 id=&quot;부품끼리-연결해-두기&quot;&gt;부품끼리 연결해 두기&lt;/h3&gt;
&lt;p&gt;“이게 고장 나면 저것도 고장 난다”를 알려면, 부품끼리 어떻게 이어져 있는지가 나무에 적혀 있어야 합니다. 연결은 두 가지입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;종속성(Edge)&lt;/strong&gt;: 한 부품이 다른 부품에 &lt;strong&gt;기대는&lt;/strong&gt; 관계. 예) 주문 기능은 주문 저장소에 기댑니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API&lt;/strong&gt;: 한 부품이 다른 부품을 &lt;strong&gt;부르는&lt;/strong&gt; 관계. 예) 결제 화면이 서버의 “주문 만들기”를 부릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;직접 그릴 필요는 없습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app 나무를 보고, 코드에서 서로 기대거나 부르는 부품끼리 연결을 걸어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;연결은 화면에서 기본으로 꺼져 있습니다. 사이드바의 레이어에서 API와 Edge를 켜야 보입니다.&lt;/p&gt;
&lt;h3 id=&quot;영향-범위-보기&quot;&gt;영향 범위 보기&lt;/h3&gt;
&lt;p&gt;나무에서 잎 하나를 누르고 &lt;strong&gt;Show impact&lt;/strong&gt;를 누르면, 그 잎이 고장 났을 때 영향을 받는 곳만 밝게 남고 나머지는 흐려집니다. 데모에서 주문 저장소(&lt;code&gt;orders&lt;/code&gt;)를 눌러 보세요. 주문을 처리하는 서버, 결제, 관리자 화면의 매출 차트까지 영향이 이어지는 게 보입니다.&lt;/p&gt;
&lt;p&gt;AI에게 물어봐도 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app에서 결제 기능을 고치려고 해. 이걸 고치면 어디까지 확인해 봐야 해?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;영향 범위가 &lt;strong&gt;비어 있다면&lt;/strong&gt; “영향이 없다”는 뜻이 아니라 “아직 연결이 적혀 있지 않다”는 뜻입니다. 연결을 먼저 걸어 주세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;버그-등록하기&quot;&gt;버그 등록하기&lt;/h3&gt;
&lt;p&gt;문제를 발견하면 버그로 등록해 두세요. 버그는 나무 위 해당 위치에 빨간 점으로 표시됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app에 버그 등록해줘: 결제를 다시 시도하면 쿠폰이 두 번 적용됨.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;어느 부분 문제인지, 얼마나 위험한지도 같이 판단해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI가 버그를 등록하면 그 버그 때문에 함께 확인해야 할 곳(영향 범위)도 같이 알려 줍니다.&lt;/p&gt;
&lt;p&gt;버그에는 &lt;strong&gt;위험도 점수&lt;/strong&gt;가 0부터 8까지 붙습니다. “얼마나 큰 문제인가”와 “고치기 어려운가”를 합친 점수입니다.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;점수&lt;/th&gt;&lt;th&gt;뜻&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0–1&lt;/td&gt;&lt;td&gt;메모나 문구 수정. 기능에는 문제없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;쓰기 불편함&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3–4&lt;/td&gt;&lt;td&gt;가벼운 기능 문제&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5–6&lt;/td&gt;&lt;td&gt;큰 기능 문제&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7–8&lt;/td&gt;&lt;td&gt;치명적인 문제&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;같은 칸 안에서는 고치기 어려울수록 높은 숫자입니다. 점수는 AI가 제안하지만, 여러분이 보기에 다르다면 바꿔 달라고 하면 됩니다.&lt;/p&gt;
&lt;h3 id=&quot;버그-고치기&quot;&gt;버그 고치기&lt;/h3&gt;
&lt;p&gt;버그마다 &lt;strong&gt;#1&lt;/strong&gt;, &lt;strong&gt;#2&lt;/strong&gt; 같은 번호가 붙습니다. 번호로 부르면 편합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;#1 버그 내용 확인하고 고쳐줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;고치기 시작할 때 &apos;추적 중&apos;으로 바꾸고, 다 고치면 &apos;해결됨&apos;으로 바꾼 다음 실제로 뭘 했는지 적어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;버그의 상태는 &lt;strong&gt;발견 → 추적 중 → 해결됨&lt;/strong&gt;으로 바뀝니다. “추적 중”은 “누가 이미 이 버그를 보고 있다”는 표시라서, 고치기 시작하는 순간 바꿔 두는 게 좋습니다. 다른 대화창의 AI나 팀원이 같은 버그를 두 번 붙잡는 일을 막아 줍니다.&lt;/p&gt;
&lt;p&gt;그리고 &lt;strong&gt;“실제로 뭘 했는지”&lt;/strong&gt;를 남기는 게 중요합니다. 몇 달 뒤 비슷한 문제가 생겼을 때 가장 먼저 찾아보게 되는 곳이 여기입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;오늘의-루틴-정리&quot;&gt;오늘의 루틴 정리&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;언제&lt;/th&gt;&lt;th&gt;이렇게 말하세요&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;새 기능을 시작할 때&lt;/td&gt;&lt;td&gt;”바로 만들지 말고 나무에 계획으로 먼저 그려줘”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;계획이 마음에 들면&lt;/td&gt;&lt;td&gt;”그려 둔 계획대로 만들고, 다 되면 확정해줘”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;파일을 정리했을 때&lt;/td&gt;&lt;td&gt;”나무에 적힌 파일 경로도 맞춰줘”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;문제를 발견했을 때&lt;/td&gt;&lt;td&gt;”버그로 등록하고 영향 범위도 알려줘”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;처음 한 번만&lt;/td&gt;&lt;td&gt;”Umtri 커밋 동기화 규칙을 CLAUDE.md에 추가해줘”&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;마지막 편에서는 이렇게 쌓인 기록이 몇 달 뒤에 어떤 차이를 만드는지, 그리고 나무만으로는 남지 않는 “왜 이렇게 만들었는지”를 &lt;strong&gt;위키&lt;/strong&gt;에 남기는 방법을 다룹니다.&lt;/p&gt;</content:encoded><category>Umtri로 프로젝트 키우기</category><category>Umtri</category><category>계획 모드</category><category>버그</category><category>바이브코딩</category></item><item><title>첫 나무 심기 — 옮겨심기와 시즌</title><link>https://blog.bepuljang.co.kr/about-umtri/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/about-umtri/03/</guid><description>이미 만들어 둔 프로젝트를 AI에게 부탁해 나무로 옮겨심고, 시즌으로 성장 단계를 나누고, 뿌리내리기로 기록을 시작하는 방법을 프롬프트 예시와 함께 안내합니다.</description><pubDate>Fri, 31 Jul 2026 06:44:23 GMT</pubDate><content:encoded>&lt;p&gt;연결까지 마쳤다면 이제 나무를 심을 차례입니다. 이번 편에서는 이미 만들어 둔 프로젝트를 AI에게 부탁해서 나무로 옮기는 방법을 다룹니다. 새로 시작하는 프로젝트라도 흐름은 같으니 그대로 따라오시면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;옮겨심기-이미-자란-나무를-가져오기&quot;&gt;옮겨심기: 이미 자란 나무를 가져오기&lt;/h2&gt;
&lt;p&gt;배지를 처음 만들면 화면 위쪽에 주황색으로 &lt;strong&gt;Transplanting(옮겨심는 중)&lt;/strong&gt;이라고 표시됩니다. 다른 곳에서 자란 나무를 새 땅으로 옮기는 중이라는 뜻입니다.&lt;/p&gt;
&lt;p&gt;옮겨심는 동안에는 무엇이든 자유롭게 고치고 지울 수 있습니다. 처음부터 완벽하게 옮길 필요가 없으니 편하게 시작하세요.&lt;/p&gt;
&lt;p&gt;AI 도구를 &lt;strong&gt;프로젝트 폴더에서&lt;/strong&gt; 열고 이렇게 부탁합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;지금 이 프로젝트 코드를 살펴보고, Umtri의 coffee-app 배지에 나무로 옮겨심어줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;옮기기 전에 어떤 줄기와 가지로 나눌지 먼저 보여주고, 내가 괜찮다고 하면 그때 심어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“먼저 보여주고”라는 한 줄이 중요합니다. AI가 제안한 구조를 보고 “관리자 화면은 따로 줄기로 빼 줘”, “결제는 주문 안에 넣지 말고 따로 가지로” 같은 식으로 고쳐 달라고 할 수 있습니다. 대화로 다듬은 뒤에 심는 게 훨씬 깔끔합니다.&lt;/p&gt;
&lt;p&gt;AI가 심고 나면 브라우저에서 배지를 열어 보세요. 나무가 생겨 있을 겁니다.&lt;/p&gt;
&lt;h3 id=&quot;파일도-같이-적어-달라고-하세요&quot;&gt;파일도 같이 적어 달라고 하세요&lt;/h3&gt;
&lt;p&gt;나무의 잎 하나하나가 실제로 &lt;strong&gt;어느 파일&lt;/strong&gt;인지 적혀 있으면 나중에 여러모로 편합니다. 어떤 파일을 고쳤을 때 그 잎에 기록이 붙고, AI도 “이 잎을 고치려면 이 파일을 열면 되는구나”를 바로 압니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;심을 때 잎마다 그 기능이 들어 있는 파일 경로도 같이 적어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;잘-옮겨졌는지-확인하기&quot;&gt;잘 옮겨졌는지 확인하기&lt;/h3&gt;
&lt;p&gt;옮겨심은 뒤에는 AI에게 스스로 점검을 시켜 보세요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;coffee-app 나무를 읽고, 코드에는 있는데 나무에 빠진 기능이 있는지 확인해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;나무에서 너무 잘게 쪼개졌거나, 엉뚱한 가지에 붙은 잎이 있으면 알려줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;시즌-성장-단계를-나누기&quot;&gt;시즌: 성장 단계를 나누기&lt;/h2&gt;
&lt;p&gt;Umtri의 나무는 &lt;strong&gt;시즌&lt;/strong&gt; 안에서 자랍니다. 시즌은 프로젝트의 “몇 번째 단계”를 나누는 이름표입니다. &lt;code&gt;1.0&lt;/code&gt;, &lt;code&gt;2.0&lt;/code&gt; 같은 버전이어도 되고, &lt;code&gt;시범 운영&lt;/code&gt;, &lt;code&gt;정식 출시&lt;/code&gt;처럼 단계 이름이어도 됩니다.&lt;/p&gt;
&lt;p&gt;데모 속 커피 주문 앱은 시즌이 세 개입니다.&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;시즌&lt;/th&gt;&lt;th&gt;무엇을 했나&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;MVP&lt;/td&gt;&lt;td&gt;메뉴 보기, 장바구니, 주문하기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Launch&lt;/td&gt;&lt;td&gt;주문 현황, 로그인, 쿠폰, 관리자 화면&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Growth&lt;/td&gt;&lt;td&gt;매출 차트, 알림 (계획 중)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;시즌은 하나만 &lt;strong&gt;지금(now)&lt;/strong&gt;이고 나머지는 &lt;strong&gt;지난 시즌(past)&lt;/strong&gt;입니다. 새 시즌을 열면 지금까지의 시즌은 지난 시즌이 되어 더 이상 고칠 수 없게 됩니다. “여기까지가 한 단계였다”고 선을 긋는 셈입니다.&lt;/p&gt;
&lt;h3 id=&quot;옮겨심을-때-시즌도-나눠-달라고-하기&quot;&gt;옮겨심을 때 시즌도 나눠 달라고 하기&lt;/h3&gt;
&lt;p&gt;이미 몇 달 동안 만든 프로젝트라면, 옮겨심을 때 과거 단계까지 나눠 두면 나중에 시간 슬라이더로 돌려 볼 때 훨씬 보기 좋습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4월 말까지 만든 기능은 &quot;시범 운영&quot; 시즌에,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;그 이후에 만든 기능은 &quot;1.0&quot; 시즌에 나눠서 심어줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;언제 만들었는지는 git 기록을 보고 판단해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI가 시즌을 만들 때는 반드시 여러분에게 먼저 묻습니다. 시즌을 여는 건 되돌리기 어려운 결정이라 사람이 확인해야만 만들어지도록 되어 있습니다. AI가 “이 시즌을 만들까요?”라고 물으면, 이름이 맞는지 보고 답해 주세요.&lt;/p&gt;
&lt;p&gt;직접 만들고 싶다면 빈 배지에 보이는 &lt;strong&gt;+ Add season&lt;/strong&gt; 버튼이나 시즌 목록의 &lt;strong&gt;+ New Season&lt;/strong&gt;을 누르면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;뿌리내리기-이제부터-기록-시작&quot;&gt;뿌리내리기: 이제부터 기록 시작&lt;/h2&gt;
&lt;p&gt;나무가 마음에 들게 옮겨졌다면 화면 위쪽 주황색 표시 옆의 &lt;strong&gt;Root&lt;/strong&gt; 버튼을 눌러 &lt;strong&gt;뿌리내리기&lt;/strong&gt;를 합니다.&lt;/p&gt;
&lt;p&gt;뿌리를 내리면 달라지는 점은 이렇습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이제부터 나무의 모든 변화가 기록으로 남습니다.&lt;/li&gt;
&lt;li&gt;가지를 지워도 완전히 사라지지 않고 “여기 있었다”는 흔적으로 남습니다.&lt;/li&gt;
&lt;li&gt;지난 시즌은 더 이상 고칠 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;뿌리내리기는 &lt;strong&gt;되돌릴 수 없습니다.&lt;/strong&gt; 옮겨심는 동안 충분히 다듬은 뒤에 누르세요. 버튼은 배지 주인만 누를 수 있고, AI는 누를 수 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;새로-시작하는-프로젝트라면&quot;&gt;새로 시작하는 프로젝트라면&lt;/h2&gt;
&lt;p&gt;코드가 아직 없다면 옮겨심을 것도 없습니다. 첫 시즌을 하나 만들고, 첫 번째 기능이 돌아가기 시작할 때 이렇게 부탁하세요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;지금까지 만든 걸 coffee-app 나무에 심어줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;앞으로 기능을 추가할 때마다 나무에도 같이 더해 나갈 거야.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 바로 뿌리를 내려도 됩니다. 새 프로젝트는 옮겨올 과거가 없으니까요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;시간-슬라이더로-돌려-보기&quot;&gt;시간 슬라이더로 돌려 보기&lt;/h2&gt;
&lt;p&gt;화면 아래의 &lt;strong&gt;시간 슬라이더&lt;/strong&gt;를 끝까지 왼쪽으로 당기면 아무것도 없는 땅에서 시작합니다. 오른쪽으로 한 칸씩 옮길 때마다 가지와 잎이 생긴 순서대로 하나씩 돋아납니다. 사이드바에서 시즌을 하나 고르면 그 시즌 동안 자란 모습만 따로 볼 수도 있습니다.&lt;/p&gt;
&lt;p&gt;아직 여러분의 나무가 작다면 &lt;a href=&quot;https://app.umtri.io/demo&quot;&gt;데모&lt;/a&gt;에서 먼저 해 보세요. 세 시즌에 걸쳐 자란 모습을 볼 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;다음 편에서는 나무를 심은 뒤의 일상을 다룹니다. 새 기능을 만들기 전에 계획을 나무에 먼저 그려 보고, 만들고 나면 기록하고, 버그가 생기면 어디까지 영향이 가는지 확인하는 흐름입니다.&lt;/p&gt;</content:encoded><category>Umtri로 프로젝트 키우기</category><category>Umtri</category><category>프로젝트 구조</category><category>옮겨심기</category><category>바이브코딩</category></item><item><title>Umtri를 내 AI와 연결하기</title><link>https://blog.bepuljang.co.kr/about-umtri/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/about-umtri/02/</guid><description>가입부터 토큰 발급, Claude Code 같은 AI 도구에 Umtri를 연결하고 잘 붙었는지 확인하는 방법까지 차례대로 안내합니다.</description><pubDate>Thu, 30 Jul 2026 18:42:38 GMT</pubDate><content:encoded>&lt;p&gt;지난 편에서 Umtri가 프로젝트를 나무로 그려 준다는 걸 알아봤습니다. 이번 편에서는 여러분이 쓰는 AI가 이 나무를 직접 읽고 그릴 수 있도록 &lt;strong&gt;연결&lt;/strong&gt;합니다.&lt;/p&gt;
&lt;p&gt;어렵지 않습니다. 순서는 이렇습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Umtri에 가입하고 프로젝트 자리 만들기&lt;/li&gt;
&lt;li&gt;AI에게 줄 &lt;strong&gt;출입증(토큰)&lt;/strong&gt; 받기&lt;/li&gt;
&lt;li&gt;화면에 나온 명령을 복사해서 붙여넣기&lt;/li&gt;
&lt;li&gt;AI에게 말을 걸어 확인하기&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ai와-umtri는-어떻게-이어지나요&quot;&gt;AI와 Umtri는 어떻게 이어지나요&lt;/h2&gt;
&lt;p&gt;AI 도구는 원래 여러분 컴퓨터 안의 코드만 볼 수 있습니다. 여기에 다른 서비스를 쓸 수 있게 이어 주는 연결 방식이 있는데, 이걸 &lt;strong&gt;MCP&lt;/strong&gt;라고 부릅니다. 휴대폰에 앱을 설치하듯 AI에 기능을 하나 붙인다고 생각하면 됩니다. (MCP가 궁금하다면 &lt;a href=&quot;https://blog.bepuljang.co.kr/vibecoding/06&quot;&gt;바이브코딩 6편&lt;/a&gt;에서 자세히 다뤘습니다.)&lt;/p&gt;
&lt;p&gt;Umtri를 연결하고 나면 이렇게 말할 수 있게 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;내 Umtri 배지 목록 보여줘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;지금 프로젝트 나무를 읽고, 로그인 기능이 어디에 있는지 알려줘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;방금 만든 쿠폰 기능을 나무에도 추가해줘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-가입하고-프로젝트-자리-만들기&quot;&gt;1. 가입하고 프로젝트 자리 만들기&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://app.umtri.io&quot;&gt;app.umtri.io&lt;/a&gt;에서 이메일과 &lt;strong&gt;핸들&lt;/strong&gt;(내 이름처럼 쓰이는 영문 아이디, 나중에 못 바꿉니다)로 가입합니다. 메일로 온 인증 링크를 누르면 가입이 끝납니다.&lt;/p&gt;
&lt;p&gt;로그인했다면 &lt;strong&gt;프로젝트 배지 추가&lt;/strong&gt;를 눌러 프로젝트 자리를 하나 만듭니다. Umtri에서는 프로젝트 하나가 자라는 땅을 &lt;strong&gt;배지(Ground)&lt;/strong&gt;라고 부릅니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;이름&lt;/strong&gt;은 편하게 정하면 됩니다. (예: 커피 주문 앱)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;슬러그(slug)&lt;/strong&gt;는 주소에 들어가는 영문 이름입니다. (예: &lt;code&gt;coffee-app&lt;/code&gt;) 나중에 바꿀 수 없으니 짧고 알아보기 쉽게 정하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;나무는 아직 비어 있어도 괜찮습니다. 심는 건 AI가 해 줄 겁니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;2-ai에게-줄-출입증토큰-받기&quot;&gt;2. AI에게 줄 출입증(토큰) 받기&lt;/h2&gt;
&lt;p&gt;AI가 여러분 대신 Umtri에 들어가려면 출입증이 필요합니다. 이걸 &lt;strong&gt;토큰&lt;/strong&gt;이라고 부릅니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;왼쪽 사이드바 아래쪽의 프로필을 누르고 &lt;strong&gt;Settings&lt;/strong&gt;로 갑니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Tokens&lt;/strong&gt;를 고릅니다.&lt;/li&gt;
&lt;li&gt;토큰에 알아보기 쉬운 이름을 붙입니다. (예: &lt;code&gt;내 노트북 claude&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;권한은 기본값인 &lt;strong&gt;Write&lt;/strong&gt;를 그대로 둡니다. AI가 나무를 읽기만 하는 게 아니라 직접 그리게 하려면 Write가 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate token&lt;/strong&gt;을 누릅니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;토큰은 &lt;strong&gt;딱 한 번만&lt;/strong&gt; 보여집니다. 비밀번호처럼 다루세요. 다른 사람에게 보내거나, 인터넷에 올라가는 파일에 적어 두면 안 됩니다. 잃어버렸다면 목록에서 지우고(Revoke) 새로 받으면 됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3-명령을-복사해서-붙여넣기&quot;&gt;3. 명령을 복사해서 붙여넣기&lt;/h2&gt;
&lt;p&gt;토큰을 받으면 바로 아래에 &lt;strong&gt;ADD UMTRI MCP&lt;/strong&gt; 상자가 나타납니다. Claude Code, Codex, Gemini CLI 같은 AI 도구별로 연결 명령이 이미 만들어져 있고, 방금 받은 토큰도 들어 있습니다.&lt;/p&gt;
&lt;p&gt;쓰는 도구의 버튼을 눌러 복사한 뒤, 터미널(AI 도구를 실행하는 검은 창)에 붙여넣고 엔터를 누르면 끝입니다.&lt;/p&gt;
&lt;p&gt;버튼은 두 가지로 나뉩니다.&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;버튼&lt;/th&gt;&lt;th&gt;뜻&lt;/th&gt;&lt;th&gt;이럴 때&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Global&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;이 컴퓨터의 모든 프로젝트에서 Umtri를 씁니다&lt;/td&gt;&lt;td&gt;내 컴퓨터를 나 혼자 쓰고, 편하게 쓰고 싶을 때&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Local&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;명령을 실행한 프로젝트 폴더에서만 씁니다&lt;/td&gt;&lt;td&gt;프로젝트마다 따로 관리하고 싶을 때&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;잘 모르겠다면 &lt;strong&gt;Local&lt;/strong&gt;을 고르세요. 조금 번거롭지만 더 안전합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;복사하기 전에 &lt;strong&gt;Dismiss&lt;/strong&gt;를 누르면 명령과 토큰이 함께 사라집니다. 꼭 먼저 복사하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4-잘-연결됐는지-확인하기&quot;&gt;4. 잘 연결됐는지 확인하기&lt;/h2&gt;
&lt;p&gt;AI 도구를 열고(이미 열려 있었다면 한 번 껐다 켜고) 이렇게 말해 보세요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;내 Umtri 배지 목록 보여줘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;방금 만든 배지 이름이 나오면 성공입니다.&lt;/p&gt;
&lt;p&gt;Claude Code를 쓴다면 대화창에 &lt;code&gt;/mcp&lt;/code&gt;를 입력해서 &lt;code&gt;umtri&lt;/code&gt;가 연결되어 있는지 직접 볼 수도 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;안-될-때&quot;&gt;안 될 때&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“Umtri 도구가 없다”고 한다면&lt;/strong&gt; — AI 도구를 껐다가 다시 켜 보세요. Local로 연결했다면, 명령을 실행했던 그 프로젝트 폴더에서 AI를 열었는지 확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;도구는 보이는데 계속 실패한다면&lt;/strong&gt; — 토큰이 잘못 들어갔을 가능성이 큽니다. 연결할 때는 토큰이 맞는지 검사하지 않아서, 틀린 토큰이어도 연결 자체는 된 것처럼 보입니다. 토큰을 새로 받아서 다시 연결해 보세요.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;읽기는 되는데 추가·수정이 안 된다면&lt;/strong&gt; — 토큰 권한이 Read로 되어 있을 수 있습니다. Write로 새로 받으세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이것도 AI에게 물어보면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Umtri 연결이 안 되는 것 같아. 뭐가 문제인지 확인해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;연결하고-나면-달라지는-것&quot;&gt;연결하고 나면 달라지는 것&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;연결 전&lt;/th&gt;&lt;th&gt;연결 후&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;나무 그리기&lt;/td&gt;&lt;td&gt;앱 화면에서 직접 하나씩&lt;/td&gt;&lt;td&gt;”나무에 추가해줘” 한 마디&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;프로젝트 설명&lt;/td&gt;&lt;td&gt;새 대화마다 처음부터 설명&lt;/td&gt;&lt;td&gt;AI가 나무를 읽고 시작&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;버그 기록&lt;/td&gt;&lt;td&gt;따로 메모&lt;/td&gt;&lt;td&gt;”버그로 등록해줘” 한 마디&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;다음 편에서는 드디어 나무를 심습니다. 이미 만들어 둔 프로젝트를 AI에게 통째로 옮겨 달라고 하는 &lt;strong&gt;옮겨심기&lt;/strong&gt;부터 시작합니다.&lt;/p&gt;</content:encoded><category>Umtri로 프로젝트 키우기</category><category>Umtri</category><category>MCP</category><category>Claude Code</category><category>바이브코딩</category></item><item><title>Umtri는 어떤 도구인가요?</title><link>https://blog.bepuljang.co.kr/about-umtri/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/about-umtri/01/</guid><description>바이브코딩은 편리하지만, 자신이 개발한 내용임에도 스스로 이해가 어려워지는 문제를 낳습니다. Umtri는 AI 에이전트를 활용해 프로젝트를 시각화할 수 있는 도구를 제공해 프로젝트를 직관적으로 이해할 수 있도록 합니다.</description><pubDate>Wed, 29 Jul 2026 16:31:36 GMT</pubDate><content:encoded>&lt;p&gt;바이브코딩으로 앱을 만들다 보면 이런 순간이 옵니다.&lt;/p&gt;
&lt;p&gt;“우리 앱에 이런 정보가 있었나? 어디 표시되고 있지?”
“결제 흐름을 살짝 고치려는데, 어디까지 영향이 있지?”
“언제 이 내용이 추가된 거지? 나도 모르게 추가되었네?”&lt;/p&gt;
&lt;p&gt;직접 코드를 작성하던 시절에 비해, 이러한 문제가 좀 더 발생하기 쉬운 구조입니다. 그런데 프로젝트가 커질수록 이 ‘모름’이 점점 쌓여서, 사용자에게 질문을 받아도 AI 에이전트에게 답을 듣기 전에는 알기 어렵고 간단한 수정이라고 생각했던 문제가 예상보다 위험 범위가 넓어서 서비스를 오랫동안 멈추게 되기도 합니다. 자신도 모르던 내용이 노출되고 있어서 곤란한 상황에 처하기도 합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.bepuljang.co.kr/series/1&quot;&gt;누구나 따라하는 바이브코딩&lt;/a&gt; 시리즈를 작성하면서, 그리고 수많은 프로젝트를 진행하면서 통감했던 이 문제, 이 문제를 해결하기 위해 제작된 서비스가 바로 &lt;a href=&quot;https://umtri.io&quot;&gt;Umtri.io&lt;/a&gt;입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;프로젝트를-나무-한-그루로-그려-보기&quot;&gt;프로젝트를 나무 한 그루로 그려 보기&lt;/h2&gt;
&lt;p&gt;Umtri는 프로젝트를 &lt;strong&gt;나무&lt;/strong&gt; 형태로 그려줍니다. 프로젝트를 구성하는 핵심적인 구분이 밑동(Trunk)의 구분을 이루고, 그로부터 분기되는 흐름이 점차 더 굵은 줄기(Limb)에서 얇은 가지(Twig)로, 잎(Leaf)과 잎맥(Vein)으로 자라납니다.&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;나무의 부분&lt;/th&gt;&lt;th&gt;이름&lt;/th&gt;&lt;th&gt;내용&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;굵은 줄기&lt;/td&gt;&lt;td&gt;Trunk&lt;/td&gt;&lt;td&gt;서비스 구성 요소 (앱, 서버, 데이터베이스 등)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;큰 가지&lt;/td&gt;&lt;td&gt;Limb&lt;/td&gt;&lt;td&gt;주요 활동 구분 (사용자 메뉴, 장바구니·결제, 주문 내역 등)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;잔가지&lt;/td&gt;&lt;td&gt;Twig&lt;/td&gt;&lt;td&gt;모듈·관련 정보 묶음 (결제 과정)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;잎&lt;/td&gt;&lt;td&gt;Leaf&lt;/td&gt;&lt;td&gt;객체 (결제 화면 컴포넌트 등)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;잎맥&lt;/td&gt;&lt;td&gt;Vein&lt;/td&gt;&lt;td&gt;기능, 메소드(화면 안의 “주문하기”, “쿠폰 적용” 같은 동작)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 구분은 절대적이지는 않습니다. 프로젝트나 구성 요소의 성격마다 같을 수 없기 때문입니다. 단지 &lt;strong&gt;큰 것에서 작은 것으로 내려간다&lt;/strong&gt;는 것이 유일하게 유지되는 규칙입니다. 사용자가 세부 내용을 세세히 알 필요는 없습니다. Umtri와 연동된 AI 에이전트에게 프로젝트를 나무로 그려달라고 요청하면, 에이전트는 규칙을 참조하여 나무를 그립니다. 단지 그 그림이 이해하기 쉬운지, 어려운지 판단해서 그림을 다시 그려달라고 조정을 요청하면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;나무로-보면-무엇이-좋은가요&quot;&gt;나무로 보면 무엇이 좋은가요?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;한눈에 보입니다.&lt;/strong&gt; 파일을 하나씩 열어 보지 않아도 우리 앱이 어떻게 자라나고 있고, 어떤 정보들이 어떤 가지에서 다뤄지고 있는지를 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;자라 온 과정을 돌려 볼 수 있습니다.&lt;/strong&gt; 화면 아래의 시간 슬라이더를 뒤로 당기면, 처음 만들었을 때의 작은 나무부터 가지가 하나씩 돋아나는 모습을 다시 볼 수 있습니다. 정보 구조의 생성 순서와 성장 흐름을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;어디까지 영향이 가는지 보입니다.&lt;/strong&gt; 나무를 그리면서 등록되는 각 노드 간에는 연결성과 종속성까지 같이 분석되어 기록됩니다. 이를 통해 어떤 곳에 문제가 생겼을 때 함께 확인해야 할 곳과 영향 범위가 표시되고, 기록됩니다. 해당 영역에 생긴 버그, 그리고 해결안이 어떤 영향을 주는지, 수정 이후 어떤 부분들을 확인해야 하는지를 체크할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;팀원도, AI 에이전트도 같이 볼 수 있습니다.&lt;/strong&gt; 나무로 그려진 결과는 팀원도, AI 에이전트도 같이 확인하며 더 명확한 소통을 돕습니다. 진행 중인 상황을 쉽게 공유할 수 있고 새로운 세션으로 시작된 에이전트도 프로젝트의 지도를 확인하면서 안전한 길을 찾을 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;먼저-구경해-보세요&quot;&gt;먼저 구경해 보세요&lt;/h2&gt;
&lt;p&gt;가입하지 않아도 바로 확인할 수 있습니다. 아래의 &lt;a href=&quot;https://app.umtri.io/demo&quot;&gt;데모&lt;/a&gt;를 확인해보세요.&lt;/p&gt;
&lt;p&gt;데모 페이지에서는 아래를 해보실 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;가지와 잎을 눌러 보기&lt;/strong&gt; — 각 노드가 무엇인지 설명이 나옵니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;아래쪽 시간 슬라이더를 끝까지 왼쪽으로 당겼다가 천천히 오른쪽으로 옮겨보세요.&lt;/strong&gt; — 앱이 자라 온 순서대로 가지가 돋아납니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;빨간 점(버그) 눌러 보기&lt;/strong&gt; — “결제를 다시 시도하면 쿠폰이 두 번 적용된다” 같은 버그가 어디에 붙어 있는지 보입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Umtri를 제대로 체험해보기에는 부족하지만, 대략적인 동작은 확인할 수 있습니다. 그러나 진짜는 MCP 연동 후 프로젝트를 직접 관리하는 과정에서 드러난다는 사실을 기억하세요.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;언제부터-쓰면-좋을까요&quot;&gt;언제부터 쓰면 좋을까요&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;처음부터 새로 시작한다면&lt;/strong&gt; 가장 좋습니다. 프로젝트 배지(Ground)를 만들고, 첫 번째 시즌(Season)을 만드세요. 시즌 이름은 PoC여도 좋고, 0.0.1이어도 좋습니다. 가장 처음 만들 목표물을 밑동으로 추가하고, 에이전트에게 생각하는 계획을 그려달라고 하세요. &lt;strong&gt;계획 노드&lt;/strong&gt;에 대해서는 4편에서 자세히 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이미 만들어 둔 프로젝트가 있어도 상관없습니다.&lt;/strong&gt; 지나온 시간을 시즌으로 만들고 AI에게 시즌별로 “코드를 보고 나무로 옮겨 줘”라고 부탁하면 됩니다. 깃(git)에 커밋된 기록을 기준으로 할 수도 있고, 파일이 생성된 시점으로 구분할 수도 있습니다. 처음 만들어진 배지는 &lt;strong&gt;옮겨심기&lt;/strong&gt; 상태로, 기록을 남기지 않고 편집할 수 있는 상태가 됩니다. 이를 이용해 만들어둔 프로젝트를 깔끔하게 옮길 수 있습니다. 이 역시 3편에서 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 Umtri를 여러분이 쓰는 AI(Claude Code 등)와 연결하는 방법을 알아봅니다. Umtri의 진가는 MCP 연동을 통해 에이전트와 함께 나무를 가꾸면서 드러납니다. 성장 관리와 버그 관리, 위키를 이용한 스펙 관리 등 프로젝트 관리에 필요한 다양한 내용들을 에이전트와 함께 해 보세요.&lt;/p&gt;</content:encoded><category>Umtri로 프로젝트 키우기</category><category>Umtri</category><category>프로젝트 구조</category><category>바이브코딩</category></item><item><title>MQTT: 끊길 것을 전제로 설계된 프로토콜</title><link>https://blog.bepuljang.co.kr/musing/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/musing/02/</guid><description>웹이 요청하고 응답받는 동안, 사물의 세계는 다른 방식으로 대화해 왔습니다. 발행과 구독, 그리고 &apos;유언&apos;까지 준비하는 MQTT의 설계 철학을 소개합니다.</description><pubDate>Wed, 15 Jul 2026 03:53:47 GMT</pubDate><content:encoded>&lt;p&gt;우리가 웹에서 익숙해진 대화 방식은 요청과 응답입니다. 브라우저가 서버에게 “이 페이지를 주세요”라고 묻고, 서버가 답합니다. 묻지 않으면 아무 일도 일어나지 않지요. 이 방식은 사람이 화면 앞에 앉아 무언가를 궁금해할 때는 더없이 자연스럽습니다.&lt;/p&gt;
&lt;p&gt;그런데 사물의 세계로 넘어오면 이야기가 달라집니다. 창고 천장에 매달린 온도 센서 이백 개가 있다고 해봅시다. 서버가 이들에게 “지금 몇 도야?”라고 물으려면 이백 번을 물어야 하고, 언제 물어야 할지도 알 수 없습니다. 1분마다 물으면 아무 변화가 없는 199개에게 헛물을 켠 것이고, 10분마다 물으면 그 사이에 냉동고가 녹아도 모릅니다. 게다가 이 센서들은 배터리로 돌아가고, 신호는 약하고, 수시로 끊깁니다.&lt;/p&gt;
&lt;p&gt;MQTT는 바로 이 상황에서 태어난 프로토콜입니다. 1999년, IBM의 앤디 스탠퍼드클라크와 아콤의 알렌 니퍼가 사막을 가로지르는 송유관을 위성으로 감시하기 위해 만들었습니다. 위성 회선은 느리고, 비싸고, 끊깁니다. 그러니 프로토콜은 가벼워야 하고, 무엇보다 &lt;strong&gt;끊길 것을 당연하게 여겨야&lt;/strong&gt; 했습니다. 이 출신 성분이 MQTT의 거의 모든 설계를 설명합니다.&lt;/p&gt;
&lt;h2 id=&quot;묻지-않고-알린다&quot;&gt;묻지 않고, 알린다&lt;/h2&gt;
&lt;p&gt;MQTT의 첫 번째 전환은 묻기를 그만두는 것입니다. 센서는 아무에게도 묻지 않고, 그저 자기가 아는 사실을 &lt;strong&gt;발행(publish)&lt;/strong&gt; 합니다. “창고/냉동고A/온도는 -18.2도다.” 이 말은 브로커(broker)라는 중개자에게 전달됩니다. 그 사실이 궁금한 쪽은 미리 브로커에게 &lt;strong&gt;구독(subscribe)&lt;/strong&gt; 을 걸어둡니다. “창고/냉동고A/온도가 바뀌면 알려줘.”&lt;/p&gt;
&lt;p&gt;센서는 누가 듣는지 모릅니다. 듣는 쪽도 어느 센서가 말했는지 알 필요가 없습니다. 둘은 서로를 모른 채 &lt;strong&gt;주제(topic)&lt;/strong&gt; 라는 이름표 하나로만 이어집니다. 온도를 기록하는 데이터베이스, 경보를 울리는 알림 서버, 관리자 화면 — 셋이 같은 주제를 구독하면 센서는 여전히 한 번만 발행하면 됩니다. 센서 코드는 한 줄도 바뀌지 않습니다.&lt;/p&gt;
&lt;p&gt;주제는 슬래시로 계층을 만들고, 구독할 때 와일드카드를 쓸 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;창고/냉동고A/온도      ← 이 하나만&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;창고/+/온도            ← 모든 냉동고의 온도 (+ 는 한 계층)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;창고/#                 ← 창고 아래 전부 (# 는 남은 전체)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드로 보면 이 정도입니다. 브로커 주소만 알면 나머지는 두 동사뿐입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mqtt &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;mqtt&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mqtt.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;mqtt://broker.local&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 듣는 쪽&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;subscribe&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;창고/+/온도&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;message&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;topic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;payload&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(topic, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(payload)); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 창고/냉동고A/온도 -18.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 말하는 쪽&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;client.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;publish&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;창고/냉동고A/온도&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;-18.2&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;끊김을-다루는-세-가지-장치&quot;&gt;끊김을 다루는 세 가지 장치&lt;/h2&gt;
&lt;p&gt;여기까지는 여느 발행/구독 시스템과 크게 다르지 않습니다. MQTT가 사물의 세계에서 살아남은 이유는 그다음에 있습니다.&lt;/p&gt;
&lt;p&gt;첫째는 &lt;strong&gt;QoS&lt;/strong&gt;, 전달 보증 수준입니다. 0은 그냥 던집니다(도착 여부를 확인하지 않음). 1은 도착할 때까지 다시 보냅니다(그래서 중복 도착할 수 있음). 2는 정확히 한 번만 도착하도록 왕복을 더 겁니다(그만큼 느림). 온도 값처럼 1초 뒤에 어차피 새 값이 오는 데이터는 0으로 충분하고, “문을 열어라” 같은 명령은 1이나 2가 필요합니다. 신뢰성을 공짜로 주는 대신, &lt;strong&gt;메시지마다 값을 치를지 고르게&lt;/strong&gt; 한 것입니다.&lt;/p&gt;
&lt;p&gt;둘째는 &lt;strong&gt;보관 메시지(retained message)&lt;/strong&gt; 입니다. 브로커는 주제마다 마지막 값 하나를 붙들고 있습니다. 관리자 화면을 새로 열었을 때, 다음 온도 보고가 올 때까지 몇 분씩 빈 화면을 보고 있을 이유가 없습니다. 구독하는 순간 마지막으로 알려진 값이 즉시 도착합니다. 상태를 다루는 시스템에서 이건 생각보다 큰 편의입니다.&lt;/p&gt;
&lt;p&gt;셋째가 가장 MQTT다운 장치인데, &lt;strong&gt;유언(Last Will and Testament)&lt;/strong&gt; 입니다. 기기는 브로커에 접속하면서 미리 유언을 맡깁니다. “내가 인사도 없이 사라지거든, 이 주제에 ‘오프라인’이라고 대신 알려줘.” 이후 기기가 정말로 죽거나, 전원이 끊기거나, 네트워크가 사라지면 — 브로커가 그 부재를 감지하고 유언을 대신 발행합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;mqtt.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;mqtt://broker.local&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  will: { topic: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;창고/냉동고A/상태&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, payload: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;오프라인&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, retain: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;부재를-설계에-포함한다는-것&quot;&gt;부재를 설계에 포함한다는 것&lt;/h2&gt;
&lt;p&gt;유언이라는 발상 앞에서 잠깐 멈추게 됩니다. 대부분의 프로토콜은 연결이 살아 있는 동안 무엇을 주고받을지를 설계합니다. MQTT는 거기서 한 걸음 더 나가, &lt;strong&gt;연결이 끊어진 뒤에 무슨 말이 남을지&lt;/strong&gt;까지 설계해 둡니다. 사라짐을 예외 처리가 아니라 정상적인 사건으로 취급하는 것이지요.&lt;/p&gt;
&lt;p&gt;이건 사막의 송유관에서 배운 태도일 겁니다. 위성 링크는 끊깁니다. 그것은 고쳐야 할 버그가 아니라 받아들여야 할 조건입니다. 조건을 부정하는 대신 조건 위에서 설계할 때, 오히려 더 단단한 물건이 나옵니다. MQTT가 스무 해가 지나도록 공장과 자동차와 집 안의 전구를 이어주고 있는 이유가 여기 있다고 생각합니다.&lt;/p&gt;
&lt;p&gt;우리가 만드는 것들도 대개 그렇습니다. 사용자는 앱을 중간에 닫고, 지하철에서 신호가 끊기고, 결제는 응답 없이 멈춥니다. 그 순간을 예외라고 부르며 급히 가려낼 것인지, 아니면 처음부터 “이 일은 일어난다”고 전제하고 그때 남길 말을 미리 준비해 둘 것인지. MQTT는 후자를 택한 프로토콜이고, 저는 그 선택이 기술적 결정이라기보다 하나의 태도에 가깝다고 봅니다.&lt;/p&gt;</content:encoded><category>단편모음</category><category>MQTT</category><category>IoT</category><category>프로토콜</category><category>네트워크</category></item><item><title>Expo와 첫 화면 띄우기</title><link>https://blog.bepuljang.co.kr/react-native/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react-native/02/</guid><description>React Native를 시작하는 가장 빠른 길인 Expo로 프로젝트를 만들고, 내 손안의 실제 기기에 첫 화면을 띄웁니다. Expo와 bare 워크플로는 무엇이 다르고, 왜 지금은 Expo가 기본 권장인지도 함께 짚습니다.</description><pubDate>Tue, 14 Jul 2026 13:33:05 GMT</pubDate><content:encoded>&lt;p&gt;지난 편에서 React Native가 무엇인지 정리했습니다. React의 사고방식은 그대로 두고 렌더러만 네이티브로 갈아 끼운 것이라고 했죠. 이제 실제로 손을 움직일 차례입니다. 오늘의 목표는 하나입니다. &lt;strong&gt;내 휴대폰 화면에 내가 만든 앱을 띄우는 것.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;웹에서는 이 단계가 아주 가벼웠습니다. HTML로 개발된 문서를 로컬이나 서버에 올려서 브라우저로 열면 끝이었으니까요. 그러나 모바일 앱은 사정이 다릅니다. 앱은 OS 위에서 돌아가고, 그 OS에 ‘설치’되어 동작하기 때문에 제약이 많습니다. 그래서 “만든 것을 어떻게 OS에서 매끄럽게 돌아가도록 빌드(Build)하고 배포할까”가 처음부터 문제가 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;barenative-build-vs-expo&quot;&gt;Bare(Native) Build vs. Expo&lt;/h2&gt;
&lt;p&gt;React Native 프로젝트를 통해 앱을 배포하는 방법은 크게 두 가지입니다.&lt;/p&gt;
&lt;p&gt;하나는 &lt;strong&gt;bare(순정) 워크플로&lt;/strong&gt;입니다. iOS 프로젝트와 Android 프로젝트를 직접 각각 빌드하고 배포하는 방식입니다. 그러려면 Mac에 Xcode를, 그리고 Android Studio와 JDK를 설치하고 시뮬레이터·에뮬레이터를 세팅해야 합니다. 각 OS에 대해 이해도가 있어야 하는데, 특히 네이티브 빌드가 실패하면 Gradle이나 CocoaPods 같은 복잡한 도구의 오류 메시지와 씨름하게 됩니다.&lt;/p&gt;
&lt;p&gt;다른 하나는 &lt;strong&gt;Expo&lt;/strong&gt;입니다. Expo는 이 네이티브 층을 대신 관리해줍니다. 우리가 자바스크립트만 쓰면, 실행에 필요한 네이티브 껍데기는 Expo가 준비된 형태로 제공합니다. 덕분에 Xcode나 Android Studio 없이도 개발을 시작할 수 있고, iPhone이 없어도 Android에서, Mac이 없어도 앱을 만들 수 있습니다. 지금은 React Native 공식 문서도 새로 시작하는 사람에게 Expo를 기본으로 권합니다. 단 단점 또한 있는데, Expo로 한번 감싸지기 때문에 Expo가 제공하는 라이브러리들을 써야 하고 네이티브 제어가 제한됩니다.&lt;/p&gt;
&lt;p&gt;때문에 “나중에 네이티브를 깊게 건드려야 하면 어떡하나”라는 걱정이 자연스럽게 따라옵니다. 예전에는 이 지점에서 Expo를 버리고 나가는(eject) 큰 결단이 필요했지만, 지금은 그렇지 않습니다. 필요해지면 네이티브 코드를 열어 함께 쓸 수 있는 길이 열려 있습니다. &lt;strong&gt;시작할 때 미래를 저당 잡히는 선택이 아니라는 뜻입니다.&lt;/strong&gt; 그러니 처음에는 고민 없이 Expo로 시작하는 편이 낫습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;프로젝트-만들기&quot;&gt;프로젝트 만들기&lt;/h2&gt;
&lt;p&gt;Node.js가 설치되어 있다면 준비는 끝났습니다. 터미널에서 이 한 줄이면 프로젝트가 생깁니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; create-expo-app@latest&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; my-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; my-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;npx&lt;/code&gt;는 패키지를 전역 설치하지 않고 그때그때 내려받아 실행합니다. 웹에서 &lt;code&gt;create-vite&lt;/code&gt;나 &lt;code&gt;create-next-app&lt;/code&gt;을 쓰던 것과 같은 감각입니다.&lt;/p&gt;
&lt;p&gt;만들어진 폴더를 열어보면 낯익은 것들이 보입니다. &lt;code&gt;package.json&lt;/code&gt;이 있고, &lt;code&gt;node_modules&lt;/code&gt;가 있고, 자바스크립트 파일들이 있습니다. 지난 편에서 말한 “React 생태계는 그대로 쓴다”는 이야기가 여기서 확인됩니다. 눈에 띄게 다른 것은 &lt;code&gt;app/&lt;/code&gt; 폴더인데, 이 안의 파일 구조가 곧 앱의 화면 구조가 됩니다. 웹의 파일 기반 라우팅과 비슷한 방식이고, 화면 이동 이야기는 6편에서 제대로 다루겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;실제-기기에-띄우기&quot;&gt;실제 기기에 띄우기&lt;/h2&gt;
&lt;p&gt;이제 개발 서버를 켭니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; expo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; start&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;터미널에 QR 코드가 하나 뜹니다. 여기서부터가 웹과 완전히 다른 부분입니다. &lt;strong&gt;휴대폰에 Expo Go 앱을 설치하고, 그 QR 코드를 찍으세요.&lt;/strong&gt; 잠시 뒤 방금 만든 앱이 손안의 기기에서 실행됩니다. Xcode도, 에뮬레이터도, 케이블도 필요 없습니다.&lt;/p&gt;
&lt;p&gt;이게 가능한 이유를 알아두면 이후에 문제가 생겼을 때 당황하지 않습니다. Expo Go는 &lt;strong&gt;네이티브 껍데기가 미리 완성되어 있는 앱&lt;/strong&gt;입니다. 개발 서버는 우리가 쓴 자바스크립트만 묶어서 내보내고, Expo Go가 그것을 받아 자기 안에서 실행합니다. 즉 우리는 앱을 빌드해 설치한 게 아니라, &lt;strong&gt;이미 설치된 껍데기에 내 자바스크립트를 실어 보낸 것&lt;/strong&gt;입니다. 컴퓨터와 휴대폰이 같은 와이파이에 있어야 하는 이유도 여기 있습니다. QR을 찍었는데 연결이 안 된다면 십중팔구 네트워크가 갈라져 있는 것입니다.&lt;/p&gt;
&lt;p&gt;시뮬레이터·에뮬레이터를 쓰고 싶다면 터미널에서 &lt;code&gt;i&lt;/code&gt;(iOS)나 &lt;code&gt;a&lt;/code&gt;(Android)를 누르면 됩니다. 이 경우엔 Xcode나 Android Studio가 필요합니다. 웹으로 확인하고 싶다면 &lt;code&gt;w&lt;/code&gt;를 누르면 브라우저에서도 열립니다. 다만 웹에서 잘 보인다고 안심하면 안 됩니다. 우리가 만드는 것은 결국 네이티브 화면이고, 그 진짜 모습은 기기에서 확인해야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;첫-화면-고쳐보기&quot;&gt;첫 화면 고쳐보기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;app/index.tsx&lt;/code&gt;(혹은 &lt;code&gt;.jsx&lt;/code&gt;)를 열고 내용을 지운 뒤 이렇게 바꿔봅시다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { View, Text } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react-native&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Home&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;View&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; style&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ flex: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, alignItems: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;center&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, justifyContent: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;center&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;안녕하세요, React Native.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Text&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;View&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;저장하는 순간 휴대폰 화면이 바뀝니다. 웹에서 익숙한 그 &lt;strong&gt;빠른 새로고침(Fast Refresh)&lt;/strong&gt;이 그대로 작동합니다. 코드를 고치고 저장하면 즉시 반영되고, 그 과정에서 컴포넌트의 State는 최대한 유지됩니다. 이 짧은 왕복이 React Native로 개발하는 즐거움의 큰 부분입니다.&lt;/p&gt;
&lt;p&gt;이 짧은 코드에 지난 편에서 예고한 것들이 이미 다 들어 있습니다. &lt;code&gt;div&lt;/code&gt;가 아니라 &lt;code&gt;View&lt;/code&gt;를 썼고, 글자를 그냥 두지 않고 &lt;code&gt;Text&lt;/code&gt;로 감쌌습니다. 스타일은 CSS 파일이 아니라 자바스크립트 객체로 넘겼고, &lt;code&gt;flex: 1&lt;/code&gt;은 “남은 공간을 다 차지하라”는 뜻입니다. 각각이 3편과 4편의 주제입니다. 지금은 “아, 이렇게 생겼구나” 정도로 눈에 익혀두면 충분합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;자주-막히는-곳&quot;&gt;자주 막히는 곳&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;QR을 찍었는데 앱이 안 뜬다.&lt;/strong&gt; 대부분 네트워크 문제입니다. 컴퓨터와 휴대폰이 같은 와이파이에 있는지 보세요. 회사나 카페의 공용 와이파이는 기기 간 통신을 막아두는 경우가 있는데, 이럴 때는 &lt;code&gt;npx expo start --tunnel&lt;/code&gt;로 우회할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;저장했는데 화면이 안 바뀐다.&lt;/strong&gt; 터미널에서 &lt;code&gt;r&lt;/code&gt;을 눌러 새로고침해보세요. 그래도 안 되면 개발 서버를 껐다 켜는 편이 빠릅니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;웹에서는 되는데 기기에서 깨진다.&lt;/strong&gt; 정상입니다. 웹 미리보기는 편의 기능일 뿐이고, 두 환경은 렌더링 방식이 다릅니다. 기기에서 본 것이 진짜입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정리하며&quot;&gt;정리하며&lt;/h2&gt;
&lt;p&gt;오늘 한 일은 단순하지만 중요합니다. &lt;strong&gt;자바스크립트를 고치면 손안의 기기에 즉시 반영되는 왕복 고리&lt;/strong&gt;를 만들었습니다. 앞으로의 모든 편은 이 고리 위에서 진행됩니다. 무언가를 배우면 바로 화면에서 확인할 수 있다는 뜻입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 방금 슬쩍 등장한 &lt;code&gt;View&lt;/code&gt;와 &lt;code&gt;Text&lt;/code&gt;를 제대로 다룹니다. &lt;code&gt;div&lt;/code&gt;도 &lt;code&gt;span&lt;/code&gt;도 없는 세계에서 화면은 무엇으로 만들어지는지, 그리고 왜 글자를 반드시 &lt;code&gt;Text&lt;/code&gt;로 감싸야 하는지를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>모바일 앱을 위한 React Native</category><category>React Native</category><category>Expo</category><category>개발환경</category><category>모바일 앱</category></item><item><title>모든 판단을 자신의 안목으로만 내리는 위험에 대하여 — 내 눈만 믿을 때, 조직은 눈을 감는다</title><link>https://blog.bepuljang.co.kr/startup-prince/07/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/07/</guid><description>『스타트업 군주론』 2부의 세 번째 이야기. 창업자의 안목은 회사를 여기까지 끌고 온 자산이지만, 모든 판단의 유일한 기준이 되는 순간 조직의 눈을 감기게 합니다. 마키아벨리가 신하의 등용을 군주의 첫 번째 능력으로 꼽은 이유를 빌려 살펴봅니다.</description><pubDate>Tue, 14 Jul 2026 13:33:05 GMT</pubDate><content:encoded>&lt;p&gt;앞 편에서는 지시가 아니라 이해로 조직을 움직이는 일을 이야기했습니다. 맥락을 건네고, 판단의 기준을 나누고, 대표가 보지 않는 자리에서도 사람이 스스로 움직이게 하는 일이었습니다. 그런데 여기까지 온 대표들이 자주 걸려 넘어지는 다음 관문이 있습니다. 맥락은 열심히 나눠주면서도, 정작 &lt;strong&gt;결정은 여전히 자기 눈으로만 내리는&lt;/strong&gt; 것입니다.&lt;/p&gt;
&lt;p&gt;창업자의 안목은 회사의 자산입니다. 아무도 보지 못한 기회를 알아봤기 때문에 회사가 시작됐고, 수많은 갈림길에서 그의 판단이 맞았기 때문에 여기까지 왔습니다. 문제는 바로 그 성공의 기록이 위험한 확신을 만든다는 데 있습니다. &lt;strong&gt;“결국 내 판단이 제일 정확하더라.”&lt;/strong&gt; 이 문장이 조직 안에서 유일한 기준이 되는 순간, 회사는 대표의 시야 크기를 넘어서 자랄 수 없게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;결정이-전부-한-사람을-통과하는-회사&quot;&gt;결정이 전부 한 사람을 통과하는 회사&lt;/h2&gt;
&lt;p&gt;증상은 대개 개입의 형태로 나타납니다. 담당자가 정한 것을 대표가 다시 뒤집습니다. 디자인 시안을 최종적으로 고르는 것도, 채용의 마지막 판단도, 문구 하나의 표현까지도 결국 대표의 손을 거칩니다. 대표는 이것을 성실함이라고 여깁니다. 회사의 모든 것에 책임을 지고 있으니 당연하다고 생각하죠.&lt;/p&gt;
&lt;p&gt;그런데 이 상태가 반복되면 조직에서 일어나는 일은 이렇습니다. 담당자는 점차 자기 판단을 내리는 대신 &lt;strong&gt;“대표님은 어떻게 생각하실까”를 추측하기 시작합니다.&lt;/strong&gt; 자신의 전문성으로 최선의 안을 만드는 대신, 대표의 취향을 통과할 안을 만듭니다. 회의에서 의견을 말하기보다 대표의 표정을 봅니다. 겉으로 조직은 조용하고 효율적으로 보이지만, 실제로는 &lt;strong&gt;모두가 눈을 감고 대표 한 사람의 눈만 뜨고 있는 상태&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;여기서 가장 뼈아픈 대목은, 대표가 뽑은 사람들이 대개 자기보다 그 분야를 더 잘 아는 사람들이라는 것입니다. 비싼 값을 치르고 전문가를 데려와서는, 정작 그 전문성이 발휘될 자리마다 자기 판단으로 덮어씁니다. 회사는 열 사람의 안목을 가질 수 있었는데 여전히 한 사람의 안목으로 굴러갑니다.&lt;/p&gt;
&lt;h2 id=&quot;마키아벨리가-신하를-보는-눈&quot;&gt;마키아벨리가 신하를 보는 눈&lt;/h2&gt;
&lt;p&gt;『군주론』에서 마키아벨리는 군주의 능력을 가늠하는 첫 번째 척도로 &lt;strong&gt;그가 곁에 누구를 두었는가&lt;/strong&gt;를 꼽습니다. 신하가 유능하고 충직하면 그 군주는 현명한 사람이라고 평가할 수 있는데, 사람을 알아보고 그 능력을 유지시켰기 때문이라는 것입니다. 반대로 곁에 있는 사람들이 무능하다면, 군주에 대한 평가는 거기서 이미 내려집니다. 그 선택 자체가 첫 번째 실책이기 때문입니다.&lt;/p&gt;
&lt;p&gt;주목할 것은 마키아벨리가 지성을 세 종류로 나눈 대목입니다. &lt;strong&gt;스스로 이해하는 지성, 남이 이해한 것을 알아보는 지성, 그리고 스스로도 남을 통해서도 이해하지 못하는 지성.&lt;/strong&gt; 그는 첫 번째가 가장 뛰어나고 두 번째가 그다음이며 세 번째는 쓸모없다고 했습니다. 여기서 중요한 것은 &lt;strong&gt;두 번째가 무능이 아니라 훌륭함의 범주에 들어 있다는 사실&lt;/strong&gt;입니다. 모든 것을 혼자 꿰뚫어 보지 못해도, 남이 옳게 본 것을 알아보고 채택할 줄 안다면 그 군주는 충분히 유능합니다.&lt;/p&gt;
&lt;p&gt;이 구분이 창업자에게 던지는 질문은 이것입니다. 나는 지금 첫 번째 지성이 되려고 애쓰다가, 정작 &lt;strong&gt;두 번째 지성을 발휘할 기회마저 스스로 닫고 있는 것은 아닌가.&lt;/strong&gt; 모든 것을 내가 가장 잘 봐야 한다는 강박은 종종 남이 더 잘 본 것을 알아보지 못하게 만듭니다.&lt;/p&gt;
&lt;h2 id=&quot;안목은-자산이지만-유일한-기준일-때-부채가-된다&quot;&gt;안목은 자산이지만, 유일한 기준일 때 부채가 된다&lt;/h2&gt;
&lt;p&gt;오해를 피해야 합니다. 이 이야기는 대표가 판단을 내려놓고 모든 것을 다수결에 부치라는 뜻이 아닙니다. 회사의 방향, 무엇을 하지 않을 것인가, 어디에 자원을 걸 것인가 같은 결정은 여전히 대표의 몫입니다. 3편에서 본 것처럼 남의 힘에 기대는 회사가 위태로운 것과 같은 이치로, 대표가 자기 판단을 포기한 회사도 방향을 잃습니다.&lt;/p&gt;
&lt;p&gt;구분해야 할 것은 &lt;strong&gt;판단의 권한이 아니라 판단의 재료&lt;/strong&gt;입니다. 위험한 것은 대표가 결정한다는 사실이 아니라, 그 결정이 &lt;strong&gt;오직 자기 눈에서만 나온 재료로&lt;/strong&gt; 만들어진다는 사실입니다. 자기 안목만이 유일한 입력값인 회사는 대표가 아는 만큼만 알고, 대표가 보는 곳만 봅니다. 대표가 틀린 날에는 그 틀림을 잡아줄 장치가 조직 안에 하나도 없습니다.&lt;/p&gt;
&lt;p&gt;그리고 확신은 시간이 지날수록 강해집니다. 대표의 판단이 계속 채택되고 그 결과가 나쁘지 않았다면, 그것은 대표가 옳았다는 증거처럼 보입니다. 하지만 애초에 다른 판단이 시도된 적이 없다면, 그 기록은 &lt;strong&gt;대표의 안목이 옳았다는 증거가 아니라 다른 안목이 시도될 기회가 없었다는 기록&lt;/strong&gt;일 뿐입니다.&lt;/p&gt;
&lt;h2 id=&quot;눈을-하나-더-뜨게-하는-일&quot;&gt;눈을 하나 더 뜨게 하는 일&lt;/h2&gt;
&lt;p&gt;방법은 거창하지 않습니다. 결정의 순간에 자기 판단을 먼저 말하지 않는 것에서 시작합니다. 대표가 먼저 결론을 꺼내는 순간, 그 자리의 논의는 이미 대표의 안을 검증하는 자리로 좁아집니다. 담당자의 안을 먼저 듣고, 그가 왜 그렇게 판단했는지를 묻고, 그 근거가 자기 것보다 나은지를 따지는 순서가 되어야 합니다.&lt;/p&gt;
&lt;p&gt;되돌릴 수 있는 결정과 되돌릴 수 없는 결정을 갈라두는 것도 방법입니다. 되돌릴 수 있는 일이라면 대표의 안목과 다르더라도 담당자의 판단대로 가보게 두는 편이 낫습니다. 조직이 자기 판단으로 결정하고 그 결과를 확인하는 경험을 쌓지 못하면, 판단할 줄 아는 사람은 영영 늘지 않습니다. 대표의 안목이 반드시 관철되어야 하는 자리는 생각보다 적습니다.&lt;/p&gt;
&lt;p&gt;무엇보다 필요한 것은 &lt;strong&gt;자기 판단이 틀렸음을 확인하는 경험을 두려워하지 않는 것&lt;/strong&gt;입니다. 대표가 자기 안이 밀린 자리에서 불편해하는 기색을 한 번 보이면, 조직은 그것을 정확히 읽고 다시 눈을 감습니다. 반대로 대표가 “그 판단이 내 것보다 낫다”고 말하는 장면을 한 번 보여주면, 그때부터 사람들은 자기 눈으로 보기 시작합니다. 마키아벨리의 표현을 빌리면, 그것이 두 번째 지성—&lt;strong&gt;남이 옳게 본 것을 알아보는 능력&lt;/strong&gt;—이 조직 안에서 작동하기 시작하는 순간입니다.&lt;/p&gt;
&lt;p&gt;점검할 질문은 단순합니다. 최근 한 달 동안, &lt;strong&gt;내 판단이 아니라 구성원의 판단대로 간 결정이 몇 개나 있었는가.&lt;/strong&gt; 하나도 떠오르지 않는다면, 조직은 지금 눈을 감고 있는 중입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 이 문제의 다른 얼굴을 다룹니다. 대표가 아무리 남의 눈을 빌리려 해도, 그에게 도달하는 정보 자체가 이미 걸러지고 다듬어진 것이라면 어떻게 될까요. 나쁜 소식이 대표의 문턱을 넘지 못하는 조직에 관한 이야기입니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>리더십</category><category>의사결정</category><category>스타트업 군주론</category></item><item><title>분석의 도구들 — 데이터가 아직 말을 하지 않을 때</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/11/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/11/</guid><description>카드 정렬법부터 친화도법, KJ 매핑, POV 문장, HMW 질문까지 — 파편화된 관찰 데이터에서 구조와 의미를 읽어내는 분석의 도구들을 소개합니다.</description><pubDate>Tue, 14 Jul 2026 11:47:50 GMT</pubDate><content:encoded>&lt;p&gt;데이터가 쌓였는데 무엇을 의미하는지 모르겠을 때 꺼내는 도구들입니다. 관찰은 즐겁고 인사이트 넘치는 과정이지만, 관찰한 데이터 자체는 파편적이고, 지엽적이며, 주관적이기 쉽습니다. 개인의 문제와 집단의 문제가 뒤섞여 있고, 특수한 상황이 보편적 패턴처럼 보이기도 합니다. 분석의 도구들은 이 파편들 사이에서 구조를 발견하고, 의미를 읽어내기 위한 것입니다.&lt;/p&gt;
&lt;p&gt;여기서 소개하는 도구들은 특정 프로젝트 단계에 묶여 있지 않습니다. 데이터가 있고, 그 데이터가 아직 말을 하지 않을 때 언제든 꺼내 쓸 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;카드-정렬법-card-sorting&quot;&gt;카드 정렬법 (Card Sorting)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 데이터는 이미 알고 있는 어떤 범주에 속하는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;기존에 정의된 분류 기준이 있을 때, 새로운 관찰 결과를 그 기준에 맞춰 배치하는 방법입니다. 예를 들어 어떤 서비스의 ‘회원’, ‘결제’, ‘매장’ 등의 범주가 이미 존재한다면, 관찰에서 발견된 내용들을 해당 범주에 분류하고 그 안에서 경험적 인사이트를 정의해 나갑니다. 스크린이나 기능 목록이 있는 상태에서 새로운 관찰들을 스크린별, 기능별로 모아보는 것도 같은 접근입니다.&lt;/p&gt;
&lt;p&gt;통계학적으로 보면 라벨이 이미 존재하는 상태에서 데이터를 분류하는 Top-down 방식이며, 기계학습의 용어를 빌리면 지도 학습(Supervised Learning)에 대응됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: 기존 분류 체계가 관찰 결과를 왜곡할 수 있습니다. 기준에 맞지 않는 데이터가 억지로 끼워 넣어지거나, 기존 범주에 속하지 않는 새로운 발견이 무시되기 쉽습니다. 분류되지 않는 데이터가 많다면, 범주 자체를 의심해야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;친화도법-affinity-diagram&quot;&gt;친화도법 (Affinity Diagram)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 데이터들 사이에 아직 발견되지 않은 구조가 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;분류 기준이 아직 정해져 있지 않은 관찰 내용들을 모아, 유사도에 따라 배치하고, 그 군집을 정의하면서 인사이트를 수립해가는 Bottom-up 방식입니다. 기계학습으로 비유하면 비지도 학습(Unsupervised Learning), 즉 군집 분석(Cluster Analysis)에 해당합니다.&lt;/p&gt;
&lt;p&gt;프로젝트 진행자의 선입견이나 관념에서 벗어나 데이터 자체에 집중할 수 있다는 점에서, 문제나 수요를 새롭게 정의하고 싶을 때 유용합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: 군집의 경계는 분석자의 판단에 의존합니다. 같은 데이터라도 누가 배치하느냐에 따라 완전히 다른 구조가 나올 수 있으므로, 가능하다면 여러 사람이 독립적으로 군집화한 뒤 비교하는 것이 좋습니다.&lt;/p&gt;
&lt;h2 id=&quot;kj-매핑-kj-mapping&quot;&gt;KJ 매핑 (KJ Mapping)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“데이터 간의 거리와 관계를 시각적으로 드러낼 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;일본의 인류학자 카와기타 지로(Kawakita Jiro)의 이름을 딴 이 방법은, 친화도법의 세분화된 일종으로 각 데이터 간 친화도에 따라 거리를 조정하는 방식으로 지도화(Mapping)하는 방법입니다.&lt;/p&gt;
&lt;p&gt;Affinity Diagram과 KJ Mapping은 혼용되며 거의 동의어처럼 여겨지는 경우가 많은데, 엄밀히는 다릅니다. 도식화(Diagramming)는 지도화(Mapping)보다 더 넓은 범주의 용어입니다. KJ Mapping은 친화도를 기준으로 도식화하되 좌표와 거리를 사용하는 지도화 방법이므로, 친화도법의 한 가지 구체적 실행 방식으로 보는 것이 바람직합니다.&lt;/p&gt;
&lt;p&gt;여기서 ‘지도(Map)‘라는 단어에 주목할 필요가 있습니다. 어떤 기법이 Map이라는 이름을 사용한다면, X/Y축의 2차원 좌표가 의미를 가지며 데이터 간의 거리나 상대적 위치가 분석의 핵심이 된다는 뜻입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: 각 관찰 내용을 데이터화하고 그 사이의 거리를 계산하여 배치하는 과정이 핵심인데, 이 데이터화와 계산의 적합성에 따라 군집의 성격이나 결과가 완전히 달라질 수 있습니다. 전처리가 부실하면 지도 자체가 왜곡됩니다.&lt;/p&gt;
&lt;h2 id=&quot;데이터-전처리-카드-작성법&quot;&gt;데이터 전처리: 카드 작성법&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“파편화된 관찰을 분석 가능한 단위로 어떻게 정제하는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;카드 정렬이든 친화도법이든, 관찰 결과를 분석하기 좋은 데이터로 정제하는 전처리 과정이 먼저 필요합니다. 통계에서 이야기하는 데이터 전처리와 같은 맥락으로, 지나치게 지엽적인 데이터(outlier)나 모호한 관측 결과, 하나의 카드에 복합적인 내용이 뒤섞인 데이터를 걸러내고 정돈해야 합니다.&lt;/p&gt;
&lt;p&gt;추천하는 방식은 관찰 대상인 사용자를 주어로 하는 서술형으로 카드를 작성하는 것입니다. 이렇게 하면 지도화할 때 내용을 파악하기 편하고, 혼란이 줄어듭니다.&lt;/p&gt;
&lt;p&gt;예를 들어 터치식 키오스크 UI 앞에서 주문하려다 어떤 버튼을 눌러야 할지 고민하다 돌아서는 사용자를 관찰했다고 하겠습니다. 이때 카드를 “복잡한 터치식 키오스크 UI”로 적는 대신, &lt;strong&gt;“주문을 하고 싶은데 어딜 눌러야 할지 모르겠어.”&lt;/strong&gt;로 작성하면 상황과 사용자의 감정이 분명하게 드러납니다. 해당 카드가 위치할 분류도 명확해지고, 사용자의 감정에 동기화하는 군집으로 발전시키기가 수월해집니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: 서술형 카드를 쓸 때 관찰자의 해석이 아니라 사용자의 목소리를 담아야 합니다. “UI가 불편하다”는 관찰자의 판단이고, “어딜 눌러야 할지 모르겠어”는 사용자의 경험입니다.&lt;/p&gt;
&lt;h2 id=&quot;pov-문장-point-of-view-statement&quot;&gt;POV 문장 (Point of View Statement)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“관찰을 하나의 관점으로 전환할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;POV 문장은 흩어진 관찰과 분석 결과를 하나의 명확한 관점으로 압축하는 도구입니다. 형식은 다음과 같습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“[사용자]는 [필요/욕구]가 필요하다, 왜냐하면 [인사이트]이기 때문이다.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;예를 들어: “혼자 키오스크를 처음 사용하는 고령 사용자는 첫 화면에서 명확한 안내가 필요하다, 왜냐하면 잘못된 버튼을 누르면 되돌릴 수 없다고 생각하기 때문이다.”&lt;/p&gt;
&lt;p&gt;이 형식이 강제하는 것은 사용자(누구), 필요(무엇), 인사이트(왜)의 세 요소를 한 문장 안에 담는 것입니다. 분석에서 발견한 패턴을 디자인 가능한 관점으로 전환하는 다리 역할을 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: POV 문장이 너무 넓으면(“사용자는 좋은 경험이 필요하다”) 방향을 잡을 수 없고, 너무 좁으면(“사용자는 파란색 버튼이 필요하다”) 이미 해결책을 전제하게 됩니다. 인사이트 부분이 핵심인데, ‘왜냐하면’ 이후가 관찰에서 발견한 진짜 이유여야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;hmw-질문-how-might-we&quot;&gt;HMW 질문 (How Might We)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“문제를 해결 가능한 기회로 전환할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HMW는 “어떻게 하면 우리가 ___할 수 있을까?” 형식의 질문으로, 발견된 문제를 디자인 기회로 재구성하는 도구입니다. POV 문장에서 출발하는 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;위의 키오스크 예시라면: “어떻게 하면 처음 사용하는 고령 사용자가 실수를 두려워하지 않고 주문할 수 있을까?”&lt;/p&gt;
&lt;p&gt;HMW 질문의 힘은 제약이 아닌 가능성의 언어로 문제를 바라보게 한다는 데 있습니다. “키오스크가 어렵다”는 진단에서 멈추는 대신, “어떻게 하면”이라는 프레임이 구체적인 탐색 방향을 열어줍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점&lt;/strong&gt;: HMW 질문도 POV와 마찬가지로 적정한 범위가 중요합니다. “어떻게 하면 모든 사용자를 만족시킬 수 있을까?”는 너무 넓고, “어떻게 하면 글씨 크기를 키울 수 있을까?”는 이미 답을 품고 있습니다. 좋은 HMW 질문은 여러 방향의 해결책이 떠오를 만큼 열려 있되, 구체적인 사용자와 맥락에 닿아 있어야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;마무리&quot;&gt;마무리&lt;/h2&gt;
&lt;p&gt;이 도구들은 모두 같은 방향을 가리킵니다. 파편화된 관찰을 구조화된 이해로 옮기는 것입니다. 카드 정렬은 기존 구조 안에서 데이터를 배치하고, 친화도법은 데이터로부터 새로운 구조를 발견하며, POV와 HMW는 그 구조를 디자인 가능한 언어로 전환합니다.&lt;/p&gt;
&lt;p&gt;다만 잊지 말아야 할 것이 있습니다. 분석의 구조는 사용자의 목소리를 더 선명하게 들려주기 위한 것이지, 그 목소리를 대체하기 위한 것이 아닙니다. 영감과 직관에 휩쓸리다 보면 모든 절차가 자칫 견강부회(牽强附會)로 끝날 수 있습니다. 선입견과 예측을 배제하고 데이터 자체에 집중해야 비로소 관찰이 살아있는 구조로 전환됩니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 표현의 도구들을 다룹니다. 분석을 통해 얻은 사용자에 대한 이해를 팀과 공유하기 위한 도구들 — 페르소나, 공감지도 등을 살펴봅니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>분석 도구</category><category>친화도법</category><category>카드 정렬법</category></item><item><title>표현의 도구들 — 보이지 않는 것을 팀과 나누는 법</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/12/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/12/</guid><description>사용자에 대한 이해는 개인의 머릿속에만 머물러서는 안 됩니다. 페르소나, 공감 지도, 시나리오, 여정 지도, 스토리보드 — 보이지 않는 사용자 경험을 팀과 나누기 위한 다섯 가지 도구를 살펴봅니다.</description><pubDate>Tue, 14 Jul 2026 11:47:50 GMT</pubDate><content:encoded>&lt;p&gt;사용자를 관찰하고, 분석하고, 정의하는 과정을 거치면 우리의 머릿속에는 사용자에 대한 이해가 형성됩니다. 그런데 이 이해는 아직 개인의 내면에 머물러 있습니다. 디자인은 혼자 하는 일이 아니기에, 이 이해를 팀원들과 나누어야 합니다. 사용자와 그들의 경험을 팀원들과 공유해야 할 때 꺼내는 도구들이 이 글에서 다룰 것들입니다.&lt;/p&gt;
&lt;p&gt;이 도구들에는 공통점이 있습니다. 보이지 않는 것을 보이게 만든다는 점입니다. 사용자의 동기, 감정, 맥락, 여정—이런 것들은 눈에 보이지 않습니다. 이 도구들은 그 보이지 않는 것에 형태를 부여하여, 팀이 같은 것을 보고 같은 방향으로 나아갈 수 있게 해줍니다.&lt;/p&gt;
&lt;h2 id=&quot;페르소나-persona&quot;&gt;페르소나 (Persona)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“우리가 디자인하는 대상은 누구인가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;페르소나는 사용자 집단을 대표하는 가상의 인물을 만드는 작업입니다. 이름, 프로필 이미지, 직업, 연령 같은 기본 정보에 성격, 기호, 목표 등을 더해 한 사람의 인격을 구성합니다. 이 구성요소들이 모두 필수인 것은 아닙니다. ‘사용자를 상상할 수 있는 최소한의 정보’를 우선 갖추되, 이 페르소나가 디자인의 판단 기준으로서 충분한지를 점검하면서 채워나가면 됩니다.&lt;/p&gt;
&lt;p&gt;특히 중요한 것이 태그라인입니다. 페르소나의 핵심 관심사나 수요를 한 문장으로 정리한 것인데, 디자인 과정에서 페르소나를 자세히 들여다볼 여유가 없을 때 이 한 문장이 나침반이 되어줍니다. “이런 문장을 가슴에 품고 사는 사람이라면 이 디자인에서의 경험을 좋아할까?”—이 질문 하나로 사용자를 환기할 수 있기 때문입니다. 태그라인을 신중하게 다듬을수록, 이후 과정에서 사용자 관찰의 통찰이 일관되게 반영됩니다.&lt;/p&gt;
&lt;p&gt;더블 다이아몬드를 떠올려보면, 페르소나는 딱 두 다이아몬드가 만나는 꼭지점에 있습니다. 관찰과 정의를 통해 함축된 정보이자, 앞으로 확장될 경험 설계의 출발점입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 나쁜 페르소나는 프로젝트 전체를 혼란에 빠뜨립니다. 템플릿의 모든 칸을 채워야 한다는 강박에 무책임하게 속성을 지어내거나, 사용자 집단과 어울리지 않는 이름이나 연예인 이미지를 쓰거나, 시나리오에 맞춰 페르소나를 역으로 조작하는 행위는 절대 피해야 합니다. 불확실한 속성은 차라리 빼고 간결하게 구성하는 편이 낫습니다.&lt;/p&gt;
&lt;p&gt;무엇보다 강조하고 싶은 것은, 관찰 없는 페르소나는 허상이라는 점입니다. 페르소나는 사용자 관찰과 정의를 집대성한 결과물이어야 합니다. 하늘에서 떨어진 페르소나는 프로젝트의 전반부와 후반부를 단절시키고, UX 디자인 과정을 진행한 의미 자체를 잃어버리게 만듭니다.&lt;/p&gt;
&lt;h2 id=&quot;공감-지도-empathy-map&quot;&gt;공감 지도 (Empathy Map)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자의 내면에서는 무슨 일이 벌어지고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;공감 지도는 사용자의 경험을 네 가지 사분면으로 나누어 기록하는 도구입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Says (말하는 것)&lt;/strong&gt;: 사용자가 직접 말한 표현, 인터뷰나 관찰 중의 발화&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thinks (생각하는 것)&lt;/strong&gt;: 사용자가 말하지는 않았지만 드러나는 내면의 생각, 기대, 의문&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Does (행동하는 것)&lt;/strong&gt;: 관찰된 구체적인 행동과 행위 패턴&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feels (느끼는 것)&lt;/strong&gt;: 사용자의 감정 상태—불안, 기대, 좌절, 만족 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;페르소나가 사용자의 외적 윤곽을 그린다면, 공감 지도는 그 안쪽을 들여다봅니다. 특히 Says와 Thinks 사이의 간극, 즉 사용자가 말하는 것과 실제로 생각하는 것 사이의 차이가 드러날 때 깊은 통찰이 생깁니다. 사용자가 “괜찮아요, 쓸만해요”라고 말하면서도(Says) 같은 버튼을 세 번 누르고 있다면(Does), 그 사이에 무언가가 있는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 공감 지도는 관찰 데이터를 정리하는 도구이지, 상상을 정리하는 도구가 아닙니다. 네 사분면을 채우는 내용은 실제 관찰과 인터뷰에서 나온 것이어야 합니다. 또한 Thinks와 Feels는 관찰자의 해석이 개입되는 영역이므로, 해석의 근거가 되는 관찰 사실을 함께 기록하는 습관이 필요합니다.&lt;/p&gt;
&lt;h2 id=&quot;시나리오-scenario&quot;&gt;시나리오 (Scenario)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자는 어떤 맥락에서 어떤 경험을 하게 되는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;시나리오는 페르소나가 특정 상황에서 목표를 달성하기 위해 겪는 일련의 과정을 서술형으로 기술한 것입니다. 핵심은 ‘서술형’이라는 점입니다. 시나리오는 기능 목록이 아니라 이야기(narrative)의 형태를 취합니다. 기능 목록은 ‘무엇을’만 말하지만, 시나리오는 ‘언제, 어디서, 왜, 어떤 기분으로’까지 담아냅니다.&lt;/p&gt;
&lt;p&gt;‘사용자가 상품을 검색하고 장바구니에 담는다’는 기능 명세입니다. 반면 ‘퇴근길 지하철에서 내일 있을 친구 생일 선물을 고르려는 지민씨는, 한 손으로 스마트폰을 잡은 채 검색창에 “30대 남성 선물”을 입력한다. 검색 결과가 너무 많아 스크롤을 내리다가 지하철이 흔들려 의도치 않은 상품을 누르게 되고…’는 시나리오입니다. 후자에는 맥락, 제약, 감성, 예상치 못한 상황이 담겨 있습니다.&lt;/p&gt;
&lt;p&gt;시나리오는 목적에 따라 나뉩니다. 현행 시나리오(As-Is)는 사용자가 현재 겪고 있는 경험을 기술하여 어디에서 문제가 발생하는지를 드러내고, 목표 시나리오(To-Be)는 디자인을 통해 개선된 미래의 경험을 기술하여 변화의 방향을 제시합니다. 이 둘의 대비를 통해 디자인이 무엇을 바꾸려 하는지가 선명해집니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 좋은 시나리오는 페르소나에 뿌리를 두어야 합니다. 페르소나의 성격과 태그라인이 시나리오 속 행동의 근거가 되어야 하며, 사용 맥락과 감성의 흐름이 충실히 반영되어야 합니다. 페르소나와 단절된 시나리오는 디자이너의 상상에 불과합니다.&lt;/p&gt;
&lt;h2 id=&quot;여정-지도-user-journey-map&quot;&gt;여정 지도 (User Journey Map)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“경험의 전체 흐름에서 어디가 무너지고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여정 지도는 시나리오를 시각적으로 표현한 것입니다. 시간의 흐름을 가로축에, 사용자의 감성이나 만족도를 세로축에 배치하여 경험의 기복을 한눈에 보여줍니다.&lt;/p&gt;
&lt;p&gt;여정 지도의 강점은 전체적인 리듬의 조망입니다. 개별 절차에 몰입하다 보면 놓치기 쉬운 것들—부정적 경험이 연속되는 구간, 감성적 고점이 없는 평탄한 여정 같은 것들—이 지도 위에서는 분명하게 드러납니다.&lt;/p&gt;
&lt;p&gt;이 지도를 구성하는 핵심 개념이 두 가지 있습니다. 터치포인트(Touchpoint)는 사용자가 제품이나 서비스와 접촉하는 모든 순간입니다. 광고를 보는 순간, 앱을 다운로드하는 순간, 고객센터에 전화하는 순간 등이 모두 터치포인트이며, 각 지점에서 사용자는 감성적 반응을 형성합니다. 고통점(Pain Point)은 사용자가 불편이나 좌절을 경험하는 지점으로, 감성 곡선이 급격히 하강하는 곳이자 디자인 개입이 가장 시급한 곳입니다.&lt;/p&gt;
&lt;p&gt;‘지도(Map)‘라는 단어에 주목할 필요가 있습니다. 앞서 KJ Mapping을 다룬 글에서 지도라는 단어가 2차원 좌표와 거리, 상대적 위치의 의미를 갖는다고 말씀드렸는데, 여정 지도도 마찬가지입니다. 시간이라는 가로축과 감성이라는 세로축 위에서 각 지점의 좌표, 지점 간의 거리와 기울기가 모두 의미를 갖습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 아름답게 그려진 여정 지도가 사용자의 실제 경험을 반영하지 못한다면 그것은 장식에 불과합니다. 지도의 가치는 시각적 완성도가 아니라, 관찰에 기반한 정확성에 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;스토리보드-storyboard&quot;&gt;스토리보드 (Storyboard)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 경험의 흐름을 팀 전체가 직관적으로 이해할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스토리보드는 시나리오를 만화의 컷처럼 시각적 장면의 연속으로 표현하는 도구입니다. 각 컷에는 사용자의 행동, 환경, 감정이 간단한 그림과 짧은 설명으로 담깁니다.&lt;/p&gt;
&lt;p&gt;시나리오가 글로 된 이야기라면, 스토리보드는 그림으로 된 이야기입니다. 글만으로는 전달하기 어려운 것들—공간적 배치, 신체적 동작, 시간의 경과, 환경과 사용자의 관계—이 시각적 장면에서는 직관적으로 드러납니다. 예를 들어 ‘한 손으로 스마트폰을 잡고 흔들리는 지하철에서 검색하는 장면’을 글로 읽는 것과 그림으로 보는 것은 전달력이 다릅니다.&lt;/p&gt;
&lt;p&gt;스토리보드는 또한 팀 내 커뮤니케이션에서 해석의 차이를 줄여줍니다. 같은 시나리오를 읽고도 각자 다른 장면을 상상할 수 있지만, 스토리보드는 모두가 같은 장면을 보게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 스토리보드는 그림의 완성도가 아니라 장면 선택의 정확성이 관건입니다. 경험에서 핵심적인 순간—기대가 형성되는 순간, 문제가 발생하는 순간, 감정이 전환되는 순간—을 정확히 포착하여 컷으로 구성해야 합니다. 모든 단계를 빠짐없이 그리려는 것은 오히려 초점을 흐립니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이 글에서 다룬 도구들—페르소나, 공감 지도, 시나리오, 여정 지도, 스토리보드—은 모두 같은 일을 합니다. 사용자의 인지와 감정이라는, 본질적으로 보이지 않는 것에 형태를 부여하는 일입니다. 형태가 부여되면 공유가 가능해지고, 공유가 가능해지면 팀이 정렬됩니다. 팀이 정렬되면 디자인은 개인의 감에 의존하는 대신 공유된 이해 위에서 움직이게 됩니다.&lt;/p&gt;
&lt;p&gt;결국 이 도구들의 존재 이유는 하나입니다. 사용자 경험이라는 보이지 않는 대상을 다루는 이 분야에서, 보이지 않는 것을 보이게 만들어 함께 논의할 수 있는 테이블 위에 올려놓는 것입니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 ‘구현의 도구들’로 넘어갑니다. 머릿속에 그려진 아이디어를 손에 잡히는 형태로 만드는 도구들—종이 프로토타입, 와이어프레임 등—을 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>페르소나</category><category>사용자 여정지도</category><category>디자인 도구</category></item><item><title>구현의 도구들 — 아이디어를 손에 잡히게 만들기</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/13/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/13/</guid><description>아이디어를 사용자가 경험할 수 있는 형태로 만드는 네 가지 도구, 종이 프로토타입부터 오즈의 마법사 기법까지를 살펴봅니다.</description><pubDate>Tue, 14 Jul 2026 11:47:50 GMT</pubDate><content:encoded>&lt;p&gt;아이디어를 손에 잡히는 것으로 만들어야 할 때 꺼내는 도구들입니다.&lt;/p&gt;
&lt;p&gt;표현의 도구들이 사용자를 팀이 볼 수 있는 형태로 만들었다면, 구현의 도구들은 디자인 아이디어를 사용자가 경험할 수 있는 형태로 만듭니다. 표현은 “우리가 누구를 위해 설계하는가”에 답하고, 구현은 “우리가 무엇을 만들려 하는가”를 시험합니다.&lt;/p&gt;
&lt;p&gt;이 도구들에 대한 가장 흔한 오해가 있습니다. ‘구현’이라는 단어 때문에, 이 도구들이 완성품을 향해 나아가는 최종 단계라고 생각하는 것입니다. 그러나 여기서 말하는 구현의 목적은 완성이 아니라 검증입니다. 시나리오를 통해 세운 가설—이러한 디자인이 사용자의 경험을 이렇게 개선할 것이라는 예측—을 사용자 앞에 내놓기 위한 도구들입니다. 빠르게 만들고, 빠르게 시험하고, 필요하다면 빠르게 버릴 수 있어야 합니다.&lt;/p&gt;
&lt;p&gt;이 도구들도 특정 단계에 귀속되지 않습니다. 아이디어를 처음 떠올리는 순간에도, 이미 어느 정도 구체화된 설계를 다시 점검하는 순간에도, 질문의 성격에 따라 적합한 도구가 달라집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;종이-프로토타입-paper-prototype&quot;&gt;종이 프로토타입 (Paper Prototype)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 아이디어가 작동하는지, 최소한의 비용으로 확인할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;종이 프로토타입은 말 그대로 종이 위에 그린 시제품입니다. 화면의 레이아웃, 버튼의 위치, 페이지 간의 흐름을 손으로 스케치하거나 인쇄하여 구성하고, 진행자가 직접 ‘시스템’ 역할을 맡아 사용자의 행동에 따라 화면을 바꾸어 보여주는 방식으로 운용합니다.&lt;/p&gt;
&lt;p&gt;이 도구의 핵심 가치는 극단적인 저비용입니다. 만드는 데 몇 분밖에 걸리지 않으며, 수정은 연필과 지우개로 즉시 할 수 있습니다. 덜 완성된 형태가 오히려 평가자로 하여금 외형이 아닌 구조와 흐름에 집중하게 만드는 효과도 있습니다. 완성도가 높은 프로토타입은 사용자가 시각적 완성도에 반응하게 만들지만, 종이 위의 스케치는 “이 흐름이 맞는가”라는 핵심 질문으로 집중하게 합니다.&lt;/p&gt;
&lt;p&gt;앞서 인지를 다룬 글에서 멘탈 모델을 이야기했습니다. 사용자가 시스템에 대해 가지고 있는 내적인 개념도입니다. 종이 프로토타입은 이 멘탈 모델과의 불일치를 가장 빠르게 발견하는 도구이기도 합니다. 디지털로 구현하기 전에, 사용자가 “여기서 이 버튼을 누르면 어디로 가야 한다고 생각했는데”라고 말하는 순간을 포착하는 것—그것이 종이 프로토타입이 하는 일입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 완성하려 하지 않는 것이 이 도구의 핵심입니다. 깔끔하게 그리려는 욕심, 빠진 화면을 모두 채우려는 강박은 종이 프로토타입의 장점을 죽입니다. 빠른 스케치 한 장이 정교하게 그린 다이어그램보다 훨씬 나은 경우가 많습니다. 진행자가 시스템 역할을 맡을 때는 사용자를 유도하지 않도록 주의해야 합니다—특정 버튼을 먼저 집어 드는 행위 하나가 테스트를 오염시킵니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;와이어프레임-wireframe&quot;&gt;와이어프레임 (Wireframe)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“화면의 구조와 요소 간 관계를 정의해야 할 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;와이어프레임은 화면의 골격입니다. 색상도, 이미지도, 실제 텍스트도 없이—오직 레이아웃과 요소의 위치, 그리고 흐름만 존재합니다. 그 이름 그대로, 철사(wire)로 틀(frame)만 잡아놓은 것입니다.&lt;/p&gt;
&lt;p&gt;와이어프레임이 답하려는 질문은 외형이 아니라 구조입니다. 이 페이지에는 어떤 요소가 있어야 하는가. 그 요소들의 우선순위는 어떻게 배치로 드러나는가. 사용자가 이 화면에서 가장 먼저 무엇을 보게 되는가. 어떤 행동이 어느 화면으로 연결되는가. 이 질문들에 집중하기 위해, 와이어프레임은 의도적으로 시각적 요소를 제거합니다.&lt;/p&gt;
&lt;p&gt;와이어프레임은 또한 개발자, 기획자, 디자이너가 같은 구조를 이해하고 논의하기 위한 공통 언어입니다. 종이 프로토타입이 생각을 탐색하는 도구라면, 와이어프레임은 그 탐색 결과를 팀과 공유하고 구체화하는 도구에 가깝습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 와이어프레임 단계에서 색상, 폰트, 아이콘 선택 같은 시각 디자인에 대한 논의가 시작되면 구조에 대한 집중이 흐트러집니다. 이 도구가 던지는 질문은 “여기에 무엇이 있어야 하는가”이지 “그것이 어떻게 보여야 하는가”가 아닙니다. 와이어프레임 리뷰에서 “색이 마음에 안 든다”는 피드백이 나온다면, 도구가 잘못 쓰이고 있다는 신호입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;인터랙티브-프로토타입-interactive-prototype&quot;&gt;인터랙티브 프로토타입 (Interactive Prototype)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“실제 사용감에 가까운 반응을 사용자에게서 끌어내야 할 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;인터랙티브 프로토타입은 실제로 클릭하거나 탭할 수 있는 시제품입니다. 종이 프로토타입이나 와이어프레임이 정적인 화면의 연속이라면, 인터랙티브 프로토타입은 버튼을 누르면 다음 화면이 나타나고, 스크롤을 내리면 콘텐츠가 펼쳐지며, 사용자의 행동에 디지털 시스템처럼 반응합니다.&lt;/p&gt;
&lt;p&gt;이 도구가 포착하는 것은 ‘사용감(Feel)‘입니다. 페이지 간 전환의 속도, 화면이 전환되는 방식, 인터랙션의 리듬—이런 것들은 정적인 화면으로는 확인할 수 없습니다. 인터랙티브 프로토타입은 사용자로 하여금 실제 제품을 사용하는 것에 가까운 경험을 하게 만들고, 그 과정에서 정적 도구로는 포착하기 어려운 반응을 불러냅니다. 어포던스(Affordance)가 작동하는지—이 버튼이 눌릴 것 같다는 신호를 제대로 주고 있는지—를 확인하는 데 특히 유용합니다.&lt;/p&gt;
&lt;p&gt;충실도(Fidelity)의 관점에서 보면, 인터랙티브 프로토타입은 고충실도(High-Fidelity)에 가까울수록 실제 사용감에 근접하지만, 제작 비용도 높아집니다. 검증하려는 질문의 성격에 맞게 충실도를 조절하는 것이 중요합니다. 전체 흐름이 맞는지 확인하는 것이라면 낮은 충실도로 충분하고, 세부 인터랙션의 질을 확인하는 것이라면 높은 충실도가 필요합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 고충실도 프로토타입은 만든 사람에게 애착을 유발합니다. “이 정도나 만들었는데 수정하기 싫다”는 감정은 객관적인 판단을 방해합니다. 또한 사용자도 정교한 시제품 앞에서는 디자인에 대한 비판을 주저하는 경향이 있습니다. 프로토타입은 완성품의 예행연습이 아니라 가설의 시험지이며, 부서지기 위해 존재한다는 것을 잊지 않아야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;오즈의-마법사-기법-wizard-of-oz&quot;&gt;오즈의 마법사 기법 (Wizard of Oz)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“아직 기술적으로 구현되지 않은 시스템을 사용자에게 경험시켜야 할 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;오즈의 마법사 기법은, 사용자는 실제 시스템과 상호작용하고 있다고 믿지만 실제로는 사람이 보이지 않는 곳에서 시스템처럼 행동하며 반응을 만들어내는 방법입니다. 커튼 뒤의 마법사가 모든 것을 조종하는 동화 속 장치처럼, 진행자가 시스템의 역할을 수행합니다.&lt;/p&gt;
&lt;p&gt;이 기법이 특히 가치를 발휘하는 상황은 기술적으로 구현하기 어렵거나 비용이 큰 시스템을 테스트해야 할 때입니다. 예를 들어 음성 인식 인터페이스를 개발하기 전에, 사용자가 목소리로 명령을 내리면 진행자가 그 명령을 직접 처리하여 화면을 바꾸어 보여줄 수 있습니다. AI 추천 시스템이 아직 학습되지 않은 상태에서도, 사람이 수동으로 추천 결과를 제공하며 사용자의 반응을 관찰할 수 있습니다. 기술 구현 전에 개념의 유효성을 검증함으로써, 잘못된 방향에 거대한 개발 비용을 쏟아붓는 위험을 줄입니다.&lt;/p&gt;
&lt;p&gt;종이 프로토타입도 넓은 의미에서 오즈의 마법사 기법의 일종입니다. 진행자가 시스템 역할을 맡아 화면을 전환하는 행위 자체가 그 원리입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 마법사의 존재가 드러나는 순간 테스트는 무너집니다. 진행자가 반응을 만들어내는 속도, 일관성, 예측 가능성이 실제 시스템처럼 자연스러워야 하며, 사전에 충분한 준비와 시나리오 숙지가 필요합니다. 또한 사용자가 다음에 무엇을 할지 예측하기 어려운 경우 진행자가 즉흥적으로 반응해야 하는 상황이 생기는데, 이때 불일관성이 테스트를 오염시킬 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이 글에서 다룬 도구들은 하나의 스펙트럼 위에 놓입니다. 종이 프로토타입은 아이디어를 거칠게 만지고, 와이어프레임은 구조를 정의하며, 인터랙티브 프로토타입은 실제 사용감을 시험하고, 오즈의 마법사는 아직 존재하지 않는 것을 경험하게 만듭니다. 이 스펙트럼을 이해하면, 지금 내가 던지는 질문에 어느 도구가 가장 적합한지 판단할 수 있습니다.&lt;/p&gt;
&lt;p&gt;공통적으로 중요한 것이 있습니다. 이 도구들의 목적은 모두 ‘실패를 일찍 만나는 것’입니다. 종이 위에서 틀렸음을 발견하는 비용과 개발이 끝난 후 틀렸음을 발견하는 비용은 비교할 수 없이 다릅니다. 구현의 도구들은 그 비용의 차이를 만드는 장치입니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 ‘검증의 도구들’—만든 것이 실제로 작동하는지 확인하는 도구들, 이를테면 사용성 테스트와 A/B 테스트 등을 다룹니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>프로토타이핑</category><category>디자인 도구</category><category>사용자 테스트</category></item><item><title>검증의 도구들 — 디자인이 실제로 작동하는지 확인하기</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/14/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/14/</guid><description>사용성 테스트부터 A/B 테스트, 정량 척도까지 — 디자인이 실제로 작동하는지 사용자 앞에서 확인하는 다섯 가지 검증 도구를 살펴봅니다.</description><pubDate>Tue, 14 Jul 2026 11:47:50 GMT</pubDate><content:encoded>&lt;p&gt;디자인이 실제로 작동하는지 확인해야 할 때 꺼내는 도구들입니다.&lt;/p&gt;
&lt;p&gt;구현의 도구들이 가설을 형태로 만들었다면, 검증의 도구들은 그 형태를 사용자 앞에 내놓고 가설이 맞는지를 묻습니다. 이 순간은 이 시리즈가 처음부터 강조한 것—사용자는 디자이너의 예측대로 행동하지 않는다—과 마주치는 순간입니다.&lt;/p&gt;
&lt;p&gt;돌아보면, 이 시리즈의 여정은 하나의 순환을 그리고 있습니다. 사용자의 행동을 관찰하여 인지를 추론하는 것으로 시작했고, 검증 역시 사용자의 행동을 관찰하는 것으로 마무리됩니다. 다만 처음의 관찰이 “사용자가 지금 어떤 경험을 하고 있는가”를 향했다면, 검증에서의 관찰은 “우리가 제시한 디자인 앞에서 사용자가 어떤 경험을 하는가”를 향합니다. 출발점과 도착점이 모두 사용자의 행동이라는 사실은, 이 일의 본질이 무엇인지를 다시 한번 일깨워줍니다.&lt;/p&gt;
&lt;p&gt;검증의 도구들도 특정 단계에 귀속되지 않습니다. 완성된 제품을 평가할 때만이 아니라, 종이 프로토타입 한 장을 들고 앉아서도 검증은 시작됩니다. 중요한 것은 단계가 아니라, “이 가설은 아직 검증되지 않았다”는 사실을 인식하고 그것을 확인하려는 태도입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;사용성-테스트-usability-testing&quot;&gt;사용성 테스트 (Usability Testing)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자가 이 디자인으로 목표를 달성할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용성 테스트는 사용자가 실제로 디자인을 사용하는 장면을 직접 관찰하는 방법입니다. 대표적인 진행 방식은 사용자에게 특정 과업(Task)을 제시하고, 그 과업을 수행하는 과정을 옆에서 지켜보는 것입니다. 사용자가 어디서 멈추고, 어디서 헤매고, 어디서 성공하는지를 관찰합니다.&lt;/p&gt;
&lt;p&gt;사용성 테스트에서 가장 먼저 확립해야 할 원칙이 있습니다. 테스트하는 것은 사용자가 아니라 디자인이라는 것입니다. 사용자가 과업을 완수하지 못했을 때, 그것은 사용자의 실패가 아니라 디자인의 실패입니다. 이 관점이 뒤집히는 순간, 진행자는 사용자를 ‘올바른 답’으로 유도하게 되고 테스트는 의미를 잃습니다.&lt;/p&gt;
&lt;p&gt;따라서 진행자는 사용자가 어려움을 겪는 순간에 도움을 주어선 안 됩니다. 그 어려움 자체가 디자인이 개선되어야 할 지점을 가리키는 가장 정직한 신호이기 때문입니다. “어떤 걸 하려고 하셨나요?”처럼 행동의 의도를 묻는 질문은 허용되지만, “이 버튼을 눌러보세요”처럼 행동을 유도하는 발화는 테스트를 오염시킵니다.&lt;/p&gt;
&lt;p&gt;사용자의 수는 많을 필요가 없습니다. 제이콥 닐슨(Jakob Nielsen)의 연구에 따르면, 5명 내외의 사용자만으로도 주요 사용성 문제의 대부분을 발견할 수 있습니다. 대규모 패널보다 소규모의 반복적인 테스트가 더 효율적입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 테스트 환경이 인위적으로 통제될수록 실제 사용 상황과의 괴리가 커집니다. 실험실처럼 조용하고 집중된 환경에서의 수행과, 시끄러운 카페에서 한 손으로 스마트폰을 잡고 사용하는 것은 완전히 다른 경험입니다. 가능하다면 실제 사용 맥락과 유사한 환경에서 테스트하거나, 환경의 한계를 인식한 채 결과를 해석해야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;사고구술법-think-aloud-protocol&quot;&gt;사고구술법 (Think-aloud Protocol)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자의 머릿속에서 무슨 일이 벌어지고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사고구술법은 사용자에게 디자인을 사용하는 동안 머릿속에 떠오르는 생각을 그대로 말해달라고 요청하는 방법입니다. “지금 뭘 보고 계신가요?”, “왜 그렇게 생각하셨나요?”를 사용자 스스로가 진행하는 것입니다.&lt;/p&gt;
&lt;p&gt;행동 관찰이 “무엇을 하는가”를 보여준다면, 사고구술은 “왜 그렇게 하는가”를 들려줍니다. 사용자가 어떤 버튼을 오래 바라본다는 사실은 행동 관찰로 포착되지만, 그것이 기능을 예측하고 있기 때문인지, 아니면 레이블의 의미를 이해하지 못해 망설이고 있는 것인지는 사고구술이 드러냅니다. 멘탈 모델과 디자인 사이의 간극이 어디에 있는지를 가장 직접적으로 들을 수 있는 방법입니다.&lt;/p&gt;
&lt;p&gt;사고구술법에는 두 가지 방식이 있습니다. 동시 사고구술(Concurrent Think-aloud)은 과업을 수행하면서 동시에 말하는 방식이고, 회고적 사고구술(Retrospective Think-aloud)은 과업을 마친 후에 행동을 돌아보며 말하는 방식입니다. 전자는 실시간 생각을 포착하지만 인지 부하를 높이고, 후자는 수행에 방해가 없지만 기억이 재구성될 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 사람은 자신이 생각하는 것을 그대로 말하지 않습니다. 연구자가 가까이 있을 때 사용자는 무의식적으로 더 합리적이고 일관성 있는 설명을 구성하려 합니다. 사고구술의 내용을 액면 그대로 믿기보다, 행동과 발화 사이의 간극에 주목해야 합니다. “이 버튼을 눌렀어요. 당연히 이렇게 되는 거잖아요”라는 말과 세 번 눌렀던 행동이 다를 때—그 간극이 인사이트입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;휴리스틱-평가-heuristic-evaluation&quot;&gt;휴리스틱 평가 (Heuristic Evaluation)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자 없이도 디자인의 잠재적 문제를 빠르게 파악해야 할 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;휴리스틱 평가는 UX 전문가가 사전에 정의된 원칙(Heuristics)을 기준으로 디자인을 점검하는 방법입니다. 사용자가 참여하지 않는다는 점에서 다른 검증 도구들과 다릅니다. 전문가의 지식을 기준으로 삼는 전문가 검토(Expert Review)의 일종입니다.&lt;/p&gt;
&lt;p&gt;이 방법의 기반이 된 것은 제이콥 닐슨(Jakob Nielsen)의 10가지 사용성 원칙입니다. 시스템 상태의 가시성, 오류 예방과 복구의 용이성, 일관성과 표준, 인식의 부담 최소화 등이 이 원칙에 포함됩니다. 전문가는 이 원칙들을 기준으로 디자인의 각 요소가 어떤 원칙을 위반하는지를 체계적으로 기록합니다.&lt;/p&gt;
&lt;p&gt;실제 사용자를 모집하고 세션을 준비하는 데는 시간이 필요합니다. 반면 휴리스틱 평가는 소수의 전문가로 빠르게 수행할 수 있습니다. 프로젝트 초기에, 또는 예산과 시간이 제한된 상황에서 명백한 문제를 신속하게 걸러내는 데 유용합니다. 이후의 사용성 테스트를 더 효율적으로 만들어주는 사전 정제 작업으로 활용할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 전문가의 예측이 사용자의 실제 행동을 대신할 수는 없습니다. 휴리스틱 평가로 발견된 문제가 실제 사용자에게는 문제가 아닐 수 있고, 반대로 전문가가 놓친 문제를 사용자는 즉각 발견하는 경우도 있습니다. 이 도구는 사용성 테스트를 대체하는 것이 아니라 보완하는 것으로 써야 합니다. 또한 평가자가 한 명이면 편향이 개입될 수 있으므로, 가능하다면 3~5명의 전문가가 독립적으로 평가한 뒤 결과를 취합하는 것이 권장됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ab-테스트-ab-testing&quot;&gt;A/B 테스트 (A/B Testing)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“두 가지 디자인 중 어느 것이 더 나은 결과를 만드는지 데이터로 확인해야 할 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A/B 테스트는 두 가지 버전의 디자인을 실제 사용자들에게 동시에 노출하여, 어느 쪽이 더 나은 성과를 보이는지를 측정하는 방법입니다. 사용자 그룹을 무작위로 나누어 A 버전과 B 버전을 각각 경험하게 하고, 클릭률, 전환율, 이탈률 같은 정량적 지표를 비교합니다.&lt;/p&gt;
&lt;p&gt;이 도구의 강점은 ‘다른 모든 조건이 동일한 상태에서’ 한 가지 변수의 효과를 측정한다는 점입니다. “파란 버튼이 초록 버튼보다 클릭을 더 많이 받는가?”, “이미지가 없는 버전이 있는 버전보다 구매 전환율이 높은가?”—이런 질문에 A/B 테스트는 인상이나 직관이 아닌 데이터로 답합니다.&lt;/p&gt;
&lt;p&gt;A/B 테스트는 운영 중인 서비스에서 가장 유용하게 활용됩니다. 충분한 트래픽이 있어야 통계적으로 유의미한 결과를 얻을 수 있기 때문에, 초기 단계보다는 이미 사용자가 있는 제품의 점진적 개선에 적합합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; A/B 테스트는 “무엇이 더 나은가”는 알려주지만 “왜 더 나은가”는 알려주지 않습니다. 파란 버튼이 더 많이 클릭되는 이유가 색상 때문인지, 위치 때문인지, 아니면 다른 요소 때문인지는 이 방법만으로는 알 수 없습니다. 또한 단기적인 지표(클릭률)가 장기적인 사용자 경험의 질(만족도, 신뢰)과 반드시 일치하지 않는다는 점도 유의해야 합니다. 지표를 최적화하는 것과 경험을 개선하는 것은 같은 일이 아닐 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정량-척도-sus-csuq-등&quot;&gt;정량 척도 (SUS, CSUQ 등)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용성을 수치로 측정하고, 다른 버전이나 다른 제품과 비교하고 싶을 때”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;정량 척도는 사용자가 응답하는 설문 형태의 도구로, 사용성 경험을 수치로 표현하게 만듭니다. 가장 널리 쓰이는 것이 SUS(System Usability Scale)와 CSUQ(Computer System Usability Questionnaire)입니다.&lt;/p&gt;
&lt;p&gt;SUS는 10개의 문항으로 구성되며, 각 문항에 1&lt;del&gt;5점으로 응답한 결과를 계산식을 통해 0&lt;/del&gt;100점 척도로 환산합니다. 70점 이상이면 수용 가능한 수준, 85점 이상이면 우수한 수준으로 해석하는 것이 일반적입니다. 사용 방법이 단순하고 표준화되어 있어, 시간에 따른 변화를 추적하거나 서로 다른 제품을 비교하는 데 유용합니다.&lt;/p&gt;
&lt;p&gt;정량 척도가 가져다주는 것은 객관적 기준점입니다. “사용자들이 어려워했다”는 인상보다 “SUS 점수 62점”이라는 수치가 문제의 심각성을 설득력 있게 전달하고, 개선 후 “SUS 점수 78점”으로의 변화가 개선의 성과를 명확하게 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;주의할 점.&lt;/strong&gt; 점수가 의미하는 맥락을 잃지 않아야 합니다. 동일한 SUS 점수 72점이라도, 의료 기기의 72점과 소셜 미디어 앱의 72점은 다른 무게를 갖습니다. 또한 정량 척도는 사용자가 경험을 어떻게 평가하는지를 측정하지, 실제로 무엇을 겪었는지를 설명하지 않습니다. 점수 이면에 있는 이유를 이해하려면 사용성 테스트나 인터뷰 같은 정성적 방법과 함께 써야 합니다. 숫자는 질문의 끝이 아니라 시작입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이 도구들은 서로 다른 각도에서 같은 질문을 던집니다. 우리의 디자인이 사용자의 경험을 실제로 개선하고 있는가. 사용성 테스트와 사고구술법은 행동과 생각을 직접 관찰하고, 휴리스틱 평가는 전문가의 눈으로 사전에 걸러내며, A/B 테스트는 데이터로 비교하고, 정량 척도는 수치로 표현합니다. 어느 것도 혼자서 완전하지 않으며, 질문의 성격에 따라 조합하여 쓰는 것이 좋습니다.&lt;/p&gt;
&lt;p&gt;그리고 다시 한번. 검증은 시작이 아니라 순환의 연결점입니다. 검증에서 발견된 것은 다시 관찰과 분석으로 이어지고, 새로운 정의와 표현과 구현을 낳습니다. 이 순환이 멈추지 않는 것—그것이 UX디자인이 하나의 프로젝트가 아닌 하나의 태도인 이유입니다.&lt;/p&gt;
&lt;p&gt;이제 이 시리즈의 여정을 마무리할 시간입니다. 다음 글에서는 지금까지 거쳐온 모든 순환을 되짚어보며, 처음에 던졌던 질문—UX디자인은 무엇인가—으로 다시 돌아갑니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용성 테스트</category><category>검증</category><category>리서치 방법론</category></item><item><title>에필로그: 다시 사용자에게</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/15/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/15/</guid><description>UX디자인은 무엇인가라는 질문에서 시작한 이 시리즈를 마무리하며, 그 답이 결국 어디로 향하는지를 되짚어봅니다.</description><pubDate>Tue, 14 Jul 2026 11:47:50 GMT</pubDate><content:encoded>&lt;p&gt;이 시리즈는 하나의 질문에서 시작했습니다. UX디자인은 무엇인가.&lt;/p&gt;
&lt;p&gt;그 답을 찾아가는 과정에서 우리는 디자인의 역사를 거슬러 올라갔고, 경험이라는 강의 원류를 탐색했으며, 인지라는 빙산의 수면 아래를 들여다보았습니다. 행동이라는 소용돌이에서 단서를 읽었고, 프레임워크라는 얼개 위에서 관찰하고, 정의하고, 시각화하고, 시나리오를 쓰고, 프로토타입을 만들고, 테스트하는 여정을 따라왔습니다.&lt;/p&gt;
&lt;p&gt;돌아보면, 이 모든 과정이 향하는 곳은 결국 하나입니다. 사용자입니다.&lt;/p&gt;
&lt;p&gt;관찰의 대상도 사용자이고, 공감의 대상도 사용자이며, 디자인의 수혜자도 사용자입니다. 기법들은 바뀔 수 있고, 프레임워크는 진화할 수 있으며, 도구는 매년 새로운 것이 나옵니다. 그러나 사용자를 이해하고 그들의 경험에 공감하려는 태도만은 바뀌지 않는 UX디자인의 본질입니다.&lt;/p&gt;
&lt;p&gt;그러므로 이제 이 시리즈가 처음에 던진 질문으로 돌아갈 차례입니다. UX디자인은 무엇인가.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UX디자인은 사용자 경험의 속성에 대한 파라미터를 디자인 계획에 반영하여 다루겠다는 자기 선언적인 흐름이며, 직관이나 영감보다 객관과 관찰에 입각하여 디자인하는 자세 그 자체입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이것이 이 시리즈의 핵심 테제입니다. 처음에 이 문장을 읽었을 때와, 지금 같은 문장을 다시 읽는 것은 다르게 느껴지기를 바랍니다. 경험의 파라미터—인지, 행동, 감성—가 어떻게 작동하는지를 살폈고, 그것을 다루기 위한 얼개와 도구들을 갖추었다면, 이 선언의 무게가 달라졌을 것입니다.&lt;/p&gt;
&lt;p&gt;자기 선언이라는 표현에 주목해주시기 바랍니다. UX디자인은 누군가가 부여하는 역할이 아닙니다. 나는 사용자의 경험을 객관적으로 파악하고, 그것을 근거로 디자인하겠다고 스스로 선포하는 것입니다. 그 선언이 있는 곳에 UX디자인이 있고, 그 선언이 없는 곳에서는 아무리 멋진 도구를 써도 UX디자인이라고 하기 어렵습니다.&lt;/p&gt;
&lt;p&gt;이 태도가 중요한 이유는, UX디자인이 근본적으로 겸손의 학문이기 때문입니다.&lt;/p&gt;
&lt;p&gt;디자이너는 자신의 직관과 영감에 의존하지 않고, 사용자의 행동에서 배웁니다. 자신이 옳다고 확신하지 않고, 프로토타입을 통해 시험합니다. 한 번의 시도로 완성하려 하지 않고, 반복을 통해 다듬어갑니다. 이 모든 과정은 ‘내가 사용자를 완벽하게 이해하고 있지 못할 수 있다’는 전제 위에 서 있습니다.&lt;/p&gt;
&lt;p&gt;그리고 바로 그 전제가, 역설적으로 사용자에게 더 가까이 다가갈 수 있게 해줍니다.&lt;/p&gt;
&lt;p&gt;이 시리즈에서 거듭 강조한 것처럼, 기법에 얽매이지 않기를 바랍니다. 페르소나를 만들지 않아도, 여정 지도를 그리지 않아도, 더블 다이아몬드를 따르지 않아도 좋습니다. 다만, 사용자의 앞에 섰을 때 그들의 눈으로 세상을 보려고 노력하는 것, 그들이 말하지 못하는 것을 행동에서 읽어내려는 것, 그리고 그 이해를 바탕으로 조금이라도 더 나은 경험을 만들어내려는 것. 이것만 잊지 않는다면, 당신은 이미 UX디자인을 하고 있는 것입니다.&lt;/p&gt;
&lt;p&gt;경험의 강은 멈추지 않고 흐릅니다. 그리고 그 강의 흐름을 바꾸려는 우리의 노력도, 한 번의 프로젝트로 끝나는 것이 아니라 계속되어야 합니다. 기술은 변하고, 사용자도 변하고, 사회도 변합니다. 그 변화 속에서 변하지 않는 것은, 결국 사용자의 경험을 더 낫게 만들고 싶다는 의지뿐입니다.&lt;/p&gt;
&lt;p&gt;다시, 사용자에게.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용자 경험</category><category>디자인 철학</category><category>UX디자인 선언</category></item><item><title>React Native란 무엇인가</title><link>https://blog.bepuljang.co.kr/react-native/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react-native/01/</guid><description>React Native는 웹뷰로 감싼 하이브리드 앱이 아닙니다. React의 사고방식은 그대로 두고 &apos;무엇을 그릴 것인가&apos;만 바꾼다는 관점에서, React Native의 정체와 웹과의 경계를 짚습니다.</description><pubDate>Mon, 13 Jul 2026 15:59:47 GMT</pubDate><content:encoded>&lt;p&gt;React와 React Native. 처음 접했을 때 이 둘의 관계가 혼란스러울 수 있습니다. 이 둘은 어떻게 다른 것일까? 단적으로 쉽게 말하자면 React는 웹을, React Native는 앱을 만든다고 할 수 있습니다. 그런데 이 React Native는 오해를 참 많이 삽니다. “웹을 앱처럼 포장한 것 아니냐”, “결국 웹뷰 아니냐” 같은 이야기가 아직도 돌아다니고, 심지어 오래된 설명글들이 그렇게 적고 있습니다. 그러니 첫 편은 무엇을 만드는 법이 아니라, &lt;strong&gt;React Native가 정확히 무엇인지&lt;/strong&gt;부터 정리하고 시작하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;react는-원래-화면을-그리는-법을-모른다&quot;&gt;React는 원래 ‘화면을 그리는 법’을 모른다&lt;/h2&gt;
&lt;p&gt;이상하게 들리겠지만 사실입니다. React 자체는 DOM을 모릅니다.&lt;/p&gt;
&lt;p&gt;1부에서 컴포넌트가 반환하는 JSX는 실제 화면이 아니라 &lt;strong&gt;“화면이 이렇게 생겨야 한다”는 설계도&lt;/strong&gt;라고 했습니다. 그 설계도를 받아 실제 화면으로 옮기는 일은 React가 아니라 &lt;strong&gt;렌더러(Renderer)&lt;/strong&gt;라는 별도의 담당자가 합니다. 우리가 웹에서 늘 함께 설치하던 &lt;code&gt;react-dom&lt;/code&gt;이 바로 그 담당자였습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 웹: react-dom이 이 설계도를 실제 DOM 노드로 옮긴다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { createRoot } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react-dom/client&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 발상 하나가 나옵니다. &lt;strong&gt;설계도를 만드는 쪽(React)과 그것을 그리는 쪽(렌더러)이 분리되어 있다면, 그리는 쪽만 바꿔 끼우면 되지 않을까?&lt;/strong&gt; DOM 대신 iOS와 Android의 네이티브 UI를 그리는 렌더러를 만들어 붙이면, React로 선언한 화면이 모바일 앱의 화면이 됩니다.&lt;/p&gt;
&lt;p&gt;그게 React Native입니다. React Native는 React를 흉내 낸 다른 무언가가 아니라, &lt;strong&gt;똑같은 React에 렌더러만 갈아 끼운 것&lt;/strong&gt;입니다. 이 문장이 이 시리즈 전체의 전제입니다. 여러분이 이미 아는 컴포넌트·Props·State·useEffect·Context는 전부 그대로 쓰입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;웹뷰가-아닌-진짜-네이티브&quot;&gt;웹뷰가 아닌, 진짜 네이티브&lt;/h2&gt;
&lt;p&gt;가장 흔한 오해를 확실히 끊고 가겠습니다. React Native는 &lt;strong&gt;화면을 웹뷰(WebView)에 띄우지 않습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이름이 비슷한 다른 접근이 실제로 존재하기 때문에 생긴 혼동입니다. Cordova나 Ionic 계열은 앱 껍데기 안에 브라우저 화면을 하나 띄우고 그 안에서 HTML을 렌더합니다. 이런 방식을 하이브리드 앱이라 부르고, 그래서 “결국 안은 웹”이라는 지적이 따라붙습니다.&lt;/p&gt;
&lt;p&gt;React Native는 다릅니다. 우리가 &lt;code&gt;&amp;#x3C;View&gt;&lt;/code&gt;라고 적으면 그것은 iOS에서는 &lt;code&gt;UIView&lt;/code&gt;, Android에서는 &lt;code&gt;android.view.ViewGroup&lt;/code&gt;이라는 &lt;strong&gt;진짜 네이티브 뷰 객체&lt;/strong&gt;가 됩니다. &lt;code&gt;&amp;#x3C;Text&gt;&lt;/code&gt;는 각 플랫폼의 실제 텍스트 뷰가 되고, 스크롤은 그 플랫폼이 원래 쓰던 스크롤 뷰가 처리합니다. 화면에 보이는 버튼은 브라우저가 흉내 낸 버튼이 아니라 OS가 그린 버튼입니다.&lt;/p&gt;
&lt;p&gt;그래서 React Native 앱에는 &lt;code&gt;div&lt;/code&gt;도 &lt;code&gt;span&lt;/code&gt;도 없고, HTML도 CSS 파일도 없습니다. 웹 기술을 앱 안에 넣은 것이 아니라, &lt;strong&gt;React라는 사고방식만 가져가고 재료는 전부 네이티브로 바꾼 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;자바스크립트와-네이티브는-어떻게-대화하는가&quot;&gt;자바스크립트와 네이티브는 어떻게 대화하는가&lt;/h2&gt;
&lt;p&gt;우리가 쓰는 컴포넌트 코드는 자바스크립트입니다. 실제 화면을 그리는 것은 네이티브입니다. 이 둘 사이에 통로가 필요합니다.&lt;/p&gt;
&lt;p&gt;예전 React Native는 이 통로를 &lt;strong&gt;Bridge&lt;/strong&gt;라고 불렀습니다. 자바스크립트 쪽과 네이티브 쪽이 서로를 직접 부르지 못하고, 메시지를 JSON 문자열로 만들어 큐에 실어 비동기로 주고받는 구조였습니다. 우체통에 편지를 넣고 답장을 기다리는 셈이라, 메시지가 몰리면 화면이 한 박자 늦게 반응하는 문제가 있었습니다. 오래된 글에서 “React Native는 브릿지로 통신한다”는 설명을 보게 되는 건 이 시절의 유산입니다.&lt;/p&gt;
&lt;p&gt;지금은 다릅니다. &lt;strong&gt;New Architecture&lt;/strong&gt;라 불리는 구조로 바뀌었고, 0.76 버전부터 이것이 기본값입니다. 세 가지 이름만 알아두면 충분합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JSI(JavaScript Interface)&lt;/strong&gt; — 자바스크립트가 네이티브 객체를 &lt;strong&gt;직접 호출&lt;/strong&gt;할 수 있게 하는 층입니다. 편지를 부치는 대신 전화를 거는 쪽에 가까워졌습니다. 우체통(Bridge)이 사라진 자리입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fabric&lt;/strong&gt; — 새 렌더링 시스템입니다. 레이아웃 계산과 화면 반영이 이전보다 긴밀하게 맞물려, 스크롤 중 깜빡임 같은 타이밍 문제가 줄었습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TurboModules&lt;/strong&gt; — 카메라·위치 같은 네이티브 기능 모듈을 앱 시작 때 전부 올리지 않고 &lt;strong&gt;필요할 때 불러오는&lt;/strong&gt; 방식입니다. 앱이 뜨는 시간이 짧아집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;지금 이 셋의 내부를 깊이 알 필요는 없습니다. 다만 &lt;strong&gt;“자바스크립트가 네이티브를 느리게 우회해서 부른다”는 낡은 인상만은 버려두시면&lt;/strong&gt; 됩니다. 실무에서 마주치는 성능 문제는 대개 이 통로가 아니라 우리가 리스트를 잘못 그리는 데서 옵니다. 그 이야기는 5편에서 하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;react와-무엇이-다른가&quot;&gt;React와 무엇이 다른가&lt;/h2&gt;
&lt;p&gt;React를 아는 사람에게 가장 유용한 지도는 “어디까지가 이미 아는 땅인가”입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;그대로인 것&lt;/strong&gt; — 컴포넌트로 화면을 조립하는 방식, JSX 문법, Props로 값을 내려보내는 것, useState로 상태를 들고 리렌더가 일어나는 것, useEffect·useRef·Context, 그리고 npm 생태계. 1부에서 배운 것은 버릴 게 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;달라지는 것&lt;/strong&gt;은 정확히 ‘화면의 재료’ 쪽입니다.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Web&lt;/th&gt;&lt;th&gt;React Native&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;div&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;View&lt;/code&gt;, &lt;code&gt;Text&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CSS 파일, 클래스&lt;/td&gt;&lt;td&gt;&lt;code&gt;StyleSheet&lt;/code&gt;(자바스크립트 객체)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;URL과 라우터&lt;/td&gt;&lt;td&gt;네비게이션(화면 스택)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;onClick&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;onPress&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;브라우저 API&lt;/td&gt;&lt;td&gt;네이티브 API + 권한 요청&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;여기서 초심자가 가장 자주 걸려 넘어지는 두 가지만 미리 말해두겠습니다. 첫째, &lt;strong&gt;모든 글자는 &lt;code&gt;&amp;#x3C;Text&gt;&lt;/code&gt; 안에 있어야 합니다.&lt;/strong&gt; 웹에서처럼 &lt;code&gt;&amp;#x3C;View&gt;여기 글씨&amp;#x3C;/View&gt;&lt;/code&gt;라고 쓰면 오류가 납니다. 둘째, &lt;strong&gt;스타일은 상속되지 않고, Flexbox의 기본축이 가로가 아니라 세로입니다.&lt;/strong&gt; 웹의 습관 그대로 쓰면 십중팔구 화면이 예상과 다르게 나옵니다. 3편과 4편에서 각각 자세히 다룹니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;네이티브-플랫폼을-몰라도-될까&quot;&gt;네이티브 플랫폼을 몰라도 될까&lt;/h2&gt;
&lt;p&gt;“하나의 코드로 두 플랫폼”은 사실이지만, &lt;strong&gt;“네이티브를 몰라도 된다”는 뜻은 아닙니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;앱을 만들다 보면 결국 iOS와 Android의 차이를 마주합니다. 권한을 요청하는 흐름이 다르고, 뒤로 가기 버튼의 존재가 다르고, 화면 상단의 노치와 하단의 홈 인디케이터를 피하는 방법도 다릅니다. React Native는 이 차이를 지워주지 않고, &lt;strong&gt;다룰 수 있는 손잡이를 줄 뿐입니다.&lt;/strong&gt; 가끔은 원하는 기능을 지원하는 라이브러리가 없어 네이티브 모듈을 직접 붙여야 하는 순간도 옵니다.&lt;/p&gt;
&lt;p&gt;그럼에도 이 선택이 합리적인 경우가 많습니다. 화면과 비즈니스 로직의 대부분을 한 벌만 쓰고, 팀이 이미 아는 React 지식을 그대로 재사용하며, 코드를 고치자마자 앱에 반영되는 개발 경험을 얻기 때문입니다. 다만 무거운 그래픽 처리나 플랫폼 최신 기능을 가장 먼저 써야 하는 앱이라면, 여전히 네이티브가 정답일 수 있습니다. 도구는 만능이 아니라 적합한 자리가 있을 뿐입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;앞으로-다룰-것&quot;&gt;앞으로 다룰 것&lt;/h2&gt;
&lt;p&gt;정리하면 React Native는 세 문장입니다. &lt;strong&gt;React의 사고방식은 그대로 쓴다. 화면은 웹뷰가 아니라 진짜 네이티브 뷰로 그려진다. 대신 DOM과 CSS라는 재료는 버리고 새 재료를 배운다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음 편에서는 Expo로 개발 환경을 만들고 실제 기기에 첫 화면을 띄워보겠습니다. 이후로는 네이티브 컴포넌트, StyleSheet와 Flexbox, 리스트와 터치, 네비게이션, 플랫폼 API, 그리고 스토어 배포까지 차례로 이어집니다. 웹에서 React를 익힌 손으로, 이번에는 주머니 속에서 돌아가는 화면을 그려볼 차례입니다.&lt;/p&gt;</content:encoded><category>모바일 앱을 위한 React Native</category><category>React Native</category><category>모바일 앱</category><category>크로스 플랫폼</category><category>네이티브</category></item><item><title>관찰의 도구들 — 사용자가 무엇을 하는지 모를 때</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/10/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/10/</guid><description>사용자가 무엇을 하는지, 왜 그렇게 하는지 알 수 없을 때 꺼내는 관찰 도구 11가지를 소개합니다. 미행관찰부터 은유 추출(ZMET)까지, 각 도구의 쓰임과 한계를 짚습니다.</description><pubDate>Mon, 13 Jul 2026 15:59:47 GMT</pubDate><content:encoded>&lt;p&gt;사용자가 무엇을 하는지 모르겠을 때 꺼내는 도구들입니다.&lt;/p&gt;
&lt;p&gt;앞서 인지의 빙산을 이야기했고, 행동의 소용돌이를 이야기했습니다. 수면 위로 드러나는 의식은 전체의 일부에 불과하며, 사용자가 정말로 겪고 있는 경험의 실체는 무의식적인 행동 속에 묻혀있다고 말씀드렸습니다. 그렇다면 그 행동을 어떻게 포착할 것인가? 여기에 소개하는 도구들은 모두 같은 질문에서 출발합니다. “사용자는 지금 무엇을 하고 있는가, 그리고 왜 그렇게 하고 있는가?”&lt;/p&gt;
&lt;p&gt;이 도구들은 특정 프로젝트 단계에 귀속되지 않습니다. 초기에 문제를 발견하기 위해 쓸 수도 있고, 설계 중에 가설을 확인하기 위해 다시 꺼낼 수도 있으며, 출시 후에 예상치 못한 사용 패턴을 추적하기 위해 동원할 수도 있습니다. 질문이 떠오르는 순간이 도구를 쓸 때입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;미행관찰-shadowing&quot;&gt;미행관찰 (Shadowing)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 사용자는 실제로 어떤 순서로, 어떤 맥락에서 행동하는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;특정 사용자를 선정하여 목표 작업 수행 과정의 일거수일투족을 따라가며 관찰하는 방법입니다. 관찰자는 사용자의 그림자가 되어 그들의 환경 속에서 행동의 흐름을 있는 그대로 기록합니다.&lt;/p&gt;
&lt;p&gt;핵심은 이름 그대로 ‘그림자’가 되는 것입니다. 관찰이라는 행위 자체가 사용자에게 영향을 끼치는 관찰자 효과(Observer Effect)가 이 도구의 가장 큰 적입니다. 사용자가 관찰자를 의식하는 순간, 행동은 자연스러움을 잃고 ‘보여주기 위한 행동’으로 변질됩니다. 존재감을 죽이는 것이 기술입니다. 관찰자가 편안한 환경을 만드는 것이 아니라, 관찰자 자신이 환경의 일부가 되어야 합니다.&lt;/p&gt;
&lt;p&gt;미행관찰은 사용자의 무의식적 행동—앞서 행동을 다룬 글에서 살펴본 행위(Activity)가 아닌 행동(Behavior)—을 포착하는 데 가장 직접적인 도구입니다. 다만 한 번에 한 명의 사용자만 깊이 따라갈 수 있으므로, 넓은 범위의 패턴을 파악하기보다는 개별 경험의 깊이를 확보하는 데 적합합니다.&lt;/p&gt;
&lt;h2 id=&quot;거점관찰-town-watching&quot;&gt;거점관찰 (Town Watching)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“이 장소에서 사람들은 전반적으로 어떤 패턴을 보이는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;특정 장소에 거점을 잡고 불특정 다수의 사용자를 관찰하는 방법입니다. 미행관찰이 한 사용자를 깊이 따라가는 도구라면, 거점관찰은 한 장소에서 다수의 행동 패턴을 넓게 수집하는 도구입니다.&lt;/p&gt;
&lt;p&gt;카페, 매장, 병원 대기실, 지하철역 등 목표 환경에 자리를 잡고 사람들의 흐름을 관찰합니다. 개별 사용자의 맥락을 깊이 이해하기는 어렵지만, 반복적으로 나타나는 행동 패턴—특정 지점에서의 머뭇거림, 예상과 다른 동선, 무의식적인 회피 행동—을 발견하는 데 강점이 있습니다.&lt;/p&gt;
&lt;p&gt;주의할 점은 관찰자의 선입견입니다. “재미있는 행동”에만 눈이 가기 쉬운데, 재미없어 보이는 반복 행동이야말로 사용자의 무의식적 인지를 드러내는 단서인 경우가 많습니다.&lt;/p&gt;
&lt;h2 id=&quot;행동-지도화-behavioral-mapping&quot;&gt;행동 지도화 (Behavioral Mapping)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자들의 행동을 공간 위에 겹쳐보면 어떤 패턴이 드러나는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자의 동선이나 행동을 2차원 평면 위에 시각화하여 분석하는 방법입니다. 직접 관찰의 결과를 공간적으로 기록함으로써, 개별 행동으로는 보이지 않던 유형적 패턴을 발견할 수 있습니다.&lt;/p&gt;
&lt;p&gt;여러 사용자의 동선을 하나의 지도 위에 겹쳐놓으면, 특정 지점에서의 정체, 우회, 회귀 등이 시각적으로 드러납니다. 앞서 행동을 다룬 글에서 쇼핑몰의 엘리베이터 사례를 다루었는데, 그런 종류의 문제를 발견하는 데 행동 지도화가 유용합니다. 사용자가 어떤 생각을 했는지 직접 물을 수는 없지만, 다수의 동선이 만들어내는 패턴을 통해 그 생각을 유추할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 도구는 단독으로 쓰이기보다는 미행관찰이나 거점관찰의 데이터를 정리하고 해석하는 후속 도구로 자주 활용됩니다.&lt;/p&gt;
&lt;h2 id=&quot;시선추적-eye-tracking&quot;&gt;시선추적 (Eye Tracking)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자의 시선은 실제로 어디를 향하고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자의 눈동자 움직임을 추적하여, 화면이나 공간에서 실제로 어디를 보고 있는지를 기록하는 방법입니다. 사용자가 “이 버튼을 봤다”고 말하는 것과 실제로 시선이 그 버튼에 닿았는지는 별개의 문제입니다. 시선추적은 이 간극을 데이터로 드러냅니다.&lt;/p&gt;
&lt;p&gt;무의식적인 인지를 가장 직접적으로 측정할 수 있는 도구 중 하나이지만, 장비 비용이 높고 실험 환경의 제약이 따릅니다. 또한 “어디를 보았는가”는 알려주지만 “왜 보았는가”는 알려주지 않습니다. 시선 데이터는 그 자체로 답이 아니라, 다른 관찰 도구와 함께 해석해야 의미가 생기는 단서입니다.&lt;/p&gt;
&lt;h2 id=&quot;일기-연구-diary-study&quot;&gt;일기 연구 (Diary Study)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“시간이 지나면서 사용자의 경험은 어떻게 변화하는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자에게 일정 기간 동안 자신의 경험을 기록하도록 요청하는 방법입니다. 관찰자가 현장에 항상 함께할 수 없는 상황—일상적 맥락, 장기적 사용 패턴, 감정의 변화—을 포착하는 데 유용합니다.&lt;/p&gt;
&lt;p&gt;간접 관찰의 대표적인 도구입니다. 관찰자가 직접 보지 않아도 사용자의 자연스러운 환경에서의 경험을 수집할 수 있다는 강점이 있습니다. 그러나 기록하는 행위 자체가 경험을 왜곡할 수 있고, 기록자의 주관에 따라 편향된 결과를 얻을 수 있다는 점을 항상 염두에 두어야 합니다. 사용자는 자신이 의식하는 것만 기록하기 때문에, 무의식적 행동은 이 도구의 사각지대입니다.&lt;/p&gt;
&lt;h2 id=&quot;면접-interview&quot;&gt;면접 (Interview)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자 자신은 자기 경험을 어떻게 인식하고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자와 대면하여 경험에 대해 직접 묻고 답을 듣는 방법입니다. 가장 익숙하고 접근성이 높은 도구이지만, 가장 주의가 필요한 도구이기도 합니다.&lt;/p&gt;
&lt;p&gt;사용자가 의식적으로 느끼는 문제들—“이 버튼이 너무 작다”, “로딩이 느리다”—은 면접을 통해 비교적 쉽게 보고됩니다. 그러나 앞서 인지를 다룬 글에서 살펴보았듯이 인지의 대부분은 무의식에 잠겨있기 때문에, 사용자 자신도 자기 경험의 실체를 정확히 설명하지 못하는 경우가 많습니다. “왜 불편한지 모르겠는데 뭔가 불편하다”는 답변이 나올 때, 그것은 면접의 한계가 아니라 인지 구조의 특성입니다. 질문자의 유도에 따라 편향된 답이 나오기도 쉽습니다.&lt;/p&gt;
&lt;p&gt;면접은 사용자의 의식적 인식을 확인하는 데는 효과적이지만, 무의식적 행동의 원인을 파악하는 데는 다른 관찰 도구와 반드시 병행해야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;설문조사-survey&quot;&gt;설문조사 (Survey)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“다수의 사용자가 공통적으로 인식하는 경험은 무엇인가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;구조화된 질문을 통해 다수의 사용자로부터 정량적 데이터를 수집하는 방법입니다. 면접이 깊이를 확보하는 도구라면, 설문은 넓이를 확보하는 도구입니다.&lt;/p&gt;
&lt;p&gt;비용 효율적이고 대규모 데이터를 수집할 수 있다는 분명한 강점이 있으나, 면접의 한계가 그대로 적용되며 여기에 더해 질문 설계의 편향이라는 문제가 추가됩니다. 질문의 순서, 선택지의 구성, 용어의 선택이 모두 응답을 왜곡할 수 있습니다. 설문으로 얻을 수 있는 것은 사용자가 의식적으로 인식하고 언어화할 수 있는 범위의 경험이며, 그 너머의 무의식적 행동은 포착할 수 없습니다.&lt;/p&gt;
&lt;h2 id=&quot;표적-집단-면접-fgi-focus-group-interview&quot;&gt;표적 집단 면접 (FGI; Focus Group Interview)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“집단의 대화 속에서 개인이 미처 의식하지 못한 경험이 드러나는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;목표 사용자의 대표 집단을 모집하여, 중재자(moderator)와 함께 사용 경험에 대해 자유롭게 대화를 나누는 방법입니다. 실무에서 많이 사용되지만, 정확하게 사용되는 경우가 매우 드문 도구이기도 합니다.&lt;/p&gt;
&lt;p&gt;FGI의 본질은 ‘집단 면접’이 아니라 ‘집단 대화’입니다. 많은 경우 단순히 여러 명과 일대다(1:N) 면접을 하는 형태로 진행되는데, 이것은 잘못된 사례입니다. FGI의 핵심은 참여자들 사이의 자유로운 대화가 서로의 기억과 경험을 자극하여, 한 명이 혼자 앉아 떠올리기 어려운 무의식적 경험들이 대화의 흐름 속에서 자연스럽게 떠오르도록 하는 것입니다. 중재자는 이 대화의 흐름을 설계하고 유지하는 역할을 하며, 동시에 제3자의 시선으로 참여자들의 무의식적인 반응과 행동—표정, 몸짓, 말의 속도 변화, 특정 주제에 대한 회피—을 관찰하여 수집하는 것이 중요합니다.&lt;/p&gt;
&lt;p&gt;편안한 분위기가 전제되어야 합니다. 경험이 많은 집단과 경험에 대한 잡담을 나누면서 무의식에 묻혀있던 이야기를 끌어내는 것이 목표이지, 정해진 질문에 답변을 받아적는 것이 목표가 아닙니다.&lt;/p&gt;
&lt;h2 id=&quot;맥락적-질의-contextual-inquiry&quot;&gt;맥락적 질의 (Contextual Inquiry)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자가 실제로 일하는 바로 그 맥락에서, 행동의 이유를 함께 추적할 수 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자의 실제 작업 환경에서, 사용자가 작업을 수행하는 동안 관찰하면서 동시에 질문을 던지는 방법입니다. 미행관찰의 현장성과 면접의 설명력을 결합한 도구라 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;관찰자는 ‘도제(apprentice)‘의 자세를 취합니다. 사용자가 ‘전문가(master)‘이고, 관찰자는 그 작업을 배우러 온 사람처럼 행동하며 “지금 왜 그렇게 하셨어요?”라고 자연스럽게 묻습니다. 이를 통해 행동을 포착하는 동시에, 그 행동의 맥락과 이유를 현장에서 바로 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;주의할 점은 두 가지입니다. 첫째, 질문이 관찰을 방해해서는 안 됩니다. 작업의 흐름을 끊을 정도로 질문이 잦으면 관찰의 자연스러움이 손상됩니다. 둘째, 사용자가 자신의 행동을 설명할 때 실제 이유와 사후 합리화를 구별해야 합니다. 사용자는 “왜?”라는 질문에 대해 실제 이유가 아닌, 그럴듯한 이유를 만들어 답하는 경우가 적지 않습니다. 이 역시 앞서 인지를 다룬 글에서 짚은 인지의 특성입니다.&lt;/p&gt;
&lt;h2 id=&quot;소지품-조사-personal-inventories&quot;&gt;소지품 조사 (Personal Inventories)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자가 지니고 다니는 물건들은 그의 멘탈모델에 대해 무엇을 말해주는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자 집단이 일상적으로 가지고 다니는 소지품을 조사하여, 그들이 대상에 대해 형성하고 있는 멘탈모델(Mental Model)을 추론하는 방법입니다.&lt;/p&gt;
&lt;p&gt;경험은 추상적인 이미지이고, 그 추상성은 언어보다 사물을 통해 더 잘 드러나는 경우가 있습니다. 사용자가 어떤 물건을 가지고 다니는지, 그 물건을 어떻게 정리하고 사용하는지는 그 사용자의 가치관과 우선순위, 그리고 세계를 인식하는 방식을 간접적으로 보여줍니다. 이 도구는 사용자의 언어적 보고에 의존하지 않기 때문에, 면접이나 설문의 사각지대를 보완할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;문화-조사-cultural-probes&quot;&gt;문화 조사 (Cultural Probes)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자의 일상 속 표현물은 어떤 인지적 단서를 담고 있는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자에게 카메라, 일기장, 지도, 엽서 등의 도구를 제공하고, 일정 기간 동안 자신의 경험과 환경을 자유롭게 기록하도록 요청하는 방법입니다. 일기 연구와 유사하나, 기록의 매체가 언어에 한정되지 않고 이미지와 사물로 확장된다는 점이 다릅니다.&lt;/p&gt;
&lt;p&gt;이 도구의 전제는 경험이 언어로만 포착되지 않는다는 것입니다. 사용자가 찍은 사진, 그린 그림, 수집한 물건들은 그 자체로 사용자의 인지 세계를 보여주는 단서가 됩니다. 다만 이 단서들은 해석을 필요로 하며, 해석자의 역량에 따라 결과의 질이 크게 달라질 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;은유-추출-zmet-zaltman-metaphor-elicitation-technique&quot;&gt;은유 추출 (ZMET; Zaltman Metaphor Elicitation Technique)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“사용자의 경험을 이미지와 은유로 표현하면, 언어로는 닿지 못하는 인지가 드러나는가?”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사용자에게 경험과 관련된 이미지(사진, 그림)를 수집하도록 하고, 그 이미지에 대한 나름의 해석을 이야기하게 하여 경험에 대한 추상적인 인지 구조를 추출하는 방법입니다.&lt;/p&gt;
&lt;p&gt;이 접근의 핵심적인 착안점은, 경험이라는 것이 본질적으로 추상적인 이미지이며, 따라서 그 경험을 추론하는 단서 역시 언어적 진술보다는 이미지와 은유를 통해 더 풍부하게 얻을 수 있다는 것입니다. 사용자에게 “당신의 경험을 설명해주세요”라고 물으면 의식의 수면 위에 있는 것만 건져올리지만, “당신의 경험을 표현하는 이미지를 골라주세요”라고 하면 수면 아래의 감각적, 정서적 차원까지 끌어올릴 가능성이 열립니다.&lt;/p&gt;
&lt;p&gt;다만 이 도구는 관찰 도구들 중에서도 가장 추상적인 축에 속하며, 수집된 은유를 해석하는 과정에서 분석자의 주관이 깊이 개입할 수밖에 없습니다. 엄밀한 정량적 결과보다는, 사용자의 인지 세계에 대한 질적 통찰을 얻는 데 적합한 도구입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;이 도구들은 저마다의 강점과 사각지대를 가지고 있으며, 현실의 프로젝트에서는 단독으로 쓰이기보다 서로 얽히며 응용되는 경우가 많습니다. 미행관찰에서 발견한 행동 패턴을 행동 지도화로 시각화하고, FGI에서 드러난 경험의 단서를 맥락적 질의로 현장에서 확인하며, 은유 추출에서 얻은 이미지를 면접에서 더 깊이 탐색하는 식입니다.&lt;/p&gt;
&lt;p&gt;그러나 어떤 도구를 쓰든, 얼마나 정교하게 쓰든, 하나의 원칙은 변하지 않습니다. 이 도구들의 목표는 사용자의 표면적인 행동과 표상을 통해 그 밑에 깔린 인지에 공감(empathize)하는 것입니다. 공감에 실패하면—사용자와 동기화하는 데 실패하면—수많은 관찰이 단지 피상적으로 이뤄질 뿐이고, 그것은 비용만 많이 들 뿐 앉아서 사용자에 대해 명상하는 것보다도 못할 수 있습니다.&lt;/p&gt;
&lt;p&gt;어떤 도구든 사용자와 동기화하는 데 실패하면 의미가 없습니다.&lt;/p&gt;
&lt;p&gt;관찰의 도구들을 살펴보았으니, 다음 글에서는 ‘분석의 도구들’ — 관찰로 쌓인 데이터에서 구조와 의미를 읽어내는 도구들을 다룹니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용자 리서치</category><category>관찰</category><category>UX 방법론</category></item><item><title>시리즈를 마치며 — 바이브코딩 핵심 정리</title><link>https://blog.bepuljang.co.kr/vibecoding/11/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/11/</guid><description>바이브코딩 연재의 마무리. 전체를 관통하는 다섯 가지 원칙과 각 편의 내용을 한눈에 되짚습니다.</description><pubDate>Mon, 13 Jul 2026 15:59:47 GMT</pubDate><content:encoded>&lt;p&gt;11편에 걸친 연재의 마지막입니다. 지금까지 바이브코딩으로 개념을 익히고, 도구를 설치하고, 첫 화면을 만들고, 프롬프트를 다듬고, 배포하고, 리팩터링하고, 버그를 잡는 과정까지 함께 걸어왔습니다.&lt;/p&gt;
&lt;p&gt;이번 편에서는 그 여정을 짧게 되짚고, 오래 기억할 만한 핵심만 추려 정리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;다섯-가지-원칙&quot;&gt;다섯 가지 원칙&lt;/h2&gt;
&lt;p&gt;연재 전체를 관통하는 핵심을 다섯 가지 원칙으로 요약합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 하나씩&lt;/strong&gt;
기능을 추가하거나 버그를 수정할 때 한 번에 하나씩 요청합니다. 작은 단위로 작업하면 문제가 생겼을 때 원인을 빠르게 찾을 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 맥락을 제공한다&lt;/strong&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt;로 프로젝트 구조와 현재 상태를 AI에게 제공합니다. 맥락이 있는 AI는 맥락이 없는 AI보다 더 나은 결과를 냅니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 바로 기록한다&lt;/strong&gt;
나중에 기록하려 하면 결국 안 하게 됩니다. 기능을 추가하는 그 자리에서 한 줄씩 남기면 이력이 자연스럽게 쌓입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 주기적으로 정리한다&lt;/strong&gt;
기능 추가만 하고 정리를 미루면 코드 복잡도가 계속 쌓입니다. 몇 주에 한 번은 리팩터링 시간을 갖습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 작동하는 것을 먼저&lt;/strong&gt;
완벽한 코드보다 작동하는 코드가 먼저입니다. 작동하고 나면 개선할 수 있지만, 작동하지 않으면 개선할 것도 없습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;시리즈-되돌아보기&quot;&gt;시리즈 되돌아보기&lt;/h2&gt;





















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;편&lt;/th&gt;&lt;th&gt;주제&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1편&lt;/td&gt;&lt;td&gt;바이브코딩이란, 도구 비교&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2편&lt;/td&gt;&lt;td&gt;Claude Code 설치와 첫 대화&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3편&lt;/td&gt;&lt;td&gt;CLAUDE.md로 AI에게 프로젝트 설명하기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4편&lt;/td&gt;&lt;td&gt;첫 화면 만들기, 프롬프트 기초&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5편&lt;/td&gt;&lt;td&gt;구조가 무너지는 함정과 기록하는 습관&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6편&lt;/td&gt;&lt;td&gt;MCP로 외부 도구 연결하기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7편&lt;/td&gt;&lt;td&gt;프롬프트 엔지니어링&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8편&lt;/td&gt;&lt;td&gt;배포 첫걸음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;9편&lt;/td&gt;&lt;td&gt;리팩터링, 코드 정리&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10편&lt;/td&gt;&lt;td&gt;버그 디버깅&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;11편&lt;/td&gt;&lt;td&gt;마치며 (이 편)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;바이브코딩은-수단이다&quot;&gt;바이브코딩은 수단이다&lt;/h2&gt;
&lt;p&gt;마지막으로 강조하고 싶은 것은, 바이브코딩 자체가 목적이 아니라는 점입니다.&lt;/p&gt;
&lt;p&gt;바이브코딩은 아이디어를 빠르게 현실로 만들기 위한 수단입니다. 코딩 지식이 없어도 서비스를 만들 수 있다는 것은 분명 큰 변화입니다. 하지만 만든 서비스가 오래 살아남으려면 빠른 속도 이상의 것이 필요합니다 — 구조를 파악하는 습관, 이력을 남기는 루틴, 주기적으로 코드를 정리하는 시간.&lt;/p&gt;
&lt;p&gt;완벽하지 않아도, 처음부터 모든 것을 알지 못해도 괜찮습니다. 만들고, 기록하고, 개선하는 사이클을 반복하다 보면 어느새 서비스가 성장해 있을 것입니다. 이 연재가 그 여정에 하나라도 도움이 됐기를 바랍니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>바이브코딩</category><category>개발루틴</category></item><item><title>이끌지 못하고 지배하는 위험에 대하여 — 복종은 시키는 데까지, 이해는 그 너머까지</title><link>https://blog.bepuljang.co.kr/startup-prince/06/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/06/</guid><description>『스타트업 군주론』 2부의 두 번째 이야기. 자리의 힘으로 복종을 얻어내는 것과 사람을 이끄는 것은 다릅니다. 강제된 복종만으로 굴러가는 조직이 왜 대표가 보는 앞에서만 움직이는지를, 마키아벨리가 나눈 두 종류의 권력을 빌려 살펴봅니다.</description><pubDate>Sun, 12 Jul 2026 12:46:02 GMT</pubDate><content:encoded>&lt;p&gt;앞 편에서는 이길 수 있는 전장을 고르는 일을 이야기했습니다. 전장을 골랐다면, 다음은 그 자리에서 사람을 어떻게 움직이게 할 것인가입니다. 그리고 여기서 리더가 가장 흔히 빠지는 착각이 하나 있습니다. 사람을 움직이게 하는 것과 사람을 이끄는 것을 같은 일로 여기는 것입니다.&lt;/p&gt;
&lt;p&gt;대표라는 자리에는 힘이 따라옵니다. 급여와 평가를 정하고, 채용과 해고를 결정하고, 최종 판단을 내리는 권한입니다. 이 힘을 쓰면 사람을 움직이게 하는 일은 어렵지 않습니다. 시키면 대개 그대로 됩니다. 문제는 그렇게 얻어낸 것이 이끎이 아니라 복종이라는 데 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;대표가-보는-앞에서만-움직이는-조직&quot;&gt;대표가 보는 앞에서만 움직이는 조직&lt;/h2&gt;
&lt;p&gt;지배로 움직이는 조직에는 뚜렷한 증상이 있습니다. 대표가 회의에 없으면 결정이 멈춥니다. 사소한 사안까지 “그건 대표님께 여쭤봐야 한다”는 말로 위로 올라옵니다. 대표가 자리를 비운 며칠 동안 조직은 새로운 일을 벌이기보다 그가 돌아올 때까지 판단을 미뤄둡니다. 겉으로는 대표의 권위가 확고해 보이지만, 실제로는 조직 전체가 대표 한 사람의 처리 용량 안에 갇혀 있는 것입니다.&lt;/p&gt;
&lt;p&gt;이런 조직은 지시받은 일은 잘합니다. 다만 지시받지 않은 일, 예상하지 못한 상황, 대표가 미처 생각하지 못한 문제 앞에서는 멈춰 섭니다. 복종은 시키는 데까지만 작동하기 때문입니다. 그 너머—누가 시키지 않아도 방향에 맞게 스스로 판단하고 움직이는 일—는 복종으로는 결코 만들어지지 않습니다.&lt;/p&gt;
&lt;h2 id=&quot;강제로-세운-권력과-지지로-세운-권력&quot;&gt;강제로 세운 권력과 지지로 세운 권력&lt;/h2&gt;
&lt;p&gt;마키아벨리는 『군주론』에서 군주가 권력에 오르는 두 경로를 구분합니다. 하나는 유력자들의 힘을 빌리거나 무력으로 오르는 길이고, 다른 하나는 인민의 지지를 얻어 오르는 길입니다. 그는 이 둘의 안정성이 크게 다르다고 봤습니다. 소수 유력자의 힘으로 오른 군주는 그들과 대등한 처지라 늘 견제받고, 인민의 호의가 없으면 역경이 닥쳤을 때 무너집니다. 반면 인민의 지지 위에 선 군주는 든든한 기반을 가진다고 보았습니다.&lt;/p&gt;
&lt;p&gt;핵심은 힘의 원천이 어디에 있느냐입니다. 강제로 세운 권력은 그 힘을 계속 행사하고 있는 동안에만 유지됩니다. 강제를 멈추는 순간—군주가 자리를 비우거나 힘이 약해지는 순간—권력도 함께 흔들립니다. 반면 지지로 세운 권력은 사람들이 스스로 원해서 따르는 것이기 때문에, 군주가 일일이 강제하지 않아도 유지됩니다. 앞 편에서 본 시운의 논리와 같습니다. 힘의 원천이 밖에 있으면 그 조건이 사라질 때 무너지고, 안에 있으면 지속됩니다.&lt;/p&gt;
&lt;h2 id=&quot;복종은-시키는-데까지-이해는-그-너머까지&quot;&gt;복종은 시키는 데까지, 이해는 그 너머까지&lt;/h2&gt;
&lt;p&gt;조직으로 옮겨보면 이렇습니다. 자리의 힘으로 얻은 복종은 그 힘이 미치는 범위 안에서만 작동합니다. 대표의 눈이 닿는 곳, 대표가 지시한 항목, 평가에 반영되는 지표까지입니다. 그 경계를 넘어서는 순간—아무도 지켜보지 않는 상황, 규정에 없는 문제, 지시와 현실이 어긋나는 지점—복종은 힘을 잃습니다. 시키지 않은 일은 하지 않고, 판단이 필요한 자리에서는 판단을 미룹니다.&lt;/p&gt;
&lt;p&gt;이해는 다르게 작동합니다. 구성원이 “우리가 무엇을 왜 하는가”를 실제로 이해하고 있다면, 그는 지시가 없는 곳에서도 방향에 맞게 움직입니다. 예상하지 못한 문제를 만나면 대표라면 어떻게 판단했을지를 스스로 추론해 결정합니다. 이것이 복종이 닿지 못하는 그 너머를 채웁니다. 마키아벨리는 두려움으로 다스리는 편이 더 안전할 수 있다고도 말했지만, 두려움은 사람을 특정 행동에서 물러서게 할 뿐 없던 자발성을 만들어내지는 못합니다. 하지 말아야 할 일을 막는 데는 두려움이 쓸모 있어도, 시키지 않은 좋은 일을 하게 만드는 데는 이해가 필요합니다.&lt;/p&gt;
&lt;h2 id=&quot;지배가-더-쉬운-이유&quot;&gt;지배가 더 쉬운 이유&lt;/h2&gt;
&lt;p&gt;그런데도 많은 창업자가 지배 쪽으로 기웁니다. 이유는 단순합니다. 지배가 더 빠르고 편하기 때문입니다. 왜 이 일을 이렇게 해야 하는지 맥락을 설명하고, 판단의 기준을 공유하고, 구성원이 그것을 소화할 때까지 기다리는 일은 느리고 품이 듭니다. 반면 “그냥 이렇게 하세요”라고 지시하는 것은 즉시 결과가 나옵니다. 하루하루가 급한 초기 스타트업에서, 이 속도 차이는 대단히 유혹적입니다.&lt;/p&gt;
&lt;p&gt;문제는 그 편함의 대가가 나중에 청구된다는 것입니다. 지시로만 굴러온 조직은 사람이 늘어나도 판단할 수 있는 사람은 여전히 대표 하나뿐인 상태로 커집니다. 조직은 100명이 되었는데 100명분의 판단이 전부 한 사람을 거쳐야 한다면, 그 병목은 대표 자신입니다. 초기에 이해를 심는 수고를 아낀 대가가, 조직이 커진 시점에 확장의 한계로 돌아오는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;이해를-심는-일&quot;&gt;이해를 심는 일&lt;/h2&gt;
&lt;p&gt;이끄는 것은 지시를 줄이고 방치하는 것이 아닙니다. 지시 대신 맥락을 함께 전달하는 것입니다. 무엇을 하라고만 말하지 않고 왜 그것이 중요한지, 어떤 기준으로 판단하면 되는지를 함께 건네면, 다음 비슷한 상황에서 구성원은 스스로 판단할 재료를 갖게 됩니다. 대표가 없는 자리에서 내려진 결정을, 결과가 아쉽더라도 곧바로 처벌하지 않고 판단의 기준을 다듬는 기회로 삼는 것도 같은 일입니다. 자발적 판단을 한 번 벌하면, 조직은 다시 시키는 것만 기다리는 자리로 돌아갑니다.&lt;/p&gt;
&lt;p&gt;이것은 대표가 힘을 내려놓는 일이 아니라, 힘의 원천을 자리 바깥에서 조직 안으로 옮기는 일입니다. 강제해야만 움직이는 조직은 대표가 강제를 멈추는 순간 멈추지만, 이해로 움직이는 조직은 대표가 보지 않을 때도 움직입니다. 마키아벨리의 표현을 빌리면, 빌린 힘 위에 선 권력이 아니라 자기 기반 위에 선 권력입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 이 이해가 한쪽으로만 흐를 때의 위험을 다룹니다. 대표가 구성원에게 맥락을 건네는 데까지는 왔지만, 정작 모든 판단을 여전히 자신의 안목으로만 내리려 할 때—자기 눈을 과신하는 순간 조직의 눈이 어떻게 감기는지에 관한 이야기입니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>리더십</category><category>조직</category><category>스타트업 군주론</category></item><item><title>이길 수 없는 전장에서 싸우는 위험에 대하여 — 용맹은 뛰어들고, 전략은 고른다</title><link>https://blog.bepuljang.co.kr/startup-prince/05/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/05/</guid><description>『스타트업 군주론』 2부의 첫 이야기. 어느 전장에 서게 되는가는 상당 부분 운의 몫이고, 그 안에서 어떻게 싸우는가가 실력의 몫입니다. 지는 전장에서 근성으로 버티는 위험을, 마키아벨리가 본 로마인의 전쟁 방식과 운명(fortuna)의 절반을 빌려 살펴봅니다.</description><pubDate>Sat, 11 Jul 2026 14:39:50 GMT</pubDate><content:encoded>&lt;p&gt;1부에서는 사업이 무엇 위에 서 있는가를 물었습니다. 비전, 돈, 접점, 시운—겉보기에는 근간처럼 보이지만 실제로는 사업을 오래 떠받치지 못하는 것들이었습니다. 2부에서는 질문이 바뀝니다. 서 있을 자리를 찾았다면, 이제 그 자리에서 조직을 어떻게 이끌 것인가입니다.&lt;/p&gt;
&lt;p&gt;그 첫 번째 질문은 리더가 내리는 가장 앞선 결정에 관한 것입니다. 바로 어디서 싸울 것인가입니다. 앞 편에서 우리는 시장이 밀어 올린 성장을 자신의 역량으로 착각하는 위험을 살펴봤습니다. 그렇다면 운과 역량은 각각 어디에 놓여 있는 것일까요. 이 편의 이야기는 거기서 시작합니다.&lt;/p&gt;
&lt;h2 id=&quot;이길-수-없는-자리에서-버티는-조직&quot;&gt;이길 수 없는 자리에서 버티는 조직&lt;/h2&gt;
&lt;p&gt;창업자에게 근성은 미덕입니다. 안 되는 일을 되게 만들어온 경험이 오늘의 회사를 만들었기 때문에, 대부분의 창업자는 노력의 총량이 결국 결과를 만든다고 믿습니다. 그러나 이 믿음이 향하는 대상이 잘못되면, 같은 미덕이 조직을 소모시키는 원인이 됩니다.&lt;/p&gt;
&lt;p&gt;익숙한 장면이 있습니다. 이미 거대한 사업자가 자리를 굳힌 시장에 정면으로 뛰어들어, 더 많은 마케팅비와 더 긴 근무로 격차를 좁히려는 경우입니다. 혹은 수요 자체가 구조적으로 꺼져가는 카테고리에서, 시장이 문제가 아니라 우리의 실행이 부족한 탓이라 여기며 더 세게 밀어붙이는 경우입니다. 이때 조직은 분명히 열심히 일하고 있고, 대표는 그 노력을 자랑스러워할 만합니다. 문제는 그 노력이 애초에 이기도록 설계되지 않은 자리에서 소모되고 있다는 것입니다. 이것이 필부(匹夫)의 용맹입니다. 용감하게 뛰어들지만, 어디로 뛰어드는지는 묻지 않는 용맹입니다.&lt;/p&gt;
&lt;h2 id=&quot;로마인은-전쟁을-미루지-않았다&quot;&gt;로마인은 전쟁을 미루지 않았다&lt;/h2&gt;
&lt;p&gt;마키아벨리는 『군주론』에서 로마인의 방식을 이렇게 전합니다. 로마인은 눈앞의 분쟁을 피하려고 전쟁을 미루는 법이 없었다는 것입니다. 그들은 전쟁이란 피할 수 있는 것이 아니라 다만 미뤄질 뿐이며, 시간을 끄는 동안 이득을 보는 쪽은 언제나 상대편이라는 것을 알았기 때문입니다. 그래서 로마인은 불리해지기 전에, 자신에게 유리한 때와 자리에서 싸우기를 택했습니다.&lt;/p&gt;
&lt;p&gt;여기서 핵심은 로마인이 싸움을 두려워하지 않았다는 대목이 아닙니다. 그들이 언제 어디서 싸울지를 스스로 골랐다는 대목입니다. 용맹한 것과 아무 데서나 싸우는 것은 다릅니다. 로마인의 강함은 물러서지 않는 근성이 아니라, 싸움의 조건을 자기 쪽으로 끌어당기는 판단에 있었습니다.&lt;/p&gt;
&lt;h2 id=&quot;전장은-운이-정하고-싸움은-기技가-한다&quot;&gt;전장은 운이 정하고, 싸움은 기(技)가 한다&lt;/h2&gt;
&lt;p&gt;흔히 운칠기삼(運七技三)이라고 합니다. 사업의 성패에서 운이 일곱이고 기술이 셋이라는 말인데, 이 비율을 패배주의로 읽으면 아무것도 남지 않습니다. 그러나 운과 기가 어디에 각각 놓이는지를 나누어 보면, 이 말은 오히려 실천적인 지침이 됩니다.&lt;/p&gt;
&lt;p&gt;어느 전장에 서게 되는가—어떤 시장이 열리는지, 그 시장의 구조가 신생 기업에 유리한지, 타이밍이 맞아떨어지는지—의 상당 부분은 운의 몫입니다. 창업자가 아무리 애를 써도 없던 수요를 만들어내거나 이미 굳은 시장 구조를 뒤집기는 어렵습니다. 반면 그 전장 안에서 어떻게 싸우는가—무엇에 자원을 집중하고, 어떤 순서로 움직이고, 어디서 물러설지—는 기의 몫입니다. 여기가 실력이 실제로 작동하는 자리입니다.&lt;/p&gt;
&lt;p&gt;이 구분에서 두 가지 태도가 갈립니다. 필부의 용맹은 지는 전장에 기를 쏟아붓습니다. 구조적으로 불리한 자리를 노력으로 뒤집을 수 있다고 믿기 때문에, 가장 귀한 자원인 시간과 사람을 이길 수 없는 싸움에 밀어 넣습니다. 냉철한 전략은 반대로 움직입니다. 어느 전장이 이길 수 있는 자리인지를 먼저 냉정하게 가려낸 뒤, 그 자리에 기를 집중합니다. 같은 실력이라도 지는 전장에서는 흔적도 없이 사라지고, 이기는 전장에서는 승부를 가르는 차이가 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;이길-수-있는-전장을-어떻게-알아보는가&quot;&gt;이길 수 있는 전장을 어떻게 알아보는가&lt;/h2&gt;
&lt;p&gt;그렇다면 이기는 전장과 지는 전장은 어떻게 구분할 수 있을까요. 몇 가지 질문이 도움이 됩니다.&lt;/p&gt;
&lt;p&gt;첫째, 이 시장의 구조가 우리 편인가 아닌가입니다. 후발주자가 선발주자를 뒤집은 사례가 이 시장에 존재하는가, 아니면 한번 굳은 순위가 좀처럼 바뀌지 않는 시장인가. 네트워크 효과나 전환 비용이 이미 강하게 작동하는 시장이라면, 우리가 아무리 잘해도 구조가 상대를 지켜줍니다. 둘째, 승부를 가르는 결정적 변수가 우리가 특별히 잘하는 것과 겹치는가입니다. 이 시장에서 이기는 데 가장 중요한 능력이 마침 우리의 강점이라면 유리한 전장이고, 우리가 약한 지점이 승부처라면 불리한 전장입니다. 셋째, 노력의 총량이 승부를 가르는가, 아니면 구조가 가르는가입니다. 더 열심히 하면 이기는 싸움도 있지만, 아무리 열심히 해도 구조가 결과를 미리 정해둔 싸움도 있습니다.&lt;/p&gt;
&lt;p&gt;이 질문들에 정직하게 답하다 보면, 지금 우리가 서 있는 자리가 노력으로 열리는 전장인지, 아니면 애초에 다른 자리를 골랐어야 하는 전장인지가 드러납니다. 냉정한 답이 나온다고 해서 곧바로 무언가 잘못한 것은 아닙니다. 전장을 정하는 몫의 상당 부분은 운이었으니까요. 다만 그 답을 회피하는 순간부터는 온전히 대표의 책임이 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;후퇴는-패배가-아니다&quot;&gt;후퇴는 패배가 아니다&lt;/h2&gt;
&lt;p&gt;이 이야기는 어려운 싸움을 무조건 피하라는 뜻이 아닙니다. 모든 좋은 전장은 처음에는 어렵게 보이고, 쉬운 자리에는 대개 이미 사람이 몰려 있습니다. 요점은 어려움의 종류를 구분하라는 것입니다. 실행으로 넘을 수 있는 어려움과, 구조가 만들어낸 넘을 수 없는 어려움은 다릅니다. 앞의 것은 기로 싸울 대상이고, 뒤의 것은 전장을 옮겨야 할 신호입니다.&lt;/p&gt;
&lt;p&gt;그래서 전략에는 후퇴와 전장 이동이 포함됩니다. 스타트업에서 이것을 흔히 피벗이라 부릅니다. 지는 전장에서 발을 빼 이길 수 있는 전장으로 옮기는 결정은, 근성이 부족해서가 아니라 근성을 어디에 쓸지 아는 데서 나옵니다. 로마인이 유리한 때를 골라 싸웠듯, 리더는 이길 수 있는 자리를 골라 조직의 힘을 모읍니다. 용맹은 뛰어들고, 전략은 고릅니다.&lt;/p&gt;
&lt;p&gt;전장을 골랐다면, 다음은 그 자리에서 사람을 어떻게 움직이게 할 것인가입니다. 다음 편에서는 조직을 이끄는 것과 지배하는 것의 차이를 다룹니다. 대표가 자리의 힘으로 복종을 얻어낼 때, 그 조직이 왜 대표가 보는 앞에서만 움직이게 되는지에 관한 이야기입니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>전략</category><category>시장</category><category>스타트업 군주론</category></item><item><title>감성은 강물의 온도다 — UX디자인의 세 번째 파라미터</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/09/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/09/</guid><description>사용성과 편의성만으로는 설명되지 않는 감성이라는 층위를 다룹니다. 도널드 노먼의 세 가지 감성 수준을 통해 UX디자인에서 감성이 수행하는 역할과, 감성 디자인이 빠지기 쉬운 함정을 살펴봅니다.</description><pubDate>Fri, 10 Jul 2026 15:04:56 GMT</pubDate><content:encoded>&lt;p&gt;인지의 세 가지 처리 방식인 선택집중, 연관짓기, 심성모형을 통해 사용자가 어떻게 정보를 받아들이고 행동으로 표출하는지를 살펴보았습니다. 그런데 이 인지적 절차들이 작동하는 과정에서 빠질 수 없는 것이 하나 있습니다. 바로 감성(Emotion)입니다.&lt;/p&gt;
&lt;p&gt;우리가 정보를 선택하고, 의미를 묶고, 기존의 모형에 비추어 판단하는 모든 과정에는 감성이 개입합니다. 감성은 인지의 부산물이 아니라, 인지 그 자체의 일부입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이 시리즈에서 사용성과 편의성에 이은 세 번째 UX디자인 파라미터로 감성(Pleasurability)을 제시한 바 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;사용성과 편의성이 비교적 분석적이고 구조적인 영역이라면, 감성은 이들 위에 놓인 정서적 가치의 영역입니다. 그리고 이 감성이야말로 경험을 ‘기억’하게 만드는 결정적인 요소이기도 합니다.&lt;/p&gt;
&lt;p&gt;사용성이 좋아서 불편하지 않았던 경험은 쉽게 잊히지만, 감성적으로 인상깊었던 경험은 오래 남습니다. 우리가 어떤 제품이나 서비스에 대해 ‘좋다’고 기억하는 것은 대부분 이 감성의 층위에서 형성된 인상입니다.&lt;/p&gt;
&lt;h2 id=&quot;감성의-층위&quot;&gt;감성의 층위&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;감성은 어디에서 오는가&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;감성적 반응은 크게 세 가지 층위에서 발생합니다. 도널드 노먼(Donald Norman)은 이를 본능적(Visceral), 행동적(Behavioral), 반성적(Reflective) 수준으로 구분했는데, 이 구분은 감성이 단순히 ‘예쁘다’의 문제가 아님을 보여주는 데 유용합니다.&lt;/p&gt;
&lt;p&gt;본능적 수준은 우리가 대상을 처음 마주했을 때의 즉각적인 감각적 반응입니다. 색상, 형태, 질감, 소리 등이 유발하는 첫인상으로, 의식적인 분석 이전에 이미 발생합니다. 매장에 들어서는 순간의 공기와 조명, 앱을 처음 켰을 때의 화면이 주는 느낌이 이에 해당합니다. 이 수준의 감성은 빠르고 강력하지만, 지속성이 비교적 짧습니다.&lt;/p&gt;
&lt;p&gt;행동적 수준은 사용하는 과정에서의 감성입니다. 버튼을 눌렀을 때의 반응, 문을 열 때의 손맛, 스크롤의 부드러움 같은 인터랙션의 질감에서 오는 만족감입니다. 이 수준은 앞서 다룬 사용성, 편의성과 밀접하게 연관되어 있으며, ‘잘 작동한다’는 느낌 자체가 감성적 만족으로 이어집니다. 즉, 기능적인 속성도 감성을 유발할 수 있습니다.&lt;/p&gt;
&lt;p&gt;반성적 수준은 사용 이후, 또는 사용 과정을 되돌아볼 때의 감성입니다. ‘이 제품을 쓰는 나’에 대한 자아 이미지, 타인에게 추천하고 싶은 마음, 브랜드에 대한 신뢰와 애착 등이 여기에 해당합니다. 이 수준은 가장 느리게 형성되지만 가장 오래 지속되며, 경험에 대한 최종적인 기억을 지배합니다.&lt;/p&gt;
&lt;h2 id=&quot;감성과-인지-그리고-행동&quot;&gt;감성과 인지, 그리고 행동&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;감성과 인지의 상호작용&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;흥미로운 것은 감성이 인지의 결과일 뿐 아니라 인지의 방향을 결정짓기도 한다는 점입니다. 긍정적인 감성 상태에서는 선택집중의 범위가 넓어지고, 연관짓기가 유연해지며, 심성모형의 적용이 관대해집니다. 반대로 불안이나 좌절의 상태에서는 집중이 좁아지고, 사소한 불일치에도 민감하게 반응하며, 기존의 모형과 조금만 달라도 혼란을 느끼게 됩니다.&lt;/p&gt;
&lt;p&gt;이는 UX디자인에 있어 중요한 시사점을 제공합니다. 사용 절차 초반에 부정적인 감성이 유발되면, 이후의 절차가 아무리 잘 설계되어 있어도 사용자는 그것을 ‘어렵다’고 느낄 가능성이 높아집니다. 반대로, 초반에 긍정적인 인상을 형성하면 이후의 사소한 불편은 관대하게 수용될 수 있습니다.&lt;/p&gt;
&lt;p&gt;경험이 시간적 절차를 통해 형성된다는 점을 상기하면, 이 감성의 순서와 리듬은 절차 설계에서 매우 중요한 고려사항이 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;감성 디자인의 함정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그러나 감성을 다룰 때 주의해야 할 함정들도 있습니다. 가장 대표적인 것은 감성을 ‘추가’하려는 시도입니다. 기능과 구조를 먼저 만들어 놓고, 그 위에 감성적 요소를 덧입히려는 접근입니다. 이는 앞서 디자인의 역사에서 살펴본, 기능공의 산출물에 장식을 더하던 초기 디자인의 접근과 다를 바 없습니다.&lt;/p&gt;
&lt;p&gt;감성은 덧붙이는 것이 아니라 스며드는 것입니다. 사용 절차의 설계, 정보의 구조화, 인터랙션의 설계 등 모든 과정에서 감성은 이미 형성되고 있습니다. 로딩 화면의 지루함도, 오류 메시지의 차가움도, 완료 후의 허무함도 모두 감성적 경험입니다. 이러한 순간들을 의식적으로 관리하는 것이 감성 디자인이지, 마지막에 예쁜 일러스트레이션을 추가하는 것이 감성 디자인은 아닙니다.&lt;/p&gt;
&lt;p&gt;또 하나의 함정은 보편적인 감성을 추구하는 것입니다. 앞서 강조했듯이 사용자에 따라 감성적 반응은 완전히 달라질 수 있습니다. 어떤 사용자에게 ‘세련된’ 느낌을 주는 미니멀한 인터페이스가, 다른 사용자에게는 ‘불친절한’ 느낌을 줄 수 있습니다. 감성 역시 목표 사용자에 대한 이해를 바탕으로 설계되어야 하며, 디자이너 자신의 감성적 선호를 투영하는 것은 위험합니다.&lt;/p&gt;
&lt;p&gt;이 시리즈 초반에 이야기한 강의 비유를 다시 빌려오자면, 감성은 강물의 온도에 해당할 것입니다. 수질(인지)이 깨끗하고 흐름(절차)이 순조롭더라도, 물의 온도가 적절하지 않으면 그 강에 발을 담그고 싶지 않게 됩니다. 그리고 그 온도는 강의 어느 한 지점에서 조절되는 것이 아니라, 원류부터 하류까지의 전 과정에서 형성됩니다.&lt;/p&gt;
&lt;p&gt;감성도 마찬가지입니다. 경험의 전 과정에 걸쳐, 사용자의 정서적 온도를 적절하게 유지하는 것. 이것이 UX디자인에서 감성이 수행하는 역할입니다.&lt;/p&gt;
&lt;p&gt;다음 글부터는 이 선언을 실무로 옮기는 구체적인 도구들을 하나씩 다룹니다. 사용자의 인지와 감성을 어떻게 관찰하고 포착할 것인가 — 관찰의 도구에서부터 시작합니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>감성 디자인</category><category>도널드 노먼</category><category>사용자 경험</category></item><item><title>버그와 마주쳤을 때 — AI와 함께 원인을 찾는 법</title><link>https://blog.bepuljang.co.kr/vibecoding/10/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/10/</guid><description>프로덕션 버그를 마주했을 때 AI와 함께 원인을 찾고 해결하는 방법을 설명합니다.</description><pubDate>Fri, 10 Jul 2026 15:04:56 GMT</pubDate><content:encoded>&lt;p&gt;서비스를 배포하고 나면 반드시 버그를 만납니다. 로컬에서는 잘 됐는데 배포 후에 안 된다거나, 사용자가 “이거 왜 안 되죠?”라고 문의를 보내오는 경우입니다. 바이브코딩으로 만든 서비스에서 버그를 마주했을 때 어떻게 접근하면 좋은지 알아봅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;프로덕션-버그를-마주하는-상황&quot;&gt;프로덕션 버그를 마주하는 상황&lt;/h2&gt;
&lt;p&gt;버그는 크게 두 가지 경로로 발견됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;직접 발견&lt;/strong&gt;
서비스를 직접 사용하다가 특정 동작이 예상대로 안 되는 것을 발견합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용자 보고&lt;/strong&gt;
서비스를 공개한 뒤 사용자가 버그를 알려줍니다.&lt;/p&gt;
&lt;p&gt;두 경우 모두 버그를 파악하는 순서는 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;버그를 재현할 수 있는가 (어떤 상황에서 발생하는가)&lt;/li&gt;
&lt;li&gt;어느 부분에서 발생하는가 (어떤 코드, 어떤 기능)&lt;/li&gt;
&lt;li&gt;왜 발생하는가 (원인)&lt;/li&gt;
&lt;li&gt;어떻게 고치는가 (해결)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;바이브코딩에서 어려운 점은 3번입니다. 코드 전체를 직접 작성하지 않았기 때문에 어디서 문제가 생기는지 바로 알기 어렵습니다. 이때 AI를 활용합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ai에게-디버깅-요청하는-방법&quot;&gt;AI에게 디버깅 요청하는 방법&lt;/h2&gt;
&lt;p&gt;AI에게 버그 수정을 요청할 때는 정보를 최대한 많이 제공하는 것이 중요합니다.&lt;/p&gt;
&lt;h3 id=&quot;좋은-버그-보고-형식&quot;&gt;좋은 버그 보고 형식&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[버그 설명]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;북마크를 삭제하면 목록에서 사라지는데, 페이지를 새로고침하면 다시 나타남.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[재현 방법]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1. 북마크를 3개 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2. 가운데 북마크의 삭제 버튼 클릭&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3. 목록에서 사라짐 (정상)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4. F5로 새로고침&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;5. 삭제된 북마크가 다시 나타남 (비정상)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[예상 동작]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;삭제한 북마크는 새로고침 후에도 사라져 있어야 함.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[브라우저 콘솔 에러]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;(없음 / 또는 에러 메시지 전체)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[관련될 것 같은 파일]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;BookmarkList.jsx, storage.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 구체적으로 전달하면 AI가 무엇을 봐야 할지 바로 파악할 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;에러-메시지가-있는-경우&quot;&gt;에러 메시지가 있는 경우&lt;/h3&gt;
&lt;p&gt;브라우저에서 에러가 나면 콘솔(F12 → Console 탭)에 빨간 글씨로 메시지가 나타납니다. 이것을 전부 복사해서 Claude Code에 붙여넣으면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;아래 에러가 나고 있어. 원인과 해결 방법 알려줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Uncaught TypeError: Cannot read properties of undefined (reading &apos;filter&apos;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at BookmarkList.jsx:23&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at Array.map (&amp;#x3C;anonymous&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at BookmarkList (BookmarkList.jsx:18)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;에러 메시지에는 어느 파일의 몇 번째 줄에서 발생했는지가 나옵니다. AI는 이 정보를 바탕으로 해당 코드를 찾아 원인을 파악합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;디버깅-과정에서-자주-쓰는-프롬프트-패턴&quot;&gt;디버깅 과정에서 자주 쓰는 프롬프트 패턴&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;원인 분석 먼저 요청&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;아래 버그의 원인을 분석해줘. 수정은 아직 하지 말고 왜 이런 현상이 일어나는지 설명해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[버그 설명]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;먼저 원인을 이해하고 수정 방향을 파악한 뒤 고치도록 합니다. 바로 “고쳐줘”라고 하면 표면적 증상만 해결하고 근본 원인이 남는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;단계별 디버깅 요청&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;이 버그의 원인을 찾기 위해 단계별로 확인해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;각 단계에서 어떤 값이 들어오고 나가는지 console.log를 추가해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;내가 직접 실행해보고 결과를 알려줄게.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AI가 코드를 직접 실행할 수 없는 경우, 개발자가 실행 결과를 다시 알려주면서 원인을 좁혀가는 방식입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;수정 후 검증 요청&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;수정한 코드가 맞는 방향인지 확인해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;다른 기능에 영향을 줄 수 있는 부분이 있는지 같이 봐줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;어느-부분에서-났지--영향-범위-파악하기&quot;&gt;”어느 부분에서 났지?” — 영향 범위 파악하기&lt;/h2&gt;
&lt;p&gt;버그의 원인을 찾았다면 이제 “이 버그가 얼마나 많은 부분에 영향을 주는가”를 파악해야 합니다. 하나의 버그가 여러 기능에 걸쳐 영향을 줄 수 있습니다.&lt;/p&gt;
&lt;p&gt;예를 들어 localStorage에 데이터를 저장하는 방식에 문제가 있다면 북마크 저장뿐만 아니라 태그 저장, 설정 저장 등 localStorage를 쓰는 모든 기능에 영향을 줄 수 있습니다.&lt;/p&gt;
&lt;p&gt;이때도 AI에게 물어보면 됩니다. &lt;code&gt;CLAUDE.md&lt;/code&gt;에 구조가 정리되어 있으면 더 정확합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;storage.js와 연결된 컴포넌트가 무엇인지 확인해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;localStorage 저장 로직에 버그가 있다면 어느 기능들이 영향을 받는지 파악해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code가 코드와 구조 설명을 읽어 영향 범위를 파악합니다. 구조가 잘 기록되어 있을수록 더 정확한 분석이 가능합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;버그-수정-후-확인사항&quot;&gt;버그 수정 후 확인사항&lt;/h2&gt;
&lt;p&gt;버그를 수정한 뒤에는 두 가지를 확인합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 버그가 실제로 해결됐는가&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;재현 방법을 그대로 따라가서 버그가 없어졌는지 확인합니다. 로컬에서 확인 후 배포해서 실제 환경에서도 확인합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 다른 기능이 망가지지 않았는가&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;버그 수정이 다른 기능에 영향을 줄 수 있습니다. 앞에서 파악한 영향 범위에 있는 기능들을 직접 사용해보면서 이상이 없는지 확인합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;버그를-방지하는-습관&quot;&gt;버그를 방지하는 습관&lt;/h2&gt;
&lt;p&gt;사후에 버그를 고치는 것보다 버그가 생기지 않도록 예방하는 것이 더 효율적입니다.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;습관&lt;/th&gt;&lt;th&gt;방법&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;기능 추가 후 직접 테스트&lt;/td&gt;&lt;td&gt;새 기능을 추가하면 관련 기능들을 직접 사용해서 확인&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;범위를 명시한 프롬프트&lt;/td&gt;&lt;td&gt;AI에게 요청할 때 기존 기능에 영향 주지 말 것을 명시&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;작은 단위로 배포&lt;/td&gt;&lt;td&gt;한 번에 많은 기능을 배포하지 않고 조금씩 배포&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;변경 이력 기록&lt;/td&gt;&lt;td&gt;무엇을 언제 바꿨는지 기록 (GitHub 커밋 메시지)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;바이브코딩에서 완벽하게 버그를 예방할 수는 없습니다. 하지만 발견했을 때 빠르게 원인을 찾고 수정할 수 있는 구조를 갖추는 것이 중요합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;다음-편에서&quot;&gt;다음 편에서&lt;/h2&gt;
&lt;p&gt;마지막 편에서는 바이브코딩으로 만든 서비스를 장기적으로 유지하는 방법을 다룹니다. 초기의 빠른 속도를 유지하면서도 서비스가 성장해도 관리 가능한 상태로 두는 루틴과 사고방식을 정리합니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>디버깅</category><category>버그</category><category>Claude Code</category><category>바이브코딩</category></item><item><title>Context — 멀리 떨어진 컴포넌트에 값을 건네는 길</title><link>https://blog.bepuljang.co.kr/react/08/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/08/</guid><description>Props를 계단처럼 넘기는 prop drilling의 피로를 Context로 푸는 법을 정리합니다. createContext·Provider·useContext 3단계, 그리고 언제 쓰고 언제 아껴야 하는지까지 짚습니다.</description><pubDate>Fri, 10 Jul 2026 07:12:44 GMT</pubDate><content:encoded>&lt;p&gt;지난 글까지는 컴포넌트 하나가 스스로 다루는 값(State·Ref)을 봤습니다. 이제 시야를 넓혀, &lt;strong&gt;여러 컴포넌트가 값을 나눠 갖는&lt;/strong&gt; 이야기로 넘어갑니다. Props가 부모에서 자식으로 값을 건넨다고 했는데, 이걸로 충분하지 않은 순간이 있습니다. 그 빈틈을 메우는 것이 &lt;strong&gt;Context&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;prop-drilling--값을-계단처럼-나르는-피로&quot;&gt;Prop drilling — 값을 계단처럼 나르는 피로&lt;/h2&gt;
&lt;p&gt;Props는 &lt;strong&gt;한 칸씩&lt;/strong&gt; 전달됩니다. 부모 → 자식 → 손자로, 한 단계씩요. 그런데 최상위에서 정한 값(예: 다크/라이트 테마)을 다섯 단계 아래의 버튼이 써야 한다면 어떻게 될까요?&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;App&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; theme&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{theme}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Layout&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; theme&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{theme}&gt;       {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* Layout은 theme을 쓰지도 않는데… */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Sidebar&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; theme&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{theme}&gt;    {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* Sidebar도 그냥 넘기기만… */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Button&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; theme&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{theme} /&gt; {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 진짜 필요한 건 여기 하나 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;중간의 &lt;code&gt;Layout&lt;/code&gt;, &lt;code&gt;Sidebar&lt;/code&gt;는 &lt;code&gt;theme&lt;/code&gt;을 &lt;strong&gt;쓰지도 않으면서&lt;/strong&gt; 그저 아래로 전달하기 위해 계속 받아 넘겨야 합니다. 이렇게 값을 계단처럼 층층이 실어 나르는 것을 &lt;strong&gt;prop drilling&lt;/strong&gt;이라고 부릅니다. 층이 깊어질수록 코드가 지저분해지고, 중간 컴포넌트가 무슨 값을 나르는지도 파악하기 어려워집니다.&lt;/p&gt;
&lt;p&gt;Context는 이 계단을 건너뛰게 해 줍니다. 위에서 값을 &lt;strong&gt;한 번 뿌려 두면&lt;/strong&gt;, 아래 어느 깊이의 컴포넌트든 중간을 거치지 않고 &lt;strong&gt;직접 꺼내&lt;/strong&gt; 쓸 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;context의-3단계&quot;&gt;Context의 3단계&lt;/h2&gt;
&lt;p&gt;Context는 딱 세 단계로 씁니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① 만든다 — &lt;code&gt;createContext&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { createContext } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; createContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;light&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 기본값&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;createContext&lt;/code&gt;가 돌려주는 것은 컴포넌트가 아니라 &lt;strong&gt;하나의 “통로 객체”&lt;/strong&gt;입니다. 이 객체가 값을 뿌리는 쪽과 꺼내는 쪽을 이어 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 뿌린다 — &lt;code&gt;&amp;#x3C;Context&gt;&lt;/code&gt;로 감싼다&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyPage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Form&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;   {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 이 안의 어떤 깊이든 &apos;dark&apos;를 꺼낼 수 있음 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ThemeContext&lt;/code&gt;로 감싼 영역 안에서는, 레벨에 상관없이 그 값을 구독할 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;예전 코드에서는 &lt;code&gt;&amp;#x3C;ThemeContext.Provider value=&quot;dark&quot;&gt;&lt;/code&gt; 형태를 씁니다. React 19부터는 위처럼 &lt;code&gt;&amp;#x3C;ThemeContext value=...&gt;&lt;/code&gt;로 바로 쓸 수 있게 짧아졌습니다. 둘은 같은 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;③ 꺼낸다 — &lt;code&gt;useContext&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { useContext } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Button&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; theme&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ThemeContext); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 중간을 거치지 않고 바로 꺼냄&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{theme}&gt;버튼&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Button&lt;/code&gt;이 아무리 깊은 곳에 있어도, &lt;code&gt;useContext(ThemeContext)&lt;/code&gt; 한 줄이면 위에서 뿌린 값을 곧바로 받습니다. 계단을 오르내리던 &lt;code&gt;theme&lt;/code&gt; prop들이 전부 사라지는 거죠.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;상수만이-아니라-상태도-함수도&quot;&gt;상수만이 아니라 상태도, 함수도&lt;/h2&gt;
&lt;p&gt;뿌리는 값은 고정된 상수일 필요가 없습니다. &lt;strong&gt;State와 결합&lt;/strong&gt;하면, 아래에서 값을 바꾸는 것까지 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyPage&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;theme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setTheme&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dark&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{{ theme, setTheme }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Form&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;theme&lt;/code&gt;과 &lt;code&gt;setTheme&lt;/code&gt;을 함께 내려보내면, 하위 컴포넌트는 값을 &lt;strong&gt;읽는 것뿐 아니라 바꾸는 것&lt;/strong&gt;도 할 수 있습니다. 로그인 정보와 &lt;code&gt;login()&lt;/code&gt; 함수를 함께 뿌리는 인증 컨텍스트가 대표적인 예입니다.&lt;/p&gt;
&lt;p&gt;Provider는 중첩할 수도 있는데, 이 경우 &lt;strong&gt;가장 가까운 것이 이깁니다.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;dark&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;light&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Footer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;   {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 가장 가까운 &apos;light&apos;를 구독 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;ThemeContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;언제-쓰고-언제-아껴야-하나&quot;&gt;언제 쓰고, 언제 아껴야 하나&lt;/h2&gt;
&lt;p&gt;Context는 강력하지만 &lt;strong&gt;만능 도구가 아닙니다.&lt;/strong&gt; 테마, 로그인한 사용자, 언어 설정처럼 &lt;strong&gt;앱 전반이 두루 쓰는 값&lt;/strong&gt;을 뿌릴 때 빛납니다. 반대로 두세 단계만 내려가면 되는 값까지 전부 Context로 빼면, 오히려 값의 출처가 흐려져 추적이 어려워집니다. &lt;strong&gt;prop drilling이 실제로 불편해질 때&lt;/strong&gt; 꺼내 드는 도구로 생각하는 게 좋습니다.&lt;/p&gt;
&lt;p&gt;한 가지 더. Context의 값이 바뀌면, 그 값을 구독하는 하위 컴포넌트들이 &lt;strong&gt;다시 렌더링&lt;/strong&gt;됩니다. 넓은 범위를 감싼 Context일수록 이 리렌더의 파장이 커질 수 있어, 성능을 신경 써야 하는 순간이 옵니다. 이렇게 “필요 이상의 리렌더를 어떻게 줄일 것인가”가 다음 글의 주제입니다. 마지막으로 &lt;strong&gt;렌더링 최적화&lt;/strong&gt; — &lt;code&gt;useMemo&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt;, &lt;code&gt;memo&lt;/code&gt;를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>Context</category><category>useContext</category><category>상태 공유</category></item><item><title>시운으로 사업을 확장하는 위험에 대하여 — 운이 열어준 문, 역량이 지키는 자리</title><link>https://blog.bepuljang.co.kr/startup-prince/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/04/</guid><description>『스타트업 군주론』 1부의 마지막 이야기. 시장의 흐름에 올라탄 성장을 스스로의 역량으로 착각하는 위험을, 마키아벨리의 역량(virtù)과 운명(fortuna) 개념을 빌려 짚어봅니다.</description><pubDate>Fri, 10 Jul 2026 07:12:44 GMT</pubDate><content:encoded>&lt;p&gt;지금까지 비전, 돈, 접점이라는 세 가지 가짜 근간을 살펴봤습니다. 1부의 마지막으로 다룰 위험은 그중에서도 가장 알아채기 어려운 것입니다. 잘하고 있어서가 아니라, 운이 좋아서 성장하고 있는 경우입니다.&lt;/p&gt;
&lt;h2 id=&quot;잘나가던-회사가-왜-시장이-꺾이자마자-무너지는가&quot;&gt;잘나가던 회사가 왜 시장이 꺾이자마자 무너지는가&lt;/h2&gt;
&lt;p&gt;돌아보면 익숙한 장면입니다. 어떤 업종 전체가 특정 시기에 유난히 순풍을 탑니다. 팬데믹으로 비대면 서비스 수요가 폭발했던 시기, 혹은 저금리로 자금이 넘쳐나던 시기에 여러 스타트업이 동시에 가파른 성장 곡선을 그렸습니다. 그 안에 있던 창업자들은 자신들의 실행력과 전략이 그 성장을 만들어냈다고 믿기 쉽습니다.&lt;/p&gt;
&lt;p&gt;그러나 시장의 바람이 바뀌면, 같은 시기에 함께 떠올랐던 여러 회사가 동시에 무너지는 모습을 보게 됩니다. 그제서야 드러나는 것은, 그 성장의 상당 부분이 실은 시장 전체가 밀어 올린 것이었고, 그 아래에서 조직·비용구조·의사결정 체계는 정작 그 성장을 감당할 만큼 단단해지지 못했다는 사실입니다.&lt;/p&gt;
&lt;p&gt;이런 순간은 업종을 가리지 않고 반복됩니다. 특정 카테고리의 수요가 일시적으로 폭발할 때, 그 흐름에 먼저 올라탄 여러 회사가 비슷한 속도로 커집니다. 그 안에 있는 창업자들은 서로의 성장을 보며 각자의 전략이 검증되었다고 확신하지만, 실은 같은 파도 위에 떠 있는 여러 개의 배일 뿐입니다. 파도가 가라앉으면 배들의 진짜 차이—선체가 얼마나 튼튼한지—가 그제서야 드러납니다.&lt;/p&gt;
&lt;h2 id=&quot;역량virtù과-운명fortuna&quot;&gt;역량(virtù)과 운명(fortuna)&lt;/h2&gt;
&lt;p&gt;마키아벨리는 『군주론』에서 군주가 권력을 얻는 두 가지 경로를 구분합니다. 하나는 자신의 역량, 즉 비르투(virtù)로 얻은 권력이고, 다른 하나는 순전한 운, 포르투나(fortuna)로 얻은 권력입니다. 그는 운으로 얻은 권력이 유지하기 어려운 이유를 이렇게 설명합니다. 그 권력을 갖게 해준 조건—우호적인 세력, 우연한 정세, 타이밍—은 애초에 군주 자신이 만든 것이 아니기 때문에, 그 조건이 사라지면 권력을 지킬 방법도 함께 사라진다는 것입니다. 반면 자신의 역량으로 쌓은 권력은 그 힘의 원천이 자기 자신 안에 있기 때문에 조건이 변해도 지속됩니다.&lt;/p&gt;
&lt;p&gt;마키아벨리가 덧붙이는 흥미로운 지점은, 운으로 권력을 얻은 이들 중에서도 그 운이 지속되는 동안 스스로의 역량을 갈고 닦은 이는 이후에도 살아남았다는 것입니다. 운은 문을 열어줄 뿐이고, 그 문 안에서 자리를 지키는 것은 결국 역량의 몫입니다.&lt;/p&gt;
&lt;h2 id=&quot;성장기에-무엇을-하지-않았는가&quot;&gt;성장기에 무엇을 하지 않았는가&lt;/h2&gt;
&lt;p&gt;스타트업으로 옮겨보면, 진짜 위험은 시장의 순풍을 탄 것 자체가 아닙니다. 그 순풍이 부는 동안 정작 필요한 준비를 하지 않은 것입니다. 매출이 매달 갱신되는 시기에는 굳이 비용구조를 점검할 필요를 못 느낍니다. 채용이 순조로운 시기에는 조직 프로세스의 허점이 잘 드러나지 않습니다. 신규 유입이 넘쳐나는 시기에는 리텐션 지표를 자세히 들여다보지 않아도 전체 숫자는 계속 좋아 보입니다.&lt;/p&gt;
&lt;p&gt;이 모든 것이 순풍이 멈추는 순간 한꺼번에 문제로 떠오릅니다. 비용구조는 그 시절의 매출 규모에 맞춰져 있었는데 매출이 꺾이니 감당이 안 되고, 조직은 그 시절의 채용 속도에 맞춰 늘어났는데 정작 업무 프로세스는 그 규모를 받아내지 못하고, 리텐션이 낮았다는 사실은 신규 유입이 줄어든 후에야 뚜렷하게 드러납니다. 실제로 저금리 시기 풍부한 자금으로 빠르게 커졌던 여러 스타트업이, 금리가 오르고 투자가 조심스러워진 시기에 거의 동시에 조직을 축소하거나 사업을 접었습니다. 그들이 갑자기 무능해진 것이 아닙니다. 애초에 역량으로 큰 것이 아니라 운으로 컸다는 사실이, 그 운이 걷히는 순간 드러난 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;역량과-운을-구분하는-질문&quot;&gt;역량과 운을 구분하는 질문&lt;/h2&gt;
&lt;p&gt;문제는 성장의 한가운데에서는 그것이 역량 때문인지 운 때문인지 구분하기가 쉽지 않다는 점입니다. 여기서 쓸 수 있는 질문이 하나 있습니다. 같은 시기에 비슷한 조건으로 시작한 경쟁사들도 함께 성장했는가, 아니면 우리만 유독 빠르게 성장했는가. 업종 전체가 같은 곡선을 그리고 있다면, 그 성장의 상당 부분은 시장이 만든 것이고 우리의 역량이 만든 몫은 그 차이분—경쟁사보다 얼마나 더 빠르게, 더 건강하게 성장했는가—에 가깝습니다.&lt;/p&gt;
&lt;p&gt;이 구분을 냉정하게 해두는 조직은 시장이 꺾여도 자신들이 지킬 수 있는 몫이 얼마인지를 압니다. 반대로 성장의 전부를 자신의 역량으로 여겨온 조직은, 시장이 꺾이는 순간 자신이 지킬 수 있는 것이 얼마나 적은지를 그제서야 알게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;운이-좋을-때-해야-할-일&quot;&gt;운이 좋을 때 해야 할 일&lt;/h2&gt;
&lt;p&gt;그렇다면 결론은 운을 거부하라는 것이 아닙니다. 운은 마다할 이유가 없습니다. 다만 운이 좋을 때가 바로 역량을 쌓아야 할 시점이라는 것입니다. 지금의 매출 규모가 아니라 그보다 작았던 시절의 비용구조를 유지할 수 있는가, 지금의 성장 속도가 느려져도 버틸 수 있는 현금 버퍼가 있는가, 채용이 빠르게 늘어나는 만큼 그들이 실제로 일할 수 있는 프로세스가 함께 갖춰지고 있는가. 이런 질문들에 답을 만들어두는 일이야말로, 운이 걷힌 뒤에도 자리를 지키는 유일한 방법입니다.&lt;/p&gt;
&lt;p&gt;이 점검은 한 번으로 끝나지 않습니다. 매 분기 같은 질문—지금보다 작았던 시절의 비용구조로도 버틸 수 있는가, 성장이 반년 멈춰도 살아남을 현금이 있는가—을 반복해서 던지는 조직과, 성장이 계속될 것을 당연하게 여기고 이 질문을 미뤄두는 조직은 시장이 꺾이는 순간 완전히 다른 처지에 놓입니다.&lt;/p&gt;
&lt;p&gt;이 시리즈의 마지막 편에서 다시 다루겠지만, 몰락은 대개 운이 사라지는 그 순간이 아니라, 운이 좋았던 시절 준비하지 않았던 대가가 뒤늦게 도착하는 순간에 찾아옵니다.&lt;/p&gt;
&lt;p&gt;지금까지 1부에서는 비전, 돈, 접점, 시운이라는 네 가지 가짜 근간을 살펴봤습니다. 다음 편부터는 2부로 넘어가, 자리를 잡은 조직을 어떻게 이끌어야 하는가—리더십의 문제로 들어갑니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>시장</category><category>확장</category><category>스타트업 군주론</category></item><item><title>행동은 인지의 소용돌이다 — 보이지 않는 것을 관찰하는 법</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/08/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/08/</guid><description>사용자의 인지는 직접 들여다볼 수 없습니다. 그러나 인지가 어긋나는 지점에서 사용자는 반드시 평소와 다른 행동을 보입니다. 쇼핑몰 엘리베이터와 편의점 우유 사례로 행동 관찰이 UX디자인의 출발점인 이유를 살펴봅니다.</description><pubDate>Fri, 10 Jul 2026 07:12:44 GMT</pubDate><content:encoded>&lt;p&gt;물이 부드럽게 흘러가다가 어디선가 소용돌이친다면, 분명 그 밑에 물의 흐름을 방해하는 지형지물이 있어서 겉과 속의 흐름이 달라지고, 그것이 소용돌이라는 형태로 드러나는 것일 겁니다. 수면 위에서는 그저 물이 빙글빙글 도는 것만 보이지만, 그 원인은 반드시 수면 아래 어딘가에 존재합니다.&lt;/p&gt;
&lt;p&gt;이 시리즈에서 사용자 경험을 물에 빗댄 비유를 다시 빌려오자면, 이 소용돌이가 바로 사용자가 보이는 특이한 행동입니다. 경험의 흐름 속에 매끄럽지 않은 지점이 있을 때, 사용자는 자신도 모르는 사이에 평소와 다른 행동을 보이게 되고, 그 행동이야말로 문제의 존재를 알려주는 가장 확실한 신호가 됩니다.&lt;/p&gt;
&lt;p&gt;물 밑을 직접 들여다보기는 어렵지만, 물의 소용돌이를 찾기는 쉽습니다. 마찬가지로 사용자의 인지를 직접 들여다보기는 어렵지만, 행동을 관찰하기는 상대적으로 쉽습니다. 바로 이 점이, 사용자 경험 디자인에서 행동의 관찰이 핵심적인 위치를 차지하는 이유입니다.&lt;/p&gt;
&lt;h2 id=&quot;행동이란-무엇인가--무의식이-드러나는-방식&quot;&gt;행동이란 무엇인가 — 무의식이 드러나는 방식&lt;/h2&gt;
&lt;p&gt;그렇다면 여기서 말하는 ‘행동’이란 정확히 무엇일까요? 행동(Behavior)은 우리가 무의식적으로 행하는 움직임을 말합니다. 의식적으로 선택하고 실행하는 행위(Activity)와 달리, 행동은 스스로 자각하지 못한 채 자연스럽게 취하는 동작이나 반응에 가깝습니다.&lt;/p&gt;
&lt;p&gt;앞서 살펴보았듯이 겉으로 보이는 의식적인 인지에 비해, 무의식적인 인지가 경험을 형성하는 데 훨씬 더 많은 영향을 끼칩니다. 일상에서 내리는 수많은 판단과 선택의 대부분은 의식의 수면 아래에서 이루어지기 때문입니다. 따라서 의식적으로 행하는 행위(Activity)에 비해, 무의식적인 행동(Behavior)을 관찰하는 것은 사용자 경험을 이해하는 데 있어 훨씬 더 중요한 의미를 갖습니다.&lt;/p&gt;
&lt;p&gt;행동의 관찰이 중요한 이유는 이러한 양적인 비중의 문제에만 국한되지 않습니다. 사용자가 의식적으로 느끼는 문제들, 예를 들어 “이 버튼이 너무 작다”거나 “로딩이 느리다”와 같은 불편은 설문이나 인터뷰를 통해 비교적 쉽게 보고됩니다.&lt;/p&gt;
&lt;p&gt;그러나 무의식의 영역에서 발생하는 문제들은 사용자 스스로 인식하지 못하기 때문에, 질문을 던져도 잘 응답되지 않습니다. 응답되지 않으니 자연스럽게 문제로 인식되지도, 따라서 해결되지도 않습니다. 사용자가 “왜 불편한지 모르겠는데 뭔가 불편하다”고 느끼는 순간이 바로 이러한 무의식적 인지 문제가 작동하고 있는 경우이며, 이런 문제를 포착할 수 있는 거의 유일한 경로가 바로 행동에 대한 관찰입니다.&lt;/p&gt;
&lt;h2 id=&quot;쇼핑몰의-엘리베이터-사라진-동선의-의미&quot;&gt;쇼핑몰의 엘리베이터, 사라진 동선의 의미&lt;/h2&gt;
&lt;p&gt;구체적인 예를 통해 살펴보겠습니다. 어떤 쇼핑몰을 개점했는데, 이상하게 사용자들의 동선을 파악해보니 특정한 한 곳에서 빙빙 돌거나 잠시 멈칫하며 망설이는 모습이 반복적으로 잡혔다고 가정해보겠습니다.&lt;/p&gt;
&lt;p&gt;처음에는 단순히 그 구역에 흥미로운 매장이 있어서 머무는 것이라 생각할 수도 있습니다. 그러나 이 동선이 어떤 의미를 가지고 있는지 좀 더 면밀히 분석해보니, 엘리베이터를 찾는 사람들이 해당 지역을 한번씩 갔다가 엘리베이터를 발견하지 못하고 되돌아오는 모습으로 관찰되었다고 해보겠습니다.&lt;/p&gt;
&lt;p&gt;이 반복적인 행동은 무엇을 의미할까요? 사용자들은 어떤 이유에서인지 그 장소에 엘리베이터가 있을 것이라 기대했고, 그 기대가 어긋나면서 혼란을 겪고 있는 것입니다.&lt;/p&gt;
&lt;p&gt;우리는 기억, 위치, 지시, 분위기, 색상 등 다양한 단서로 시공간의 성격을 파악하고 행동합니다. 그 원인 역시 다양할 수 있습니다. 어쩌면 다른 쇼핑몰들에서는 일반적으로 그 위치에 엘리베이터가 있는 경우가 많아서, 사용자들이 과거의 경험을 기반으로 이곳에서도 같은 위치에 엘리베이터가 있을 것이라 짐작한 것일 수 있습니다.&lt;/p&gt;
&lt;p&gt;또는 복도 앞에 놓인 정수기와 소파가 만들어내는 분위기가, 더 안쪽으로 들어가면 엘리베이터가 있을 것 같은 착각을 일으켰을 수도 있습니다. 혹은 엘리베이터 앞에 흔히 위치하는 특정 종류의 브랜드들이 그 근처에 입점해 있어서, 사용자들이 무의식적으로 “이 브랜드가 있으니 엘리베이터도 근처에 있겠지”라고 오해했을 수도 있습니다.&lt;/p&gt;
&lt;p&gt;주목할 점은, 이 모든 판단이 의식적인 사고의 산물이 아니라는 것입니다. 우리는 단순히 지시적인 표지판만을 읽고 움직이는 것이 아니라, 공간의 형태, 사물의 배치, 분위기, 기억 등 다양한 정보를 종합적으로 얻고 미루어 짐작하는 식으로 인지적인 낭비를 줄입니다. 대부분의 경우 이러한 짐작은 맞아떨어지지만, 그 짐작의 근거가 되는 환경적 단서들이 실제와 어긋날 때 행동에 오류가 발생할 수 있는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;해결책은-표지판이-아니라-환경입니다&quot;&gt;해결책은 표지판이 아니라 환경입니다&lt;/h2&gt;
&lt;p&gt;그렇다면 이 문제를 어떻게 해결할 수 있을까요? 이미 지어진 건물에서 엘리베이터의 위치 자체를 바꾸기는 현실적으로 어렵습니다. 그러나 그 장소가 엘리베이터 공간처럼 인식되지 않도록, 사용자의 무의식적 판단에 영향을 주는 환경적 요소들을 재구성하는 것은 가능합니다.&lt;/p&gt;
&lt;p&gt;복도의 형태를 변경하거나, 오해를 유발하는 사물의 배치를 바꾸거나, 공간의 분위기를 전환하거나, 동선의 흐름을 자연스럽게 실제 엘리베이터 방향으로 유도하거나, 매장을 재배치하는 등 원인에 따라 다양한 해결책이 존재할 것입니다.&lt;/p&gt;
&lt;p&gt;이러한 접근들이 모두 실패하면 결국 큼지막한 표지판이나 입간판이 들어서게 되는데, 이는 가장 마지막에 써야 하는 해결책입니다. 표지판은 문제를 근본적으로 해소하는 것이 아니라 사용자에게 의식적인 인지 부담을 추가로 지우는 것이기에, 사용자 경험 디자인의 관점에서 가장 하책(下策)에 해당하기 때문입니다.&lt;/p&gt;
&lt;h2 id=&quot;추단휴리스틱과-편의점에서-우유를-찾는-법&quot;&gt;추단(휴리스틱)과 편의점에서 우유를 찾는 법&lt;/h2&gt;
&lt;p&gt;앞서 쇼핑몰 예시에서 사용자들이 다양한 단서를 종합하여 무의식적으로 판단을 내리는 모습을 살펴보았는데, 이러한 짐작을 통한 인지처리 방식에는 이름이 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이를 추단(휴리스틱; Heuristic)이라고 합니다. 모든 정보를 꼼꼼히 검토하지 않고 정보의 양을 대폭 줄여 빠르게 결정할 수 있도록 돕는 인지적 장치입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;사실 대부분의 경우 이 휴리스틱은 꼭 필요한 인지적 절약책으로 작동합니다. 만약 우리가 매 순간 모든 정보를 의식적으로 처리해야 한다면, 아무리 간단한 일상적 행동도 엄청난 인지적 에너지를 소모하게 될 것입니다.&lt;/p&gt;
&lt;p&gt;예를 들어, 처음 간 편의점에서도 우유를 비교적 쉽게 찾을 수 있는 것은 그 편의점에서 우유의 위치를 특별히 안내받아서가 아닙니다. 우유는 으레 냉장 코너의 어떠한 위치에, 어떠한 분위기 속에 진열되어 있다는 과거의 기억과 경험적인 판단, 즉 일종의 멘탈모델을 통해 무의식중에 발걸음이 향하는 것입니다.&lt;/p&gt;
&lt;p&gt;이처럼 우리는 물리적 공간뿐 아니라 디지털 환경에서도 다양한 사용자 인터페이스를 접하면서 이러한 종류의 인터랙션을 수도 없이 반복합니다. 그리고 이 자동적인 행동과 기대한 결과 사이의 연계가 원활하게 이어질 때 경험은 매끄럽게 흘러가지만, 그 연계가 깨졌을 때 비로소 인지적인 검토와 수정의 요구가 생기게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;흐름을-끊는-것도-디자인입니다--의도된-마찰&quot;&gt;흐름을 끊는 것도 디자인입니다 — 의도된 마찰&lt;/h2&gt;
&lt;p&gt;흥미로운 점은, 이 자동적인 흐름과 의식적 검토 사이의 간극(chasm)조차도 때로는 의도된 사용자 경험 요소가 될 수 있다는 것입니다.&lt;/p&gt;
&lt;p&gt;만약 어떤 중요한 정보에 사용자의 집중을 요구하고, 그 정보에 대해서는 무의식적인 행동의 흐름대로 넘어가는 것이 아니라 의식적인 검토가 반드시 필요하다면, 오히려 행동의 흐름에 의도적으로 방해를 가함으로써 사용자의 집중도를 높일 수 있습니다. 금융 서비스에서 중요한 약관 동의 전에 일부러 스크롤을 요구하거나, 되돌릴 수 없는 작업 전에 확인 단계를 추가하는 것이 그런 예가 될 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;다만 이러한 접근은 매우 이례적이고 신중하게 사용되어야 합니다. 대부분의 경우 사용자 경험 디자인은 자연스러운 경험의 흐름, 행동의 흐름을 유도하는 방향을 지향합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;따라서 이러한 간극이 의도되지 않은 상태에서 일어나고 있다면, 그것은 사용자 경험을 저해하는 물 밑의 바윗덩어리 같은 요인으로 여겨져야 합니다. 처음에 이야기했던 비유로 돌아가자면, 원치 않는 곳에서 일어나고 있는 소용돌이인 셈입니다.&lt;/p&gt;
&lt;h2 id=&quot;행동은-인지로-들어가는-유일한-창&quot;&gt;행동은 인지로 들어가는 유일한 창&lt;/h2&gt;
&lt;p&gt;지금까지의 논의를 종합해보겠습니다. 지난 글에서 사용자 경험 디자인은 ‘사용자 인지에 대한 디자인’임을 명시한 바 있습니다. 그러나 거듭 이야기되듯이 인지는 우리가 직접적으로 관찰하고 교정할 수 있는 대상이 아닙니다.&lt;/p&gt;
&lt;p&gt;인지는 사용자의 머릿속에서 일어나는 내적 과정이기에, 우리는 사용자가 사물에 대한 인지를 통해 겉으로 표현하는 ‘행동’을 관찰하여 그 인지를 추론할 수밖에 없습니다. 쇼핑몰에서 빙빙 도는 사람들의 동선을 통해 공간 인지의 문제를 파악했듯이, 행동이야말로 인지에 접근할 수 있는 유일한 창구인 셈입니다.&lt;/p&gt;
&lt;p&gt;또한 사용자 경험 디자인을 통해 사물을 교정하면 사용자는 그 교정된 사물을 새롭게 인지하게 되고, 역시 그 인지의 결과를 행동으로 표출하게 됩니다. 디자이너가 자신의 디자인이 의도한 대로 작동하고 있는지, 사용자 경험이 실제로 개선되었는지를 확인할 수 있는 것도 결국 이 행동을 통해서 유추할 수밖에 없습니다. 다시 말해, 사용자 경험 디자인의 전 과정은 행동으로 시작해 행동으로 끝나는 셈입니다.&lt;/p&gt;
&lt;p&gt;바로 이러한 이유로, 앞으로 이 시리즈에서 다룰 ‘UX디자인 기법’들은 행동을 관찰하고 그것을 분석하는 데 많은 초점을 두게 됩니다. 경험을 디자인한다, 또는 행동을 관찰하고 인지를 유추한다는 것은 개념적으로는 이해가 되어도, 막상 실무에서 실행하려고 하면 어디서부터 어떻게 시작해야 할지 막막하게 느껴지기 마련입니다.&lt;/p&gt;
&lt;p&gt;어떤 행동을 관찰해야 하는지, 그 행동에서 어떤 인지적 의미를 읽어내야 하는지, 그리고 그 해석을 어떻게 디자인의 개선으로 연결해야 하는지가 모두 구체적인 방법론을 필요로 합니다. UX디자인 기법들은 바로 이 지점에서 체계적인 절차와 사고의 틀을 제시하며, 사용자 경험 디자인이 궁극적으로 추구하는 사용자 인지의 교정이라는 목표에 한 걸음씩 다가갈 수 있도록 돕습니다.&lt;/p&gt;
&lt;p&gt;지금까지 UX디자인이 무엇이고, 경험이 어떤 원리로 형성되며, 인지와 행동이 그 안에서 각각 어떤 역할을 하는지를 살펴보았습니다. 경험의 뿌리에는 인지가 있고, 그 인지는 행동이라는 창을 통해서만 관찰할 수 있으며, 디자인의 결과 또한 행동을 통해 검증된다는 것이 지금까지 이야기의 골자였습니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 인지, 행동과 더불어 경험을 구성하는 또 하나의 축인 감성(Emotion)을 다룹니다. 전통적인 디자인에서부터 다루어져 온 만큼 익숙하게 느껴질 수 있지만, 여전히 강력하고 독자적인 UX디자인 파라미터입니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용자 행동</category><category>휴리스틱</category><category>인지</category></item><item><title>배포 후 코드 정리하기 — AI와 함께 리팩터링하는 법</title><link>https://blog.bepuljang.co.kr/vibecoding/09/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/09/</guid><description>바이브코딩 후 반드시 필요한 리팩터링을 AI와 함께 진행하는 방법을 설명합니다.</description><pubDate>Fri, 10 Jul 2026 07:12:44 GMT</pubDate><content:encoded>&lt;p&gt;서비스를 배포하고 나면 한 가지 선택의 기로에 서게 됩니다. 계속해서 새 기능을 추가할 것인가, 아니면 지금까지 만든 코드를 한 번 정리할 것인가.&lt;/p&gt;
&lt;p&gt;빠르게 기능을 만들어온 바이브코딩 프로젝트라면 이 시점이 중요합니다. 코드 정리 없이 계속 기능을 추가하면 나중에 AI도 코드를 파악하기 어려운 상태가 됩니다. 이 편에서는 AI와 함께 코드를 읽고 정리하는 방법, 즉 &lt;strong&gt;리팩터링(refactoring)&lt;/strong&gt;을 다룹니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;왜-바이브코딩-후엔-반드시-정리가-필요한가&quot;&gt;왜 바이브코딩 후엔 반드시 정리가 필요한가&lt;/h2&gt;
&lt;p&gt;리팩터링은 &lt;strong&gt;기능은 바꾸지 않고 코드의 구조를 개선하는 작업&lt;/strong&gt;입니다. 눈에 보이는 변화는 없지만 나중에 수정과 확장이 훨씬 쉬워집니다.&lt;/p&gt;
&lt;p&gt;바이브코딩으로 빠르게 만든 코드에는 공통적인 문제들이 생깁니다.&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;문제&lt;/th&gt;&lt;th&gt;예시&lt;/th&gt;&lt;th&gt;영향&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;한 파일에 너무 많은 역할&lt;/td&gt;&lt;td&gt;&lt;code&gt;App.jsx&lt;/code&gt;에 UI + 로직 + 데이터 처리가 한꺼번에&lt;/td&gt;&lt;td&gt;어디를 고쳐야 할지 파악하기 어려움&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;중복 코드&lt;/td&gt;&lt;td&gt;비슷한 함수가 2~3군데에 존재&lt;/td&gt;&lt;td&gt;하나 수정하면 다른 곳도 수동으로 바꿔야 함&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;일관성 없는 명명&lt;/td&gt;&lt;td&gt;&lt;code&gt;getBookmarks&lt;/code&gt;, &lt;code&gt;fetchData&lt;/code&gt;, &lt;code&gt;loadItems&lt;/code&gt;가 같은 기능&lt;/td&gt;&lt;td&gt;코드 읽는 데 시간이 더 걸림&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;하드코딩된 값&lt;/td&gt;&lt;td&gt;&lt;code&gt;localStorage.getItem(&apos;bm-data-v1&apos;)&lt;/code&gt; 같은 문자열이 여러 곳에&lt;/td&gt;&lt;td&gt;키 이름 바꾸면 모두 찾아서 변경해야 함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이런 문제들은 기능을 빠르게 추가할 때는 눈에 띄지 않지만, 코드가 쌓이면 새로운 기능을 추가하거나 버그를 수정하는 데 시간이 점점 더 오래 걸리게 만듭니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ai와-함께-코드를-읽고-구조를-개선하는-방법&quot;&gt;AI와 함께 코드를 읽고 구조를 개선하는 방법&lt;/h2&gt;
&lt;p&gt;리팩터링을 직접 하려면 코드를 이해하고 있어야 합니다. 바이브코딩으로 만든 코드는 AI가 만들었기 때문에 정확히 무엇이 어디에 있는지 파악하기 어려울 수 있습니다.&lt;/p&gt;
&lt;p&gt;이때도 AI를 활용합니다. 리팩터링 요청을 위한 좋은 프롬프트 방식입니다.&lt;/p&gt;
&lt;h3 id=&quot;1단계-현재-코드-분석-요청&quot;&gt;1단계: 현재 코드 분석 요청&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;현재 bookmark-app 프로젝트의 코드를 읽고, 아래 항목을 파악해줘:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;1. 각 파일이 어떤 역할을 하는가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;2. 한 파일이 너무 많은 역할을 하고 있는 부분은 어디인가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;3. 중복된 로직이 있는 부분은 어디인가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;4. 개선하면 좋을 부분 상위 3가지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;수정은 아직 하지 말고, 분석만 해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;분석 먼저 요청하는 것이 중요합니다. 바로 “고쳐줘”라고 하면 AI가 과도하게 많은 것을 한 번에 바꿀 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;2단계-우선순위-정하기&quot;&gt;2단계: 우선순위 정하기&lt;/h3&gt;
&lt;p&gt;AI가 분석 결과를 알려주면 어떤 것부터 정리할지 순서를 정합니다. 모든 것을 한 번에 고치려 하지 않습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;위 분석에서 3번 항목(localStorage 로직 분리)부터 처리해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;현재 App.jsx에 있는 localStorage 관련 코드를 storage.js 파일로 분리해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;기능은 그대로 유지하고 구조만 바꿔줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3단계-변경-후-작동-확인&quot;&gt;3단계: 변경 후 작동 확인&lt;/h3&gt;
&lt;p&gt;코드를 바꾼 후에는 반드시 브라우저에서 기능이 그대로 작동하는지 확인합니다. 리팩터링은 기능을 바꾸지 않는 것이 원칙이지만, 실수가 생길 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;4단계-다음-항목으로&quot;&gt;4단계: 다음 항목으로&lt;/h3&gt;
&lt;p&gt;확인이 끝나면 다음 항목으로 넘어갑니다. 한 번에 하나씩입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;리팩터링할-때-자주-쓰는-프롬프트-패턴&quot;&gt;리팩터링할 때 자주 쓰는 프롬프트 패턴&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;컴포넌트 분리&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;App.jsx에서 북마크 목록을 보여주는 부분을 BookmarkList.jsx 컴포넌트로 분리해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;props와 콜백 함수 연결도 함께 처리해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;공통 로직 추출&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;fetchBookmarks(), saveBookmark(), deleteBookmark() 함수가 각각 다른 파일에 흩어져 있어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;이것들을 hooks/useBookmarks.js 커스텀 훅으로 묶어줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;상수 정리&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;코드에 문자열로 하드코딩된 값들(localStorage 키 이름 등)을 &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;constants.js 파일로 모아줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;불필요한 코드 정리&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;주석 처리된 코드, 사용하지 않는 import, 미완성된 함수들을 정리해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;기능에 영향 없이 제거할 수 있는 것들만 처리해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;리팩터링-결과를-claudemd에-반영하기&quot;&gt;리팩터링 결과를 CLAUDE.md에 반영하기&lt;/h2&gt;
&lt;p&gt;리팩터링은 새 기능을 추가하는 것이 아니라 구조를 바꾸는 작업이므로, 구조를 설명해둔 &lt;code&gt;CLAUDE.md&lt;/code&gt;도 바뀐 내용에 맞게 갱신해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;리팩터링이 완료됐어. CLAUDE.md의 구조 설명을 아래에 맞게 갱신해줘:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- storage.js 새로 추가 (localStorage 로직 담당)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- hooks/useBookmarks.js 새로 추가 (북마크 CRUD 로직)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- App.jsx는 이제 UI 레이아웃만 담당&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- loadData() 함수는 삭제됨&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;문서가 코드와 동기화되어 있으면 나중에 AI에게 “지금 구조가 어떻게 되어 있어?”라고 물었을 때 정확한 현재 상태를 바로 파악할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;언제-리팩터링을-멈춰야-하는가&quot;&gt;언제 리팩터링을 멈춰야 하는가&lt;/h2&gt;
&lt;p&gt;리팩터링에는 끝이 없습니다. 코드는 항상 더 개선할 수 있습니다. 하지만 서비스를 운영하면서 리팩터링에만 시간을 쏟을 수는 없습니다.&lt;/p&gt;
&lt;p&gt;리팩터링을 멈추고 다음 기능으로 넘어가도 되는 신호는 이렇습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI에게 새 기능을 요청했을 때 기존 코드와 충돌 없이 잘 추가된다&lt;/li&gt;
&lt;li&gt;특정 기능을 수정할 때 어떤 파일을 열어야 하는지 바로 알 수 있다&lt;/li&gt;
&lt;li&gt;코드 파일 하나의 길이가 대략 200줄 이하다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;완벽하게 정리된 코드가 목표가 아닙니다. &lt;strong&gt;다음 기능을 추가하고 버그를 수정하기에 불편하지 않은 상태&lt;/strong&gt;가 목표입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;다음-편에서&quot;&gt;다음 편에서&lt;/h2&gt;
&lt;p&gt;다음 편에서는 배포 후 반드시 마주치게 되는 상황인 프로덕션 버그를 다룹니다. 실제 사용자가 쓰는 환경에서 발생하는 버그는 로컬 개발 환경과 다른 점이 있습니다. AI와 함께 원인을 찾고 해결하는 방법을 알아봅니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>리팩터링</category><category>바이브코딩</category><category>Claude Code</category></item><item><title>useRef — 화면을 건드리지 않고 값을 기억하기</title><link>https://blog.bepuljang.co.kr/react/07/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/07/</guid><description>State와 달리 바뀌어도 리렌더를 일으키지 않는 useRef를 정리합니다. 일반 변수·전역 let과 무엇이 다른지, 왜 렌더링 중엔 읽고 쓰면 안 되는지, 그리고 DOM에 손대는 대표 쓰임까지 다룹니다.</description><pubDate>Fri, 10 Jul 2026 06:41:13 GMT</pubDate><content:encoded>&lt;p&gt;지난 글까지 다룬 State는 “바뀌면 화면을 다시 그리는” 값이었습니다. 그런데 정반대의 요구가 있을 수 있습니다. 값은 &lt;strong&gt;렌더링을 넘어 기억하고 싶지만, 그 값이 바뀌어도 화면은 다시 그리고 싶지 않은&lt;/strong&gt; 경우죠. 이럴 때 쓰는 것이 &lt;strong&gt;useRef&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;예를 들어 “지난번 스크롤 위치”, “몇 번째 렌더인지 세는 카운터”, “타이머의 ID” 같은 값들은 기억은 해야 하지만 화면에 직접 나타나진 않습니다. 이런 것을 State로 두면 바뀔 때마다 불필요하게 화면을 다시 그리게 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;useref--렌더링에-영향-없는-기억-상자&quot;&gt;useRef — 렌더링에 영향 없는 기억 상자&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { useRef } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useRef&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(initialValue);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;useRef&lt;/code&gt;는 &lt;code&gt;{ current: 초기값 }&lt;/code&gt; 형태의 객체를 돌려줍니다. 값은 &lt;code&gt;ref.current&lt;/code&gt;로 읽고 쓰며, 이 상자는 두 가지 성질을 가집니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;바꿔도 리렌더가 일어나지 않는다&lt;/strong&gt; (State와의 결정적 차이)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;리렌더가 일어나도 값이 유지된다&lt;/strong&gt; (일반 지역 변수와의 차이)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;State와 나란히 두면 성격이 선명합니다.&lt;/p&gt;























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;바꾸면 리렌더?&lt;/th&gt;&lt;th&gt;리렌더 넘어 유지?&lt;/th&gt;&lt;th&gt;용도&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;State&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;✅ 한다&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;화면에 반영돼야 하는 값&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;useRef&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;❌ 안 한다&lt;/td&gt;&lt;td&gt;✅&lt;/td&gt;&lt;td&gt;기억하되 화면과 무관한 값&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;그냥-변수나-전역-let이면-안-될까&quot;&gt;그냥 변수나 전역 &lt;code&gt;let&lt;/code&gt;이면 안 될까&lt;/h2&gt;
&lt;p&gt;“화면을 안 건드리는 기억 값이면, 컴포넌트 밖에 &lt;code&gt;let&lt;/code&gt;으로 하나 두면 되지 않나?” 하는 생각이 듭니다. 실제로 그렇게 해도 ‘리렌더 안 하는 유지되는 값’은 만들 수 있습니다. 하지만 결정적 문제가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모듈 바깥의 &lt;code&gt;let&lt;/code&gt;은 그 컴포넌트의 모든 인스턴스가 공유합니다.&lt;/strong&gt; 같은 컴포넌트를 화면에 세 개 띄우면, 세 개가 하나의 변수를 나눠 쓰게 되어 서로의 값을 덮어써 버립니다. 반면 &lt;code&gt;useRef&lt;/code&gt;는 &lt;strong&gt;각 컴포넌트 인스턴스마다 자기만의 독립된 상자&lt;/strong&gt;를 갖습니다. 세 개를 띄우면 상자도 세 개, 서로 간섭하지 않죠.&lt;/p&gt;
&lt;p&gt;컴포넌트 &lt;strong&gt;안의&lt;/strong&gt; 지역 변수는 반대 문제입니다. 인스턴스마다 독립적이긴 하지만, 앞서 봤듯 렌더링 때마다 다시 실행돼 &lt;strong&gt;매번 초기화&lt;/strong&gt;됩니다. useRef는 “인스턴스마다 독립적이면서, 렌더링을 넘어 유지되는” 두 성질을 동시에 만족시키는 유일한 자리입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;렌더링-중에는-읽지도-쓰지도-말-것&quot;&gt;렌더링 중에는 읽지도, 쓰지도 말 것&lt;/h2&gt;
&lt;p&gt;useRef에는 중요한 규칙이 하나 있습니다. &lt;strong&gt;렌더링 도중에 &lt;code&gt;ref.current&lt;/code&gt;를 읽거나 쓰지 마세요.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  myRef.current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 123&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 🚩 렌더 중 쓰기 금지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{myRef.current}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 🚩 렌더 중 읽기 금지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5편에서 렌더링은 &lt;strong&gt;순수&lt;/strong&gt;해야 한다고 했습니다. 그런데 ref는 바뀌어도 React에 알리지 않는 값이라, 렌더 도중에 이걸 읽거나 쓰면 “언제 바뀐 건지 알 수 없는 값”에 화면이 의존하게 되어 예측 불가능해집니다. 대신 ref는 &lt;strong&gt;이벤트 핸들러나 이펙트 안에서&lt;/strong&gt; 다뤄야 합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    myRef.current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 123&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✅ 이펙트 안에서는 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; handleClick&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    doSomething&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(myRef.current);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✅ 이벤트 핸들러 안에서는 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;렌더링이 끝난 뒤, 특정 사건이 벌어졌을 때 한 번씩 만지는 것 — 그게 ref의 올바른 사용 리듬입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;가장-흔한-쓰임--dom-요소에-손대기&quot;&gt;가장 흔한 쓰임 — DOM 요소에 손대기&lt;/h2&gt;
&lt;p&gt;사실 실무에서 useRef를 가장 많이 만나는 곳은 따로 있습니다. 바로 &lt;strong&gt;특정 DOM 요소를 직접 가리켜야 할 때&lt;/strong&gt;입니다. 입력창에 자동으로 포커스를 주거나, 요소의 크기를 재거나, 스크롤을 옮기는 일들이죠.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SearchBox&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; inputRef&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useRef&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    inputRef.current.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;focus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 마운트되면 입력창에 자동 포커스&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }, []);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;input&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ref&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{inputRef} /&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JSX 요소에 &lt;code&gt;ref={inputRef}&lt;/code&gt;를 달아 두면, 렌더 후 React가 그 실제 DOM 노드를 &lt;code&gt;inputRef.current&lt;/code&gt;에 넣어 줍니다. 선언형으로 화면을 그리다가도, 이렇게 &lt;strong&gt;명령형으로 요소를 직접 다뤄야 하는 순간&lt;/strong&gt;을 위한 공식 탈출구가 useRef인 셈입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;state냐-ref냐&quot;&gt;State냐 Ref냐&lt;/h2&gt;
&lt;p&gt;마지막으로 판단 기준 하나. &lt;strong&gt;그 값이 화면에 보여야 하면 State, 화면과 무관하게 그저 기억만 하면 되면 Ref&lt;/strong&gt;입니다. 둘을 혼동해 “화면에 보여야 할 값을 ref에 넣어” 화면이 갱신되지 않거나, 반대로 “화면과 무관한 값을 state에 넣어” 불필요한 리렌더를 유발하는 것이 흔한 실수입니다.&lt;/p&gt;
&lt;p&gt;이렇게 컴포넌트 하나가 스스로 다루는 값들(State·Ref)까지 왔습니다. 다음 글에서는 시야를 넓혀, &lt;strong&gt;멀리 떨어진 컴포넌트끼리 값을 나눠 갖는&lt;/strong&gt; 방법 — Props를 한 단계 넘어서는 &lt;strong&gt;Context&lt;/strong&gt;를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>useRef</category><category>훅</category><category>DOM</category></item><item><title>useEffect 정리 함수(cleanup) — 켠 것을 끄는 대칭의 기술</title><link>https://blog.bepuljang.co.kr/react/06/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/06/</guid><description>useEffect의 정리 함수가 언제, 왜 실행되는지 생명주기로 정리합니다. 흔히 오해하는 &apos;개발 모드 이중 실행&apos;의 진짜 이유(StrictMode)까지 명확히 짚습니다.</description><pubDate>Fri, 10 Jul 2026 06:39:07 GMT</pubDate><content:encoded>&lt;p&gt;지난 글에서 “타이머를 켜거나 서버에 연결했다면, 컴포넌트가 사라질 때 꺼 줘야 한다”고 했습니다. 그 &lt;strong&gt;끄는 일&lt;/strong&gt;을 담당하는 것이 정리 함수(cleanup)입니다. 개념 자체는 단순한데, 실행 시점이 헷갈려서 useEffect에서 가장 많은 혼란이 생기는 지점이기도 합니다. 오늘 그 타이밍을 확실히 잡아 보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정리-함수란&quot;&gt;정리 함수란&lt;/h2&gt;
&lt;p&gt;정리 함수는 &lt;strong&gt;설정 함수가 반환하는 함수&lt;/strong&gt;입니다. 문법은 이게 전부입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; connection&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; createConnection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(roomId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  connection.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 설정: 연결한다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;disconnect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 정리: 연결을 끊는다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, [roomId]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;return&lt;/code&gt; 뒤의 함수가 정리 함수입니다. 이름 그대로 설정 함수가 벌여 놓은 일(연결·구독·타이머 등)을 &lt;strong&gt;되돌리는&lt;/strong&gt; 역할을 합니다. 핵심 감각은 “정리 함수는 설정 함수의 &lt;strong&gt;짝&lt;/strong&gt;”이라는 것입니다. 설정에서 켰으면 정리에서 끄고, 설정에서 구독했으면 정리에서 구독을 해지합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;언제-실행되나--세-가지-시점&quot;&gt;언제 실행되나 — 세 가지 시점&lt;/h2&gt;
&lt;p&gt;React는 필요할 때마다 설정과 정리를 부르는데, 정리하면 세 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;마운트&lt;/strong&gt;(컴포넌트가 처음 화면에 등장): 설정 함수 실행&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의존성이 바뀌어 다시 실행될 때&lt;/strong&gt;: 먼저 &lt;strong&gt;옛 값으로 정리 함수&lt;/strong&gt;를 실행하고, 그다음 &lt;strong&gt;새 값으로 설정 함수&lt;/strong&gt;를 실행&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;언마운트&lt;/strong&gt;(컴포넌트가 화면에서 사라짐): 정리 함수를 마지막으로 한 번 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2번이 특히 중요합니다. 위 예시에서 &lt;code&gt;roomId&lt;/code&gt;가 &lt;code&gt;1번방&lt;/code&gt;에서 &lt;code&gt;2번방&lt;/code&gt;으로 바뀌면, React는 &lt;strong&gt;“1번방 연결을 끊고 → 2번방에 연결”&lt;/strong&gt;하는 순서로 동작합니다. 새로 연결하기 &lt;strong&gt;전에&lt;/strong&gt; 옛 연결을 정리하기 때문에, 방을 옮길 때 이전 연결이 그대로 남아 중복되는 사고가 생기지 않습니다.&lt;/p&gt;
&lt;p&gt;즉 정리 함수는 “컴포넌트가 죽을 때만” 도는 게 아니라, &lt;strong&gt;설정이 다시 실행되기 직전마다&lt;/strong&gt; 옛 것을 되돌리기 위해 함께 돕니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;개발-모드에서-두-번-실행되는-이유&quot;&gt;개발 모드에서 두 번 실행되는 이유&lt;/h2&gt;
&lt;p&gt;여기서 많은 사람이 크게 헷갈립니다. 개발 환경에서 이펙트를 만들면, 마운트 시 설정이 &lt;strong&gt;두 번&lt;/strong&gt; 불리는 것처럼 보입니다(설정 → 정리 → 설정). 로그를 찍어 보면 초기화가 두 번 도는 것 같아 당황하게 되죠.&lt;/p&gt;
&lt;p&gt;이건 버그도, JavaScript 비동기 동작 탓도 &lt;strong&gt;아닙니다.&lt;/strong&gt; React의 &lt;strong&gt;StrictMode&lt;/strong&gt;가 개발 모드에서만 &lt;strong&gt;일부러&lt;/strong&gt; 설정→정리→설정을 한 번 더 돌리는 것입니다. 목적은 하나, &lt;strong&gt;정리 함수가 빠졌거나 잘못된 이펙트를 조기에 드러내려는 스트레스 테스트&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;논리는 이렇습니다. 정리 함수가 설정 함수를 완벽히 되돌린다면, “설정을 한 번 부른 것(프로덕션)“과 “설정→정리→설정(개발)“은 사용자 입장에서 &lt;strong&gt;구별되지 않아야&lt;/strong&gt; 합니다. 만약 이중 실행 때문에 눈에 보이는 문제(중복 연결, 이벤트 두 번 등록 등)가 생긴다면, 그건 React가 알려 주는 신호입니다 — &lt;strong&gt;당신의 정리 함수에 빠진 로직이 있다&lt;/strong&gt;고요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그러니 개발 모드의 이중 실행은 없애야 할 대상이 아니라, 정리 로직이 온전한지 &lt;strong&gt;검증받는 기회&lt;/strong&gt;입니다. 프로덕션 빌드에서는 이중 실행이 사라지고 설정은 한 번만 돕니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;그래서-정리-함수를-이렇게-보면-쉽다&quot;&gt;그래서 정리 함수를 이렇게 보면 쉽다&lt;/h2&gt;
&lt;p&gt;정리 함수를 “가끔 필요한 마무리 청소” 정도로 보면 타이밍이 계속 헷갈립니다. 대신 이렇게 보세요. &lt;strong&gt;모든 설정 함수는 자신을 되돌리는 정리 함수와 한 쌍이어야 한다.&lt;/strong&gt; 연결했으면 끊고, 구독했으면 해지하고, 타이머를 걸었으면 해제한다 — 이 대칭만 지키면, React가 그 짝을 언제 실행하든(재실행 전이든 언마운트든, 개발 모드의 이중 실행이든) 항상 올바르게 동작합니다.&lt;/p&gt;
&lt;p&gt;이렇게 State와 Effect까지 왔습니다. 다음 글에서는 상태와는 또 다른 성격의 값 — 바뀌어도 화면을 다시 그리지 않으면서, 렌더링을 넘어 값을 기억하는 &lt;strong&gt;useRef&lt;/strong&gt;를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>useEffect</category><category>cleanup</category><category>StrictMode</category></item><item><title>useEffect — 렌더링 바깥의 일을 다루기</title><link>https://blog.bepuljang.co.kr/react/05/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/05/</guid><description>React의 useEffect를 &apos;사이드 이펙트&apos;라는 개념부터 짚습니다. 렌더링과 무엇이 다른지, 의존성 배열의 세 가지 형태가 각각 언제 실행되는지, 그리고 흔한 오해까지 정리합니다.</description><pubDate>Fri, 10 Jul 2026 06:36:13 GMT</pubDate><content:encoded>&lt;p&gt;지난 글 끝에서 이런 질문을 남겼습니다. 상태가 바뀔 때 &lt;strong&gt;화면을 그리는 것 말고 다른 일&lt;/strong&gt;을 하고 싶다면? 검색어가 바뀔 때마다 서버에 요청을 보낸다든지 말입니다. 그 ‘화면 밖의 일’을 다루는 훅이 &lt;strong&gt;useEffect&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;useState가 “상태를 바꿔 화면을 갱신”하는 쪽이라면, useEffect는 반대로 “상태나 렌더링에 맞춰 &lt;strong&gt;어떤 동작을 수행&lt;/strong&gt;”하는 쪽입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;사이드-이펙트란&quot;&gt;사이드 이펙트란&lt;/h2&gt;
&lt;p&gt;1편에서 컴포넌트는 “상태를 받아 화면을 반환하는 함수”라고 했습니다. 이 반환, 즉 렌더링은 &lt;strong&gt;순수&lt;/strong&gt;해야 합니다. 같은 입력이면 같은 화면을 내놓고, 그 과정에서 바깥 세계를 건드리지 않아야 예측 가능하니까요.&lt;/p&gt;
&lt;p&gt;하지만 실제 앱은 바깥 세계와 끊임없이 얽힙니다. 서버에서 데이터를 가져오고, 타이머를 켜고, 브라우저 이벤트를 구독하고, 로그를 남깁니다. 이렇게 &lt;strong&gt;렌더링의 순수한 계산 바깥에서 벌어지는 일&lt;/strong&gt;을 사이드 이펙트(side effect)라고 부릅니다. useEffect는 이런 일들을 렌더링 흐름에서 떼어내, &lt;strong&gt;화면이 그려진 뒤에&lt;/strong&gt; 안전하게 실행해 주는 도구입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { useEffect } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기본-문법&quot;&gt;기본 문법&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // 여기서 사이드 이펙트를 수행&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, [의존성]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;인자는 두 개입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;첫 번째: &lt;strong&gt;실행할 함수&lt;/strong&gt;(설정 함수)&lt;/li&gt;
&lt;li&gt;두 번째: &lt;strong&gt;의존성 배열&lt;/strong&gt; — 이 이펙트가 언제 다시 실행될지를 결정하는 값들의 목록&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;핵심은 이겁니다. 이펙트는 렌더링 &lt;strong&gt;도중&lt;/strong&gt;이 아니라 화면이 그려진 &lt;strong&gt;직후&lt;/strong&gt;에 실행됩니다. 그리고 매번이 아니라, &lt;strong&gt;의존성 배열의 값이 바뀌었을 때만&lt;/strong&gt; 다시 실행됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;의존성-배열이-전부다&quot;&gt;의존성 배열이 전부다&lt;/h2&gt;
&lt;p&gt;useEffect의 동작은 결국 두 번째 인자를 어떻게 두느냐로 갈립니다. 세 가지 경우가 있습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1) [값] — 첫 렌더 후 1회 + 그 값이 바뀔 때마다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;count가 바뀜:&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, count);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, [count]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 2) [] — 첫 렌더 후 딱 1회 (초기화용)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;컴포넌트가 처음 등장&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, []);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3) 배열 생략 — 렌더될 때마다 매번&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;무언가 렌더됨&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;두 번째 인자&lt;/th&gt;&lt;th&gt;실행 시점&lt;/th&gt;&lt;th&gt;주 용도&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;[a, b]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;첫 렌더 후 + &lt;code&gt;a&lt;/code&gt;나 &lt;code&gt;b&lt;/code&gt;가 바뀔 때&lt;/td&gt;&lt;td&gt;특정 값 변화에 반응&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;첫 렌더 후 1회&lt;/td&gt;&lt;td&gt;초기 설정(구독·최초 로드)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;(없음)&lt;/td&gt;&lt;td&gt;매 렌더마다&lt;/td&gt;&lt;td&gt;거의 안 씀&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;한 가지 자주 헷갈리는 점. &lt;strong&gt;의존성 배열이 있든 없든, 이펙트는 첫 렌더 직후 최소 한 번은 실행됩니다.&lt;/strong&gt; &lt;code&gt;[count]&lt;/code&gt;라고 적었다고 “count가 바뀔 때만” 도는 게 아니라, “처음 한 번 + 이후 count가 바뀔 때”입니다. 초기 1회 실행이 필요 없다면 이펙트 안에서 조건으로 걸러 줘야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;흔한-오해-아무-데나-쓰지-않는다&quot;&gt;흔한 오해: 아무 데나 쓰지 않는다&lt;/h2&gt;
&lt;p&gt;useEffect는 강력해서 초보일수록 남용하기 쉽습니다. 하지만 다음 두 가지는 &lt;strong&gt;useEffect가 필요 없는&lt;/strong&gt; 대표적인 경우입니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;다른 상태로부터 계산되는 값&lt;/strong&gt;: 예를 들어 &lt;code&gt;firstName&lt;/code&gt;, &lt;code&gt;lastName&lt;/code&gt;으로 &lt;code&gt;fullName&lt;/code&gt;을 만든다면, 이펙트로 상태를 또 만들 필요 없이 렌더 중에 그냥 계산하면 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사용자 이벤트에 대한 반응&lt;/strong&gt;: 버튼 클릭에 반응하는 건 이펙트가 아니라 &lt;code&gt;onClick&lt;/code&gt; 같은 &lt;strong&gt;이벤트 핸들러&lt;/strong&gt;의 몫입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;useEffect는 “렌더링만으로는 할 수 없는, &lt;strong&gt;바깥 세계와의 동기화&lt;/strong&gt;”가 필요할 때 꺼내는 도구라고 기억해 두면 남용을 피할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;시작이-있으면-정리도-필요하다&quot;&gt;시작이 있으면 정리도 필요하다&lt;/h2&gt;
&lt;p&gt;useEffect로 타이머를 켜거나 서버에 연결했다면, 컴포넌트가 사라질 때 그것들을 &lt;strong&gt;꺼 주는&lt;/strong&gt; 뒷정리가 필요합니다. 켜기만 하고 끄지 않으면 메모리 누수나 중복 연결 같은 문제가 생기니까요.&lt;/p&gt;
&lt;p&gt;useEffect는 이를 위해, 설정 함수가 &lt;strong&gt;또 다른 함수를 반환&lt;/strong&gt;하도록 해서 ‘정리(cleanup)’ 단계를 붙일 수 있게 해 두었습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;useEffect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setInterval&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tick, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 설정: 타이머 켜기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; clearInterval&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id);      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 정리: 타이머 끄기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}, []);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 정리 함수가 정확히 언제, 왜 실행되는지는 처음엔 꽤 헷갈리는 부분입니다. 그래서 다음 글에서 &lt;strong&gt;useEffect의 정리 함수&lt;/strong&gt;만 따로 떼어 자세히 다루겠습니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>useEffect</category><category>사이드 이펙트</category><category>훅</category></item><item><title>State와 useState — 컴포넌트가 스스로 기억하는 값</title><link>https://blog.bepuljang.co.kr/react/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/04/</guid><description>React의 State를 Props와 대비해 정리합니다. 일반 변수로는 왜 안 되는지, useState를 왜 const로 받는지, 값을 반드시 setter로 바꿔야 하는 이유까지 짚습니다.</description><pubDate>Fri, 10 Jul 2026 01:37:31 GMT</pubDate><content:encoded>&lt;p&gt;지난 글에서 Props는 &lt;strong&gt;바깥(부모)에서 받아 바꿀 수 없는&lt;/strong&gt; 값이라고 했습니다. 그러면서 자연스러운 질문을 하나 남겼죠. 컴포넌트가 &lt;strong&gt;스스로 들고 있으면서 시간에 따라 바뀌는&lt;/strong&gt; 값은 어떻게 다룰까? 그 답이 오늘의 주제, &lt;strong&gt;State(상태)&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;버튼을 누를 때마다 올라가는 카운터, 입력창에 타이핑되는 글자, 열리고 닫히는 메뉴 — 이렇게 사용자와 상호작용하며 변하는 값이 전부 State입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;왜-일반-변수로는-안-될까&quot;&gt;왜 일반 변수로는 안 될까&lt;/h2&gt;
&lt;p&gt;“값이 바뀌는 거면 그냥 변수 쓰면 되지 않나?” 싶습니다. 그런데 컴포넌트 안에서 평범한 변수로는 두 가지가 안 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Counter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }}&gt;{count}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 버튼을 눌러도 화면의 숫자는 &lt;strong&gt;0에서 꿈쩍도 하지 않습니다.&lt;/strong&gt; 이유는 두 가지입니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;바뀌어도 화면이 다시 그려지지 않는다.&lt;/strong&gt; 1편에서 React는 “상태가 바뀌면 화면을 다시 그린다”고 했는데, 평범한 변수는 React가 지켜보지 않아서 바뀐 걸 모릅니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;다시 그려지면 값이 초기화된다.&lt;/strong&gt; 설령 어떻게 다시 그려진들, 컴포넌트 함수가 처음부터 다시 실행되면서 &lt;code&gt;let count = 0&lt;/code&gt;도 다시 실행돼 0으로 돌아갑니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;즉 컴포넌트에는 “&lt;strong&gt;리렌더링을 넘어 값을 기억하고&lt;/strong&gt;, 그 값이 &lt;strong&gt;바뀌면 화면도 다시 그리는&lt;/strong&gt;” 특별한 변수가 필요합니다. 그게 State이고, 이를 만드는 도구가 &lt;strong&gt;useState&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;usestate-사용법&quot;&gt;useState 사용법&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { useState } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Counter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)}&gt;{count}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;useState&lt;/code&gt;는 초기값을 인자로 받아 &lt;strong&gt;길이 2짜리 배열&lt;/strong&gt;을 돌려줍니다. 이걸 구조 분해로 받는데,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;첫 번째(&lt;code&gt;count&lt;/code&gt;): 현재 상태 값&lt;/li&gt;
&lt;li&gt;두 번째(&lt;code&gt;setCount&lt;/code&gt;): 그 값을 바꾸는 전용 함수(setter)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이름은 자유지만 관례상 &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;setX&lt;/code&gt; 형태로 짝지어 씁니다. 이제 버튼을 누르면 &lt;code&gt;setCount&lt;/code&gt;가 상태를 바꾸고, 그에 따라 컴포넌트가 다시 그려지면서 새 숫자가 화면에 나타납니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;use&lt;/code&gt;로 시작하는 이런 특수 함수들을 &lt;strong&gt;훅(Hook)&lt;/strong&gt;이라고 부릅니다. State, 사이드 이펙트 등 React의 기능에 함수 컴포넌트가 ‘갈고리를 걸어’ 쓰는 것이라고 이해하면 됩니다. 이 시리즈의 상당 부분이 이 훅들에 대한 이야기입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;왜-let이-아니라-const로-받을까&quot;&gt;왜 &lt;code&gt;let&lt;/code&gt;이 아니라 &lt;code&gt;const&lt;/code&gt;로 받을까&lt;/h2&gt;
&lt;p&gt;값이 바뀌는데 &lt;code&gt;const&lt;/code&gt;로 받는 게 이상해 보입니다. “바뀔 값이니 &lt;code&gt;let&lt;/code&gt;이어야 하지 않나?” 하지만 여기엔 React의 렌더링 방식에 대한 오해가 숨어 있습니다.&lt;/p&gt;
&lt;p&gt;핵심은 이것입니다. &lt;strong&gt;&lt;code&gt;count&lt;/code&gt;는 “한 번의 렌더링” 안에서는 절대 바뀌지 않습니다.&lt;/strong&gt; 상태가 바뀐다는 건, 그 값을 그 자리에서 고치는 게 아니라, &lt;strong&gt;컴포넌트 함수를 처음부터 새로 실행&lt;/strong&gt;한다는 뜻입니다. 그 새 실행에서 &lt;code&gt;useState&lt;/code&gt;가 이번엔 갱신된 값을 돌려주고, &lt;code&gt;const count&lt;/code&gt;는 그 새 값으로 &lt;strong&gt;새로 바인딩&lt;/strong&gt;됩니다.&lt;/p&gt;
&lt;p&gt;그러니까 흐름은 “하나의 &lt;code&gt;count&lt;/code&gt;를 계속 고쳐 쓴다”가 아니라, “렌더링마다 그 순간의 &lt;code&gt;count&lt;/code&gt;가 새로 만들어진다”입니다. 각 렌더링 안에서 &lt;code&gt;count&lt;/code&gt;는 고정된 스냅샷이므로 &lt;code&gt;const&lt;/code&gt;가 정확한 표현입니다. 오히려 &lt;code&gt;let&lt;/code&gt;으로 두고 직접 &lt;code&gt;count = ...&lt;/code&gt;처럼 고치면, React는 그 변경을 전혀 알지 못한 채 다음 렌더링에서 덮어써 버려 혼란만 생깁니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;값은-반드시-setter로-바꾼다&quot;&gt;값은 반드시 setter로 바꾼다&lt;/h2&gt;
&lt;p&gt;방금 이야기에서 가장 중요한 실전 규칙이 나옵니다. &lt;strong&gt;상태는 절대 직접 고치지 말고, 언제나 setter로 바꿉니다.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ React가 모른다 → 화면 안 바뀜&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✅ 상태 변경 + 리렌더링 예약&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;setCount&lt;/code&gt;는 단순히 값만 바꾸는 게 아니라 “이 컴포넌트를 다시 그려라”라고 React에 &lt;strong&gt;예약을 겁니다.&lt;/strong&gt; 이 한 줄이 값 변경과 화면 갱신을 하나로 묶어 주는, State의 존재 이유 그 자체입니다.&lt;/p&gt;
&lt;p&gt;객체나 배열 상태도 마찬가지입니다. 안을 직접 수정(&lt;code&gt;user.name = ...&lt;/code&gt;)하지 말고, &lt;strong&gt;새 객체를 만들어&lt;/strong&gt; setter에 넘깁니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setUser&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;user, name: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;새 이름&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;이전-값을-기반으로-바꿀-땐-함수로&quot;&gt;이전 값을 기반으로 바꿀 땐 함수로&lt;/h2&gt;
&lt;p&gt;한 가지 실전 팁. 이전 상태를 토대로 다음 값을 정할 때는, 값 대신 &lt;strong&gt;함수&lt;/strong&gt;를 넘기는 편이 안전합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;prev&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; prev &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;setCount&lt;/code&gt;에 함수를 넣으면 React가 &lt;strong&gt;가장 최신 상태&lt;/strong&gt;를 &lt;code&gt;prev&lt;/code&gt;로 넣어 줍니다. 버튼을 빠르게 여러 번 눌러 상태 변경이 몰릴 때도 값이 꼬이지 않아, “왜 한 번밖에 안 오르지?” 같은 버그를 예방할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;정리하면, State는 &lt;strong&gt;리렌더링을 넘어 유지되고, 바뀌면 화면을 다시 그리는&lt;/strong&gt; 값이며, 그 변경은 언제나 setter를 통합니다. 이제 “상태가 바뀌면 화면이 다시 그려진다”는 흐름이 손에 잡혔을 겁니다.&lt;/p&gt;
&lt;p&gt;그런데 상태가 바뀔 때 &lt;strong&gt;화면을 그리는 것 말고 다른 일&lt;/strong&gt;을 하고 싶다면 어떻게 할까요? 예를 들어 검색어(상태)가 바뀔 때마다 서버에 요청을 보내야 한다면요. 그 ‘화면 밖의 일’을 다루는 도구가 다음 글의 &lt;strong&gt;useEffect&lt;/strong&gt;입니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>State</category><category>useState</category><category>훅</category></item><item><title>Props — 부모가 자식에게 건네는 속성</title><link>https://blog.bepuljang.co.kr/react/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/03/</guid><description>React의 Props를 웹의 속성(attribute)에 빗대어 정리합니다. 함수 인자처럼 동작하는 원리, 구조 분해, children, 그리고 &apos;Props는 읽기 전용&apos;이라는 규칙이 왜 존재하는지까지 짚습니다.</description><pubDate>Fri, 10 Jul 2026 01:34:20 GMT</pubDate><content:encoded>&lt;p&gt;지난 글 끝에서 “컴포넌트를 조합할 때 부모가 자식에게 값을 건네는 방법”을 예고했습니다. 그게 바로 &lt;strong&gt;Props&lt;/strong&gt;입니다. 사실 쉬워 보이는데 막상 뭔가 만들다 보면 의도대로 동작하지 않아 당황하게 만드는 대표 주자이기도 한데, 그 헷갈림의 대부분은 Props의 정체를 살짝 오해하는 데서 옵니다. 오늘 그 정체를 분명히 해두겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;props는-컴포넌트의-속성이다&quot;&gt;Props는 컴포넌트의 ‘속성’이다&lt;/h2&gt;
&lt;p&gt;Props는 &lt;strong&gt;Properties&lt;/strong&gt;, 즉 ‘속성’의 줄임말입니다. 이 이름이 전부라고 해도 과언이 아닙니다. 웹에서 우리는 이미 속성을 써 왔습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://...&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;링크&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 &lt;code&gt;href&lt;/code&gt;는 &lt;code&gt;a&lt;/code&gt; 요소의 속성입니다. 태그에 성질을 부여해 그 요소가 어떻게 생기고 행동할지를 정하죠. React에서는 이 &lt;strong&gt;엘리먼트 자리에 컴포넌트가 들어옵니다.&lt;/strong&gt; 그리고 컴포넌트는 함수이기 때문에, 속성은 그 &lt;strong&gt;함수의 인자처럼&lt;/strong&gt; 전달됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Welcome&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;props&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;안녕하세요, {props.name}님&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Welcome&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;사라&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;Welcome name=&quot;사라&quot; /&gt;&lt;/code&gt;라고 쓰면, &lt;code&gt;Welcome&lt;/code&gt; 함수는 &lt;code&gt;{ name: &quot;사라&quot; }&lt;/code&gt;라는 객체를 &lt;code&gt;props&lt;/code&gt;로 받습니다. 결과는 &lt;code&gt;&amp;#x3C;h1&gt;안녕하세요, 사라님&amp;#x3C;/h1&gt;&lt;/code&gt;이 되고요. 즉 &lt;strong&gt;JSX 속성으로 적은 것들이 하나의 객체로 묶여 컴포넌트 함수에 인자로 들어가는&lt;/strong&gt; 구조입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;실무에서는-구조-분해로-꺼내-쓴다&quot;&gt;실무에서는 구조 분해로 꺼내 쓴다&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;props.name&lt;/code&gt;, &lt;code&gt;props.age&lt;/code&gt;처럼 매번 &lt;code&gt;props.&lt;/code&gt;를 붙이는 게 번거로워서, 실제로는 &lt;strong&gt;구조 분해(destructuring)&lt;/strong&gt;로 필요한 것만 바로 꺼내 쓰는 경우가 훨씬 많습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Welcome&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{name}님, {age}살이시군요&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;동작은 완전히 같습니다. 인자로 들어온 &lt;code&gt;props&lt;/code&gt; 객체를 함수 머리에서 곧바로 풀어 헤친 것뿐입니다. 기본값도 이 자리에서 줄 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Welcome&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;손님&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{name}님, 환영합니다&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;props는-읽기-전용이다&quot;&gt;Props는 읽기 전용이다&lt;/h2&gt;
&lt;p&gt;가장 중요한 규칙 하나. &lt;strong&gt;자식은 전달받은 Props를 고칠 수 없습니다.&lt;/strong&gt; 읽기 전용(read-only)입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; MyComponent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;다른 이름&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 🚩 이렇게 하면 안 된다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{name}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;왜 이런 제약이 있을까요? ‘잉크’에 ‘검정색’이라는 속성을 주어 ‘검정 잉크’로 정의했다면, 그 잉크가 스스로 자기 색을 빨강으로 바꿀 수는 없는 것과 같습니다. 속성은 그 컴포넌트가 &lt;strong&gt;바깥(부모)으로부터 부여받은 정체성&lt;/strong&gt;입니다. 자식이 그걸 제멋대로 바꾼다면, 부모가 “너는 이런 모습이어야 해”라고 정해 준 약속이 깨지는 셈이죠.&lt;/p&gt;
&lt;p&gt;이 규칙은 React의 큰 원칙인 &lt;strong&gt;단방향 데이터 흐름&lt;/strong&gt;과 이어집니다. 데이터는 언제나 부모 → 자식, 위에서 아래로만 흐릅니다. 값이 한 방향으로만 흐르기 때문에, “이 값이 대체 어디서 바뀐 거지?”를 추적하기 쉬워지고, 지난 글들에서 말한 ‘예측 가능한 화면’이 가능해집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;children--태그-사이에-낀-것도-props다&quot;&gt;children — 태그 사이에 낀 것도 Props다&lt;/h2&gt;
&lt;p&gt;속성뿐 아니라, 컴포넌트 &lt;strong&gt;여는 태그와 닫는 태그 사이에 넣은 내용&lt;/strong&gt;도 Props로 전달됩니다. 이건 &lt;code&gt;children&lt;/code&gt;이라는 특별한 이름으로 들어옵니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Card&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({ &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;children&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;card&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{children}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Card&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;제목&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;본문&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Card&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Card&lt;/code&gt; 안의 &lt;code&gt;{children}&lt;/code&gt; 자리에 &lt;code&gt;&amp;#x3C;h2&gt;&lt;/code&gt;와 &lt;code&gt;&amp;#x3C;p&gt;&lt;/code&gt;가 그대로 들어갑니다. 덕분에 바깥 껍데기(카드, 모달, 레이아웃 등)와 그 안에 담길 내용을 깔끔하게 분리할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;props를-통신-수단이라-부르지-말자&quot;&gt;Props를 ‘통신 수단’이라 부르지 말자&lt;/h2&gt;
&lt;p&gt;정리하면서 관점 하나를 바로잡고 싶습니다. Props를 흔히 “부모가 자식에게 값을 전달하는 통신 방법”이라고 설명하는데, 틀린 말은 아니지만 순서가 뒤바뀌어 있습니다.&lt;/p&gt;
&lt;p&gt;Props의 본질은 어디까지나 &lt;strong&gt;자식 컴포넌트의 속성을 정의하는 것&lt;/strong&gt;입니다. 그 속성을 정의하는 값을 부모가 내려주다 보니, &lt;strong&gt;결과적으로&lt;/strong&gt; 하향식 데이터 전달에도 쓰이는 것이지요. “값을 나르는 도구”가 아니라 “자식이 어떤 모습이어야 하는지 부모가 적어 주는 명세”로 보면, 앞머리에서 말한 ‘의도대로 동작하지 않는’ 순간이 확 줄어듭니다. 읽기 전용인 이유도 이 관점에서 자연스럽고요.&lt;/p&gt;
&lt;p&gt;그런데 여기서 자연스러운 질문이 생깁니다. Props가 바깥에서 받아 &lt;strong&gt;바꿀 수 없는&lt;/strong&gt; 값이라면, 컴포넌트가 &lt;strong&gt;스스로 들고 있으면서 시간에 따라 바뀌는&lt;/strong&gt; 값은 어떻게 다룰까요? 다음 글의 주제, &lt;strong&gt;State&lt;/strong&gt;가 바로 그것입니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>Props</category><category>컴포넌트</category><category>단방향 데이터 흐름</category></item><item><title>JSX — HTML처럼 생겼지만 사실은 JavaScript</title><link>https://blog.bepuljang.co.kr/react/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/02/</guid><description>React가 화면을 적는 문법 JSX의 정체를 짚습니다. HTML과 닮았지만 왜 다른지, 중괄호로 무엇을 하는지, class 대신 className을 쓰는 이유까지 웹 경험에 빗대어 정리합니다.</description><pubDate>Fri, 10 Jul 2026 01:24:02 GMT</pubDate><content:encoded>&lt;p&gt;지난 글에서 컴포넌트는 “화면을 그리는 설계도를 반환하는 함수”라고 했습니다. 그런데 그 설계도, 즉 &lt;code&gt;return&lt;/code&gt; 뒤에 오는 HTML처럼 생긴 그것의 정체가 궁금했을 겁니다. 함수 안에 태그가 들어가 있는 모습은 처음 보면 분명 낯서니까요. 그 문법의 이름이 바로 &lt;strong&gt;JSX&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;JSX는 웹 경험이 있는 사람에게 양날의 검입니다. HTML과 닮아서 진입장벽을 낮춰주지만, 딱 그만큼 “HTML이겠거니” 하고 넘어갔다가 헷갈리게 만들기 때문입니다. 그래서 오늘은 JSX가 HTML과 무엇이 같고 무엇이 다른지를 정확히 갈라보겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;jsx는-html이-아니라-javascript다&quot;&gt;JSX는 HTML이 아니라 JavaScript다&lt;/h2&gt;
&lt;p&gt;JSX는 &lt;strong&gt;JavaScript XML&lt;/strong&gt;의 줄임말입니다. 이름에 XML이 붙어 마크업처럼 보이지만, 핵심은 앞의 &lt;strong&gt;JavaScript&lt;/strong&gt;에 있습니다. JSX는 별도의 마크업 언어가 아니라, &lt;strong&gt;JavaScript 안에 마크업을 쓸 수 있게 해주는 문법 확장&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; element&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;안녕하세요&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 한 줄은 브라우저가 그대로 이해하는 게 아닙니다. 빌드 과정에서 아래처럼 &lt;strong&gt;평범한 JavaScript 함수 호출로 변환&lt;/strong&gt;됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; element&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; React.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;h1&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;안녕하세요&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러니까 우리가 태그를 쓰는 건 사실 함수를 부르는 일이고, JSX는 그걸 보기 좋게 적도록 도와주는 껍데기인 셈입니다. “HTML을 JS에 붙였다”가 아니라 &lt;strong&gt;“JS가 마크업처럼 보이는 문법을 빌려왔다”&lt;/strong&gt;가 정확한 이해입니다. 이 점을 붙잡고 있으면 뒤에 나올 차이들이 전부 자연스럽게 설명됩니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;참고로 React 17부터는 이 변환 방식이 바뀌어, JSX만 쓰려고 파일 상단에 &lt;code&gt;import React&lt;/code&gt;를 적지 않아도 됩니다. 예전 코드에서 그 import를 보게 되는 이유입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;중괄호---마크업에서-javascript로-나가는-문&quot;&gt;중괄호 &lt;code&gt;{}&lt;/code&gt; — 마크업에서 JavaScript로 나가는 문&lt;/h2&gt;
&lt;p&gt;JSX가 JavaScript이기 때문에, 마크업 한가운데에서 다시 JavaScript로 빠져나올 수 있습니다. 그 출입구가 &lt;strong&gt;중괄호 &lt;code&gt;{}&lt;/code&gt;&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;카리나&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; element&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;안녕하세요, {name}님&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;{}&lt;/code&gt; 안에는 변수뿐 아니라 계산식, 함수 호출 등 &lt;strong&gt;값을 만들어내는 표현식(expression)&lt;/strong&gt;이면 무엇이든 들어갈 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;              {&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 3 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;{user.isAdmin &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;관리자&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;회원&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;단, 들어갈 수 있는 건 “값이 되는 표현식”까지입니다. &lt;code&gt;if&lt;/code&gt; 문이나 &lt;code&gt;for&lt;/code&gt; 문 같은 &lt;strong&gt;문장(statement)&lt;/strong&gt;은 넣을 수 없습니다. 이 구분은 처음엔 걸리적거리지만, “JSX 안의 &lt;code&gt;{}&lt;/code&gt;는 결국 하나의 값을 기대하는 자리”라고 생각하면 금방 익숙해집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;html과-미묘하게-다른-것들&quot;&gt;HTML과 미묘하게 다른 것들&lt;/h2&gt;
&lt;p&gt;닮은 만큼 어긋나는 지점들이 있습니다. 이유는 하나같이 &lt;strong&gt;“JSX는 JavaScript다”&lt;/strong&gt;로 귀결됩니다.&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;HTML&lt;/th&gt;&lt;th&gt;JSX&lt;/th&gt;&lt;th&gt;이유&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;class=&quot;box&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;className=&quot;box&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;class&lt;/code&gt;는 JavaScript 예약어라 못 씀&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;for=&quot;id&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;htmlFor=&quot;id&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;for&lt;/code&gt;도 예약어(반복문)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;onclick=&quot;...&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;onClick={...}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;속성은 camelCase, 값은 함수&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;style=&quot;color:red&quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;style={{ color: &apos;red&apos; }}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;문자열이 아니라 &lt;strong&gt;객체&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;br&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;#x3C;br /&gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;모든 태그는 반드시 닫아야 함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;특히 &lt;code&gt;style&lt;/code&gt;을 눈여겨보세요. 바깥 &lt;code&gt;{}&lt;/code&gt;는 “JavaScript로 나가는 문”, 안쪽 &lt;code&gt;{}&lt;/code&gt;는 “객체”라서 중괄호가 두 겹입니다. &lt;code&gt;background-color&lt;/code&gt;처럼 하이픈이 든 속성은 JavaScript 객체 키로 쓸 수 없어 &lt;code&gt;backgroundColor&lt;/code&gt;처럼 camelCase로 적습니다. 웹의 스타일과 닮았지만, 어디까지나 &lt;strong&gt;JavaScript 객체&lt;/strong&gt;라는 점이 다릅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;반환은-반드시-하나의-덩어리로&quot;&gt;반환은 반드시 하나의 덩어리로&lt;/h2&gt;
&lt;p&gt;컴포넌트는 화면 설계도를 &lt;code&gt;return&lt;/code&gt;하는데, 이때 &lt;strong&gt;최상위 요소는 하나여야&lt;/strong&gt; 합니다. 함수가 값 하나를 반환하듯, JSX도 결국 하나의 결과로 모여야 하기 때문입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ 형제 요소 두 개를 나란히 반환할 수 없음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;제목&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;본문&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그렇다고 의미도 없는 &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt;로 감싸 마크업을 지저분하게 만들긴 아깝습니다. 이때 쓰라고 있는 것이 &lt;strong&gt;프래그먼트(Fragment)&lt;/strong&gt;, 빈 태그 &lt;code&gt;&amp;#x3C;&gt;...&amp;#x3C;/&gt;&lt;/code&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;제목&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;본문&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  &amp;#x3C;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;#x3C;&gt;&lt;/code&gt;는 실제 화면에 아무 요소도 남기지 않으면서 여러 형제를 하나로 묶어줍니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;왜-굳이-이렇게-만들었을까&quot;&gt;왜 굳이 이렇게 만들었을까&lt;/h2&gt;
&lt;p&gt;마크업과 로직을 굳이 한 파일, 한 함수 안에 섞는 이 방식은 처음엔 어색합니다. 오랫동안 우리는 HTML은 HTML끼리, JavaScript는 JavaScript끼리 파일을 나누는 걸 미덕으로 배웠으니까요.&lt;/p&gt;
&lt;p&gt;하지만 지난 글에서 이야기한 컴포넌트의 발상을 떠올리면 이야기가 달라집니다. 버튼 하나를 만들 때 그 버튼의 &lt;strong&gt;생김새(마크업)&lt;/strong&gt;와 &lt;strong&gt;행동(로직)&lt;/strong&gt;은 사실 떼어놓기 어려운 한 덩어리입니다. JSX는 “화면과 그 화면을 만드는 논리는 원래 한 몸”이라는 관점을 문법으로 옮긴 것입니다. 파일 종류가 아니라 &lt;strong&gt;관심사(하나의 컴포넌트)&lt;/strong&gt;를 기준으로 코드를 모으는 셈이지요.&lt;/p&gt;
&lt;p&gt;이제 화면을 어떻게 적는지는 감이 잡혔습니다. 다음 글에서는 이 컴포넌트들을 조합할 때 부모가 자식에게 값을 건네는 방법, &lt;strong&gt;Props&lt;/strong&gt;를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>JSX</category><category>프론트엔드</category><category>선언형 UI</category></item><item><title>React란 무엇인가 — 선언형 UI와 컴포넌트라는 발상</title><link>https://blog.bepuljang.co.kr/react/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/react/01/</guid><description>React가 해결하려 한 문제는 무엇이고, &apos;명령형에서 선언형으로&apos;라는 전환은 왜 중요한가. 웹 개발 경험에 빗대어 React의 핵심 발상을 짚습니다.</description><pubDate>Thu, 09 Jul 2026 15:25:42 GMT</pubDate><content:encoded>&lt;p&gt;웹을 조금이라도 만져봤다면 React라는 이름은 익숙할 것입니다. 채용 공고에도, 튜토리얼에도, 남의 프로젝트 의존성 목록에도 늘 등장하니까요. 그런데 막상 “React가 뭐냐”고 물으면 “음… 프론트엔드 프레임워크?” 정도에서 말이 막히곤 합니다.&lt;/p&gt;
&lt;p&gt;이 시리즈는 React의 핵심 개념을 &lt;strong&gt;웹 개발 경험에 빗대어&lt;/strong&gt; 하나씩 짚어보려고 합니다. 이미 HTML·CSS·JavaScript로 무언가를 만들어본 사람을 전제로 하고, “기존 방식으로는 이런 게 불편했는데 React는 이렇게 풀더라”라는 식으로 이야기를 풀어갈 예정입니다. 그 첫걸음으로, 오늘은 React가 대체 무엇을 해결하려고 등장했는지부터 봅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;react는-프레임워크가-아니라-라이브러리다&quot;&gt;React는 ‘프레임워크’가 아니라 ‘라이브러리’다&lt;/h2&gt;
&lt;p&gt;먼저 사소해 보이지만 중요한 구분 하나. React는 스스로를 &lt;strong&gt;“사용자 인터페이스를 만들기 위한 라이브러리”&lt;/strong&gt;라고 소개합니다. 프레임워크가 아니라 라이브러리라는 점이 핵심인데, 라우팅이나 데이터 관리 같은 것을 React가 다 정해주지 않는다는 뜻이기 때문입니다.&lt;/p&gt;
&lt;p&gt;React가 책임지는 것은 딱 하나, &lt;strong&gt;화면(View)을 그리는 일&lt;/strong&gt;입니다. 주소에 따라 페이지를 바꾸는 일, 서버와 통신하는 일, 전역 상태를 관리하는 일은 별도의 라이브러리를 골라 조합합니다. 그래서 React는 가볍지만, 대신 “어떻게 조립할지”는 개발자의 몫으로 남습니다. 이 성격을 기억해두면 뒤에 나올 여러 선택지들이 왜 존재하는지 이해하기 쉬워집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;명령형에서-선언형으로&quot;&gt;명령형에서 선언형으로&lt;/h2&gt;
&lt;p&gt;React를 이해하는 가장 빠른 길은 &lt;strong&gt;선언형(Declarative)&lt;/strong&gt;이라는 단어를 붙잡는 것입니다. 이게 무슨 말인지는 기존 방식과 비교하면 선명해집니다.&lt;/p&gt;
&lt;p&gt;예전 방식으로 “버튼을 누르면 숫자가 1 올라가는” 화면을 만든다고 해봅시다. 우리는 대략 이렇게 했습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; el&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;#count&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;button.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;click&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  el.textContent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count; &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 화면을 &apos;직접&apos; 고쳐준다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기서 개발자가 하는 일은 “값이 바뀌었으니 화면의 이 부분을 이렇게 고쳐라”라고 &lt;strong&gt;일일이 지시하는 것&lt;/strong&gt;입니다. 이것이 명령형(Imperative)입니다. 화면이 복잡해질수록 “무엇이 바뀌면 어디를 고쳐야 하는가”의 경우의 수가 폭발하고, 여기서 대부분의 버그가 태어납니다.&lt;/p&gt;
&lt;p&gt;React는 발상을 뒤집습니다. 개발자는 화면을 고치는 절차를 쓰는 대신, &lt;strong&gt;“이 상태일 때 화면은 이렇게 생겼다”&lt;/strong&gt;만 선언합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Counter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;count&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;{() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)}&gt;{count}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;count&lt;/code&gt;가 바뀌면 화면의 어디를 어떻게 고칠지는 &lt;strong&gt;React가 알아서&lt;/strong&gt; 계산합니다. 개발자는 “상태가 이러면 결과는 이것”이라는 관계만 적어두면 됩니다. 요리에 비유하면, 명령형이 “냄비를 불에 올리고 3분 뒤 저어라”라는 조리 순서라면, 선언형은 “완성된 요리는 이런 모습이다”라는 완성 사진을 건네는 쪽에 가깝습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;컴포넌트--화면을-조립-가능한-단위로&quot;&gt;컴포넌트 — 화면을 조립 가능한 단위로&lt;/h2&gt;
&lt;p&gt;두 번째 핵심은 &lt;strong&gt;컴포넌트(Component)&lt;/strong&gt;입니다. 위 예시의 &lt;code&gt;Counter&lt;/code&gt;처럼, React에서는 화면의 조각을 &lt;strong&gt;함수 하나&lt;/strong&gt;로 정의합니다. 이 함수는 화면(정확히는 화면을 그리는 설계도)을 반환하고, 우리는 이 조각들을 레고 블록처럼 조합해 전체 화면을 만듭니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; App&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Header&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Counter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;Footer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;한 번 잘 만든 &lt;code&gt;Counter&lt;/code&gt;를 여러 곳에서 재사용할 수 있고, 각 조각은 자기 안의 일만 책임지면 됩니다. 화면을 ‘하나의 거대한 문서’가 아니라 ‘작은 부품들의 조합’으로 바라보는 이 관점은, 사실 React뿐 아니라 Vue·Svelte 같은 현대 프레임워크가 공유하는 공통 언어이기도 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;react는-어떻게-화면을-최소한으로만-고치는가&quot;&gt;React는 어떻게 화면을 최소한으로만 고치는가&lt;/h2&gt;
&lt;p&gt;“상태가 바뀌면 화면을 다시 그린다”라고 하면, 매번 전체를 새로 그려서 느리지 않을까 하는 의문이 듭니다. 여기서 등장하는 것이 &lt;strong&gt;가상 DOM(Virtual DOM)&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;React는 실제 화면(DOM)을 곧바로 건드리지 않습니다. 대신 화면의 모습을 가벼운 자바스크립트 객체로 한 벌 들고 있다가, 상태가 바뀌면 &lt;strong&gt;바뀐 새 버전과 이전 버전을 비교&lt;/strong&gt;해서 실제로 달라진 부분만 골라 진짜 DOM에 반영합니다. 이 비교 과정을 재조정(Reconciliation)이라고 부릅니다. 덕분에 우리는 “전체를 다시 선언”하는 편한 방식으로 코드를 쓰면서도, 실제 화면 갱신은 최소한으로 유지되는 이점을 함께 얻습니다.&lt;/p&gt;
&lt;p&gt;이 원리를 지금 깊이 알 필요는 없습니다. 다만 “React는 내가 선언한 결과와 현재 화면의 차이를 스스로 계산해 메운다”는 감각만 가지고 있으면, 앞으로 나올 State나 렌더링 이야기가 훨씬 자연스럽게 이어집니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;이-시리즈에서-다룰-것--그리고-react-native&quot;&gt;이 시리즈에서 다룰 것 — 그리고 React Native&lt;/h2&gt;
&lt;p&gt;정리하면 React의 발상은 세 문장입니다. &lt;strong&gt;화면을 상태의 함수로 선언한다. 화면은 재사용 가능한 컴포넌트로 조립한다. 실제 갱신은 React가 알아서 최소화한다.&lt;/strong&gt; 앞으로 이어질 글에서 JSX, Props, State, useEffect, Context 같은 개념을 하나씩 이 발상 위에 얹어갈 것입니다.&lt;/p&gt;
&lt;p&gt;한 가지 미리 밝혀둘 것이 있습니다. 이 시리즈의 1부는 &lt;strong&gt;웹에서의 React&lt;/strong&gt;를 다룹니다. 흔히 함께 묶여 언급되는 React Native는 방금 이야기한 React의 사고방식을 웹이 아니라 &lt;strong&gt;모바일 네이티브 화면&lt;/strong&gt;으로 옮긴 것으로, 별도의 2부에서 다룰 예정입니다. React를 제대로 이해해두면 React Native는 그 위에 얹히는 이야기라 훨씬 수월해집니다. 그러니 우선은 이 선언형이라는 감각에 익숙해지는 것부터 시작해봅시다.&lt;/p&gt;</content:encoded><category>웹 개발 시작부터 배포까지, React</category><category>React</category><category>선언형 UI</category><category>컴포넌트</category><category>프론트엔드</category></item><item><title>접점(contact point) 위주로 움직이는 사업의 위험성에 대하여 — 대표의 인맥이 곧 매출 구조일 때</title><link>https://blog.bepuljang.co.kr/startup-prince/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/03/</guid><description>『스타트업 군주론』 세 번째 이야기. 창업자의 개인적 관계로 만들어진 초기 매출이 왜 오래가지 못하는지, 빌린 힘으로 얻은 권력을 지키지 못했던 체사레 보르자의 이야기를 빌려 살펴봅니다.</description><pubDate>Thu, 09 Jul 2026 15:21:30 GMT</pubDate><content:encoded>&lt;p&gt;앞선 두 편에서는 비전과 돈, 조직 내부에서 벌어지는 근간의 문제를 다뤘습니다. 이번에는 조직 바깥, 사업이 세상과 맞닿는 접점 자체에 뿌리 깊은 위험이 있는 경우를 다룹니다.&lt;/p&gt;
&lt;h2 id=&quot;대표의-인맥이-곧-매출-구조일-때&quot;&gt;대표의 인맥이 곧 매출 구조일 때&lt;/h2&gt;
&lt;p&gt;초기 스타트업의 첫 매출은 대체로 창업자의 개인적인 관계에서 나옵니다. 이전 직장의 동료, 학교 선후배, 업계에서 알게 된 지인—이런 인맥을 통해 첫 번째, 두 번째, 열 번째 계약이 성사됩니다. 이 자체는 전혀 이상한 일이 아닙니다. 오히려 초기에는 가장 빠르고 효율적인 방법입니다.&lt;/p&gt;
&lt;p&gt;문제는 이 방식이 시간이 지나도 유일한 매출 경로로 남아있는 경우입니다. 대표가 여전히 모든 딜의 시작점이고, 신규 고객은 여전히 누군가의 소개를 통해서만 들어옵니다. 매출 대시보드는 성장하고 있지만, 그 성장의 엔진을 뜯어보면 결국 대표 한 사람의 시간과 인맥이라는, 확장 불가능한 자원 위에 세워져 있습니다.&lt;/p&gt;
&lt;p&gt;이런 구조는 투자자와의 대화에서도 잘 드러나지 않습니다. 매출 대시보드만 보면 성장세가 뚜렷하기 때문에, 그 성장의 근원이 무엇인지는 굳이 캐묻지 않는 경우가 많습니다. 정작 문제가 드러나는 시점은 대표가 육아휴직이나 건강 문제, 혹은 단순한 번아웃으로 몇 주간 자리를 비웠을 때입니다. 이때 신규 계약 파이프라인이 거의 그대로 멈춰버리는 회사와, 큰 변화 없이 굴러가는 회사의 차이가 비로소 눈에 보입니다.&lt;/p&gt;
&lt;h2 id=&quot;빌린-힘으로-세운-권력의-취약함&quot;&gt;빌린 힘으로 세운 권력의 취약함&lt;/h2&gt;
&lt;p&gt;마키아벨리는 『군주론』에서 체사레 보르자의 사례를 자세히 다룹니다. 보르자는 아버지인 교황 알렉산데르 6세의 후원과 프랑스의 군대라는, 자기 것이 아닌 힘을 빌려 로마냐 지역을 손에 넣었습니다. 그가 다스리는 방식 자체는 뛰어났다고 마키아벨리는 평가합니다. 그러나 그 권력의 기반이 온전히 자신의 것이 아니었기에, 아버지가 사망하고 후원자가 사라지자 그가 그렇게 애써 세운 것들은 순식간에 흔들렸습니다.&lt;/p&gt;
&lt;p&gt;마키아벨리가 이 사례에서 끌어내는 교훈은 명확합니다. 타인의 힘, 타인의 은혜로 얻은 지위는 그 타인이 존재하는 동안만 유지됩니다. 진짜 권력은 자기 자신의 역량과 자원—마키아벨리의 표현으로는 자신의 군대—으로 세운 것이어야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;접점은-시작점-엔진은-목적지&quot;&gt;접점은 시작점, 엔진은 목적지&lt;/h2&gt;
&lt;p&gt;스타트업의 인맥 기반 매출도 똑같은 취약함을 가집니다. 그 인맥이라는 자원은 무한하지 않습니다. 소진되거나, 그 인맥의 소유자인 대표가 다른 일에 시간을 뺏기는 순간, 신규 계약의 파이프라인은 눈에 띄게 얇아집니다. 더 위험한 경우는, 그 관계 자체가 대표 개인과 묶여 있어서, 조직이 아무리 커져도 영업이 여전히 대표를 거치지 않고는 진행되지 않는 구조로 굳어지는 것입니다.&lt;/p&gt;
&lt;p&gt;실제로 여러 B2B 스타트업이 이 단계에서 성장이 멈춥니다. 초기 몇 년간은 창업자의 이전 업계 네트워크로 착실하게 계약을 쌓아왔지만, 그 네트워크가 자연스럽게 소진되는 시점에 신규 파이프라인이 없다는 사실을 그제서야 깨닫습니다. 매출 그래프가 평평해지고 나서야 뒤늦게 세일즈 조직을 꾸리기 시작하지만, 그 사이 이미 벌어놓은 시간을 상당 부분 잃은 뒤입니다.&lt;/p&gt;
&lt;h2 id=&quot;전환의-신호를-놓치지-않는-법&quot;&gt;전환의 신호를 놓치지 않는 법&lt;/h2&gt;
&lt;p&gt;이 전환이 늦어지는 이유는 대개 신호가 없어서가 아니라, 신호를 무시하기 쉬워서입니다. 신규 계약의 몇 퍼센트가 대표를 거치지 않고 성사되는가, 소개 없이 들어온 문의가 실제 계약으로 이어지는 비율은 얼마인가—이 두 숫자를 매 분기 확인하는 것만으로도 접점 의존도를 가늠할 수 있습니다. 만약 대표를 거치지 않은 계약의 비율이 몇 분기 연속 늘지 않고 있다면, 매출 그래프가 아무리 우상향해도 사업의 엔진은 여전히 대표 개인이라는 뜻입니다.&lt;/p&gt;
&lt;p&gt;이 지표를 일찍부터 챙기는 조직은 대표의 인맥이 소진되기 전에 미리 세일즈 조직과 채널을 준비합니다. 반대로 매출 성장에만 눈이 가 있는 조직은, 그 성장이 멈추는 순간에야 비로소 엔진이 하나뿐이었다는 사실을 깨닫습니다. 깨달음의 시점이 늦을수록 대체 엔진을 만드는 데 걸리는 시간과 비용은 커집니다.&lt;/p&gt;
&lt;h2 id=&quot;접점을-시스템으로-바꾸는-일&quot;&gt;접점을 시스템으로 바꾸는 일&lt;/h2&gt;
&lt;p&gt;이 위험을 피하는 방법은 접점 자체를 없애는 것이 아닙니다. 접점에서 시작한 딜을 분석해서, 그 안에 반복 가능한 패턴이 있는지를 찾아내는 것입니다. 이 고객들은 어떤 문제 때문에 우리를 찾았는가, 어떤 채널을 통해 우리를 알게 되었는가, 어떤 메시지에 반응했는가. 이 질문에 대한 답을 찾아내면, 대표의 인맥에 의존하지 않고도 같은 패턴을 반복할 수 있는 구조—콘텐츠, 콜드 아웃바운드, 파트너십, 레퍼럴 프로그램—로 옮겨갈 수 있습니다.&lt;/p&gt;
&lt;p&gt;실제로 이 전환에 성공한 팀들은 흔히 비슷한 절차를 밟습니다. 지난 1~2년간 성사된 계약을 모두 나열하고, 각각이 시작된 경로와 계약까지 걸린 시간, 결정적으로 작용한 메시지를 함께 정리합니다. 이렇게 모아 놓으면 우연이라고 생각했던 성공 사례들 사이에서 반복되는 패턴—특정 업종, 특정 규모, 특정 문제를 가진 고객이 유난히 빠르게 계약한다는 사실—이 드러납니다. 그 패턴을 알고 나면, 같은 조건의 잠재 고객을 대표의 인맥 밖에서도 찾아낼 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 전환이 이루어지지 않으면, 매출 대시보드에 찍히는 숫자와 관계없이 그 사업은 사실 회사가 아니라 대표 개인의 활동에 더 가깝습니다. 대표가 자리를 비우면 함께 멈추는 사업은, 마키아벨리가 우려했던 그 취약함을 그대로 안고 있는 것입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 시장의 흐름과 타이밍이라는, 또 다른 형태의 빌린 힘을 다룹니다. 운으로 오른 성장이 왜 그 운이 꺾이는 순간 함께 무너지는지 살펴봅니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>영업</category><category>네트워크</category><category>스타트업 군주론</category></item><item><title>인지를 디자인에 어떻게 활용할 것인가 — 그리고 어포던스라는 조용한 설득</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/07/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/07/</guid><description>선택집중, 연관짓기, 심성모형이라는 세 가지 인지 처리 방식이 실제 디자인에 던지는 시사점을 살펴보고, 사용자의 무의식을 통해 행동을 이끄는 어포던스라는 개념까지 함께 짚어봅니다.</description><pubDate>Thu, 09 Jul 2026 15:21:30 GMT</pubDate><content:encoded>&lt;p&gt;지난 글에서는 인간이 경험을 형성하는 과정에서 핵심적으로 작동하는 세 가지 인지 처리 방식—선택집중, 연관짓기, 심성모형—을 살펴보았습니다. 이 세 가지는 각각 정보를 받아들이는 입구에서, 정보를 조직하는 과정에서, 그리고 정보를 해석하고 활용하는 단계에서 작동하는 것이었습니다. 이제 이것이 실제 디자인에 어떤 의미를 갖는지, 그리고 그 연장선에 있는 어포던스라는 개념까지 이어서 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;선택집중이-디자인에-남기는-과제&quot;&gt;선택집중이 디자인에 남기는 과제&lt;/h2&gt;
&lt;p&gt;우선 선택 집중의 측면에서, 디자이너는 두 가지 차원의 고려가 필요합니다.&lt;/p&gt;
&lt;p&gt;하나는 정량적인 차원입니다. 시인성과 대비감을 활용하여 정보의 우선순위에 따라 집중이 필요한 핵심 정보가 사용자의 선택을 받을 수 있도록 충분한 시각적 구분을 부여해야 합니다. 다른 하나는 정성적인 차원으로, 사용자의 흥미와 관심이 무엇인지를 깊이 이해하여 그들의 집중을 자연스럽게 이끌어내야 한다는 점입니다.&lt;/p&gt;
&lt;p&gt;여기서 특히 경계해야 할 것은, 정보를 그냥 무의미하게 나열하거나 가능한 한 많이 배치하면 사용자가 그 모든 것을 유익하고 유의미하게 받아들일 것이라는 안일한 생각입니다. 앞서 살펴보았듯이 인간의 집중은 선택적이므로, 모든 것을 동일한 무게로 보여주는 것은 결국 아무것도 제대로 보여주지 못하는 것과 다름없습니다. 정보는 철저하게 레벨링되어야 하며, 목표로 하는 경험에 가까운 핵심 정보일수록 더 선명하게, 더 흥미롭게 사용자의 눈앞에 놓여야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;연관짓기와-정보의-위계&quot;&gt;연관짓기와 정보의 위계&lt;/h2&gt;
&lt;p&gt;다음으로, 연관짓기의 측면에서는 정보의 조직과 계층화에 대한 중요한 통찰을 얻을 수 있습니다.&lt;/p&gt;
&lt;p&gt;디자이너가 사용자에게 전달하고자 하는 정보는 의미적으로 연관성 있게 조직되어 사용자가 자연스럽게 덩어리로 묶어 처리할 수 있어야 합니다. 인간의 단기 정보 처리 용량에는 한계가 있으므로, 너무 많은 정보가 한꺼번에 쏟아지지 않도록 적절한 선에서 계층화가 이뤄져야 합니다. 앞서 선택 집중에서도 언급했듯이 무의미하게 많이 배치된 정보는 사용자의 시선조차 끌지 못할 뿐 아니라, 연관짓기의 측면에서도 인지 부하를 과도하게 늘려 오히려 정보의 처리와 습득을 적극적으로 방해하는 결과를 낳습니다.&lt;/p&gt;
&lt;p&gt;따라서 디자이너는 정보 하나하나의 의미와 정보 간의 상호 관련성을 유심히 살펴야 합니다. 여기서 한 가지 더 주의해야 할 점은, 디자이너가 설정한 그 관련성이 과연 사용자의 관점에서도 유효한지를 반드시 검증해야 한다는 것입니다. 디자이너에게는 당연히 한 묶음으로 보이는 정보들이 사용자에게는 전혀 다른 기준으로 분류될 수 있기 때문입니다. 사용자에 따라서 어떤 정보들끼리 관련이 있다고 느끼는지는 그들의 경험과 맥락에 따라 상당히 달라질 수 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이렇게 사용자의 경험과 맥락에 따라 관련성의 기준이 달라진다는 점에서, 연관짓기는 이 시리즈에서 다루는 UX디자인 파라미터 중 ‘편의성’과 깊은 관련이 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;심성모형과-학습-비용의-절감&quot;&gt;심성모형과 학습 비용의 절감&lt;/h2&gt;
&lt;p&gt;마지막으로, 심성모형은 세 가지 인지처리 방식 중에서도 UX디자인에서 특히 자주 언급되고 중시되는 개념입니다. 그 이유는 심성모형이 사용자 경험의 유도 측면에서 매우 강력하고도 효율적인 수단이 되기 때문입니다.&lt;/p&gt;
&lt;p&gt;현실적으로, 제품이나 서비스를 제작하는 제공자가 사용자에게 제작 의도와 각 기능들의 사용법을 하나하나 설명하는 것은 불가능에 가깝습니다. 설령 가능하다 하더라도, 그 학습에 많은 시간과 노력이 소모된다면 사용자 입장에서는 큰 부담이 되어 제품 자체를 외면하게 될 수 있습니다.&lt;/p&gt;
&lt;p&gt;따라서 이 학습 비용을 최소화하는 것이 UX디자인의 핵심 과제 중 하나인데, 바로 그때 빛을 발하는 것이 사용자가 이미 가지고 있는 심성모형입니다. 사용자가 기존에 형성해 놓은 정보의 구조체를 디자인에 적절히 활용하면, 별도의 설명 없이도 사용자는 제품의 작동 방식을 직관적으로 이해할 수 있습니다. 적절하게 사용된 아이콘 하나가 장황한 사용자 자습서보다 유용하고 강력할 수 있으며, 사용자의 행동을 자연스럽고 직관적으로 유도할 수 있는 것이 바로 이런 이유에서입니다.&lt;/p&gt;
&lt;h2 id=&quot;과거의-경험이-유도하는-새로운-경험&quot;&gt;과거의 경험이 유도하는 새로운 경험&lt;/h2&gt;
&lt;p&gt;이처럼 심성모형을 통해 사용자의 행동을 자연스럽게 이끌어내는 성질을 행동유도성(어포던스; affordance)이라고 하는데, 이 개념을 좀 더 깊이 들여다볼 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;우선 ‘행동유도성’이라는 명칭이 직접적으로 명시하듯이, 이것은 명시적인 지시(guidance)와는 분명히 다른 성격을 갖습니다. 지시가 “이것을 누르세요”라고 직접 알려주는 것이라면, 어포던스는 사용자가 스스로 “이것을 눌러야겠다”고 느끼도록 만드는 것입니다.&lt;/p&gt;
&lt;p&gt;어원을 살펴보면 이 차이가 더 명확해집니다. 영어에서 afford라는 단어의 뜻은 ‘~할 만하다’, ‘~할 여유가 있다’ 정도로 풀이됩니다. 이처럼 ‘어포던스’는 강제하거나 명령하는 것이 아니라, 어떤 행동을 할 만하도록 지그시, 자연스럽게 이끄는 의미를 갖습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;앞서 ‘행동(behavior)‘이 의식적인 행위(action)와 달리 무의식적으로 발현되는 표상이라는 점을 짚은 적이 있는데, 행동유도성에서도 ‘행동’이라는 단어가 쓰이는 이유는 여기에 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이는 심성모형을 통한 유도가 사용자의 의식적인 판단이 아닌, 무의식의 영역에서 자연스럽게 발생하는 것임을 암시합니다. 다시 말해, 좋은 어포던스를 가진 디자인 앞에서 사용자는 “이걸 어떻게 쓰지?”라고 의식적으로 고민하는 대신, 자신도 모르게 올바른 방향으로 손이 움직이게 되는 것입니다.&lt;/p&gt;
&lt;p&gt;지금까지 살펴본 선택집중, 연관짓기, 심성모형이라는 주요한 인지적 절차들은 결국 하나의 방향을 가리킵니다. 그것은 우리가 어떻게 사용자를 이해하고, 어떤 식으로 디자인을 구성해야 사용자의 경험을 실질적으로 개선할 수 있는지를 보여준다는 것입니다.&lt;/p&gt;
&lt;p&gt;이를 정리하면, 우리는 먼저 사용자의 흥미와 관심이 어디에 있는지, 그리고 그들이 이미 가지고 있는 정보 간의 의미 관계나 심성모형이 어떤 형태인지를 깊이 이해해야 합니다. 그래야 사용자가 무엇에 집중하고 무엇을 무시할지, 어떤 정보를 하나의 덩어리로 묶어 인식할지, 어떤 형태에서 어떤 기능을 기대할지를 예측할 수 있기 때문입니다.&lt;/p&gt;
&lt;p&gt;이러한 이해를 바탕으로, 우리는 정보를 신중하게 분류하고 레벨링하여 명확한 우선순위로 정리해야 하며, 사용자의 관심과 흥미는 물론 그들의 신체적이고 인지적인 한계까지 고려하여 정보를 배치해야 합니다. 그리고 궁극적으로, 우리는 명시적인 지시가 아닌 사용자의 무의식을 통해 자연스럽게 행동을 유도하는 디자인을 지향해야 합니다. 이 모든 것의 출발점은 결국 같습니다. 우리는 사용자와 정보를 깊이 공부하고, 그 이해 위에서 경험을 설계해야 합니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 이렇게 형성된 인지가 겉으로 드러나는 단서, 즉 ‘행동(Behavior)‘을 다룹니다. 사용자가 보여주는 행동이야말로 그 이면의 인지를 읽어낼 수 있는 실마리이기 때문입니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>인지심리학</category><category>어포던스</category><category>심성모형</category></item><item><title>내 서비스를 세상에 내놓기 — 바이브 코더의 배포 첫걸음</title><link>https://blog.bepuljang.co.kr/vibecoding/08/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/08/</guid><description>로컬에서만 돌아가던 앱을 인터넷에 배포하는 방법을 처음부터 단계별로 다룹니다.</description><pubDate>Thu, 09 Jul 2026 15:21:00 GMT</pubDate><content:encoded>&lt;p&gt;로컬에서 잘 돌아가는 앱을 만들었다면 이제 다른 사람도 쓸 수 있도록 인터넷에 올릴 차례입니다. 이 과정을 **배포(deploy)**라고 합니다.&lt;/p&gt;
&lt;p&gt;배포는 개발자만 할 수 있는 전문 영역처럼 느껴지지만, 지금은 코딩 지식 없이도 몇 분 안에 배포할 수 있는 서비스들이 많이 있습니다. 이 편에서는 배포의 개념과 실제 배포 방법을 다룹니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;배포란-무엇인가&quot;&gt;배포란 무엇인가&lt;/h2&gt;
&lt;p&gt;배포는 &lt;strong&gt;내 컴퓨터에서만 실행되던 서비스를 인터넷에 올려서 다른 사람도 접근할 수 있게 만드는 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;지금까지 만든 북마크 앱은 &lt;code&gt;http://localhost:5173&lt;/code&gt;에서만 동작합니다. &lt;code&gt;localhost&lt;/code&gt;는 “내 컴퓨터”를 뜻하는 주소로, 내 컴퓨터에서만 접근할 수 있습니다. 배포를 하면 &lt;code&gt;https://myapp.vercel.app&lt;/code&gt; 같은 주소가 생기고, 전 세계 어디서나 접근할 수 있게 됩니다.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;로컬 개발&lt;/th&gt;&lt;th&gt;배포 후&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;접근 주소&lt;/td&gt;&lt;td&gt;&lt;code&gt;localhost:5173&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;myapp.vercel.app&lt;/code&gt; 같은 실제 URL&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;접근 가능한 사람&lt;/td&gt;&lt;td&gt;나만&lt;/td&gt;&lt;td&gt;인터넷이 되는 누구나&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;컴퓨터 상태&lt;/td&gt;&lt;td&gt;내 컴퓨터가 켜져 있어야 함&lt;/td&gt;&lt;td&gt;클라우드 서버가 24시간 운영&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;프론트엔드-배포-vercel로-5분-만에&quot;&gt;프론트엔드 배포: Vercel로 5분 만에&lt;/h2&gt;
&lt;p&gt;북마크 앱처럼 백엔드(서버) 없이 HTML/CSS/JavaScript로만 구성된 앱(정적 사이트)은 Vercel로 쉽게 배포할 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;1단계-github에-코드-올리기&quot;&gt;1단계: GitHub에 코드 올리기&lt;/h3&gt;
&lt;p&gt;배포하려면 코드를 GitHub에 올려야 합니다. GitHub는 코드를 저장하고 공유하는 서비스입니다.&lt;/p&gt;
&lt;p&gt;아직 Git을 쓴 적 없다면 Claude Code에게 도움을 요청합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plain&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;이 프로젝트를 GitHub에 올리고 싶어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;git 초기화부터 GitHub 저장소 연결까지 순서대로 알려줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code가 단계별로 안내합니다.&lt;/p&gt;
&lt;h3 id=&quot;2단계-vercel-가입-및-배포&quot;&gt;2단계: Vercel 가입 및 배포&lt;/h3&gt;
&lt;p&gt;GitHub 계정으로 &lt;a href=&quot;https://vercel.com&quot;&gt;vercel.com&lt;/a&gt;에 로그인합니다.&lt;/p&gt;
&lt;p&gt;“New Project” 버튼을 누르고 방금 만든 GitHub 저장소를 선택합니다. Vercel이 자동으로 React/Vite 프로젝트를 감지하고 빌드 설정을 제안합니다. “Deploy” 버튼을 누르면 1~2분 안에 배포가 완료됩니다.&lt;/p&gt;
&lt;p&gt;배포가 끝나면 &lt;code&gt;https://프로젝트명.vercel.app&lt;/code&gt; 형태의 주소가 생깁니다.&lt;/p&gt;
&lt;h3 id=&quot;자동-재배포&quot;&gt;자동 재배포&lt;/h3&gt;
&lt;p&gt;Vercel의 장점은 이후에 GitHub에 코드를 올릴 때마다 자동으로 재배포된다는 것입니다. 따로 배포 작업을 할 필요 없이, 코드를 수정하고 GitHub에 올리면 몇 분 후 변경사항이 반영됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;다양한-배포-서비스-비교&quot;&gt;다양한 배포 서비스 비교&lt;/h2&gt;
&lt;p&gt;상황에 따라 적합한 배포 서비스가 다릅니다.&lt;/p&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;서비스&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;th&gt;적합한 상황&lt;/th&gt;&lt;th&gt;가격&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Vercel&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;React/Next.js 배포에 최적화, GitHub 연동 간편&lt;/td&gt;&lt;td&gt;프론트엔드 위주 프로젝트&lt;/td&gt;&lt;td&gt;무료 플랜 있음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Netlify&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Vercel과 유사, 폼 처리 등 추가 기능 제공&lt;/td&gt;&lt;td&gt;정적 사이트, 간단한 백엔드 필요 시&lt;/td&gt;&lt;td&gt;무료 플랜 있음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Render&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;백엔드(Node.js, Python 등) 포함 배포 가능&lt;/td&gt;&lt;td&gt;풀스택 앱&lt;/td&gt;&lt;td&gt;무료 플랜 있음 (저속)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Railway&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Docker 기반 배포, 데이터베이스 포함&lt;/td&gt;&lt;td&gt;복잡한 백엔드, DB 필요 시&lt;/td&gt;&lt;td&gt;월 $5부터&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AWS / GCP&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;전문 클라우드 서비스, 확장성 높음&lt;/td&gt;&lt;td&gt;대규모 서비스, 세밀한 제어 필요 시&lt;/td&gt;&lt;td&gt;사용량 기반&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;처음 배포를 경험해보는 용도라면 Vercel이나 Netlify에서 시작하는 것을 권장합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;배포-후-확인사항&quot;&gt;배포 후 확인사항&lt;/h2&gt;
&lt;p&gt;배포가 완료됐다면 몇 가지를 확인합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기능 확인&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;배포된 주소에 접속해서 로컬에서 작동하던 기능들이 그대로 작동하는지 확인합니다. 로컬에서는 잘 되지만 배포 환경에서는 안 되는 경우가 종종 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;에러 확인&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Vercel 대시보드에서 빌드 로그와 함수 로그를 확인할 수 있습니다. 에러가 있다면 로그를 Claude Code에 붙여넣고 도움을 요청합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;첫-배포의-의미&quot;&gt;첫 배포의 의미&lt;/h2&gt;
&lt;p&gt;로컬에서만 돌아가던 앱이 이제 인터넷에 올라가 있습니다. 주소를 공유하면 다른 사람도 접근할 수 있습니다. 이 시점이 서비스가 실제로 “세상에 나온” 순간입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 배포 후에 반드시 해야 하는 작업인 리팩터링을 다룹니다. 빠르게 만들다 보면 코드가 복잡해지는데, AI와 함께 코드를 읽고 정리하는 방법을 알아봅니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>배포</category><category>Vercel</category><category>GitHub</category><category>바이브코딩</category></item><item><title>스페큘러티브 디자인: 선호되는 미래를 디자인하다</title><link>https://blog.bepuljang.co.kr/speculative-design/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/speculative-design/01/</guid><description>미래를 예측하는 것을 넘어, 사회 전체가 나아갈 더 나은 길을 제안하는 스페큘러티브 디자인. 그 개념과 디자인 방향을 이야기합니다.</description><pubDate>Thu, 09 Jul 2026 10:51:08 GMT</pubDate><content:encoded>&lt;p&gt;스페큘러티브 디자인(Speculative Design)이라는 개념이 있습니다. ‘디자인(Design)‘이라는 개념은 처음에 공예(Craft)로부터 출발했다고 여겨지는데요, 공산품에 예술을 더하는 공예의 개념에서 점차 공산품을 만드는 과정에서 예술을 생각하는 식으로 분화되어 나온 것이라고 할 수 있겠습니다. 그런 식으로 무언가의 공정에서 그 목적과 효율성에 맞춰 기획하고 조율하는 것으로 의미가 확장되어 오던 ‘디자인’에 추측, 전망을 뜻하는 ‘스페큘레이션(Speculation)‘이 붙은 것이지요.&lt;/p&gt;
&lt;p&gt;즉, 말 그대로 풀면 미래를 예측하고 전망하는 디자인인데, 사실 이 자체는 ‘디자인’이라는 개념에는 자연스럽습니다. 디자인은 원래 그 목적물의 사용자와 사용환경을 예측하고 사용 목적에 맞춰 효율화된 형태를 제공해왔기 때문이죠. 단편적으로 생각하면, 모든 디자인은 예측과 전망을 담고 있습니다.&lt;/p&gt;
&lt;p&gt;그렇기에 특별히 이러한 용어가 생겨난 배경과 그 말이 설명하는 색다른 개념이 무엇인지가 궁금한데요, 스페큘러티브 디자인은 단순히 어떤 디자인 목적물의 공정에서의 예측을 넘어, 보다 사회적이고 거시적인 관점을 지닌다는 특징이 있습니다.&lt;/p&gt;
&lt;p&gt;다시 말해, 이전의 디자인이 제품이나 서비스, 기업 등 특정 목적물에 대해서 고민하고 그 미래에 대한 예견적 성격을 통해 목표에 맞는 최적의 형태를 제안해왔다면 스페큘러티브 디자인은 사회와 시대 전반을 디자인 목적물로 두고 우리에게 주어진 기술과 환경 속에서 우리 사회 전체가 나아갈 더 나은 길을 상상하고 제안하는 디자인이라고 볼 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;스페큘러티브 디자인에서 많이 다뤄지곤 하는 미래의 고깔(Futures Cone, 발생 가능성의 고깔이라고도 합니다)은 이를 시각적으로 설명하는 좋은 도표인데, 우리의 현재에서 발생 가능한 전체 미래를 두고 그 가능성에 따라 유망한(Probable) 미래와 그럴듯한(Plausible) 미래, 그리고 가능성이 있는(Possible) 미래로 구분한 뒤 이들 중 선호되는(Preferred) 미래로 나아가도록 제안할 수 있음을 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;현재에서 시간이 흐를수록 넓어지는 고깔 도표. 안쪽부터 유망한, 그럴듯한, 가능성이 있는 미래로 나뉘고, 선호되는 미래는 고깔 안의 한 지점으로 표시되어 있다.&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; width=&quot;1400&quot; height=&quot;780&quot; src=&quot;https://blog.bepuljang.co.kr/_astro/futures-cone.DqKx5H1F_Zckyn0.webp&quot; srcset=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Hancock &amp;#x26; Bezold(1994)와 Joseph Voros의 도표를 바탕으로 다시 그린 미래의 고깔&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;기존에도 컨셉 디자인(Conceptual Design)이라고 해서 비슷하게 상상력의 사물을 제시하는 디자인 분야가 있었지만 스페큘러티브 디자인이 이와 구별되는 점은 컨셉 디자인은 어디까지나 현실에 방점을 찍고 다가오는 근미래에서의 새로운 제품 및 서비스의 사용성을 제시하는 측면에 그쳤다면(Probability), 스페큘러티브 디자인은 선도적으로 미래의 비전과 우리가 나아가야 할 길을 제시하고 이끄는 측면(Preferred)이 있다는 점일 것입니다. 즉, 현실의 결과로서의 미래를 디자인하는 것이 아니라 변화를 통해 나아갈 수 있는, 더 개선된 미래를 디자인하는 것이 주요한 차별점이라고 봅니다.&lt;/p&gt;
&lt;p&gt;보통 우리는 미래를 어둡고 막막한 디스토피아(Dystopia)로 조망하는 경우가 많습니다. 우리는 같은 크기라도 이득보다 손실을 더 크게 느끼고(전망이론의 손실 회피), 부정적인 자극에 더 강하게 반응하는 경향이 있기 때문일 것입니다. 하지만 디자인은 언제나 그 인간의 본성을 이겨내고 주어진 조건과 목표 속에서 가장 최적의 결과를 찾아왔습니다.&lt;/p&gt;
&lt;p&gt;스페큘러티브 디자인 역시, 우리가 가진 조건들을 냉정하게 바라보고 그 속에서 사회가 나아가야 할 길, 그리고 가장 선호될 미래를 찾는데 그 의의가 있습니다. 우리에게 주어진 유토피아의 실마리를 찾는 것이지요. 단 하나의 가장 이상적인 미래를 말입니다.&lt;/p&gt;
&lt;p&gt;이 시리즈에서는 이 개념이 어디에서 왔고, 어떤 작업들을 낳았으며, 어떤 비판을 받아 왔는지를 차례로 살펴보려고 합니다. 그 끝에서 이 마지막 문장도 다시 생각해 보겠습니다.&lt;/p&gt;</content:encoded><category>What is Speculative Design</category><category>스페큘러티브 디자인</category><category>디자인</category><category>UX디자인</category><category>미래</category></item><item><title>돈을 목표로 삼는 위험에 대하여 — 좇을수록 멀어지는 역설</title><link>https://blog.bepuljang.co.kr/startup-prince/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/02/</guid><description>『스타트업 군주론』 두 번째 이야기. 비전이 있어도 그 자리에 돈이 슬며시 들어와 앉는 순간, 조직의 의사결정이 어떻게 왜곡되는지를 마키아벨리의 부(富)에 대한 논의를 빌려 살펴봅니다.</description><pubDate>Wed, 08 Jul 2026 15:06:46 GMT</pubDate><content:encoded>&lt;p&gt;앞선 글에서는 비전이 명확하게 제시되지 않을 때 조직이 각자 다른 방향으로 흩어지는 위험을 다뤘습니다. 그런데 비전이 있다고 해서 안심할 수 있는 것도 아닙니다. 더 흔하게 벌어지는 일은, 비전이 분명 존재하는데도 그 자리에 슬며시 돈이 들어와 앉는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;좇을수록-멀어지는-역설&quot;&gt;좇을수록 멀어지는 역설&lt;/h2&gt;
&lt;p&gt;돈을 목표로 삼은 조직은 처음엔 오히려 빠르게 성과를 냅니다. 이번 달 매출 목표, 이번 분기 순증 매출, 전환율 몇 퍼센트—숫자로 표현된 목표는 명확하고 측정 가능해서 다들 거기에 맞춰 일하기 쉽습니다. 프로모션을 돌리고, 가격을 조정하고, 업셀을 강화합니다. 숫자는 정말로 오릅니다.&lt;/p&gt;
&lt;p&gt;문제는 그 다음입니다. 프로모션에 익숙해진 사용자는 정가에 반응하지 않게 되고, 무리하게 밀어붙인 업셀은 해지율을 함께 밀어 올립니다. 이번 달 매출을 채우기 위해 다음 달의 신뢰를 미리 꺼내 쓴 셈입니다. 반년, 일년이 지나면 매출 목표는 매번 달성했는데도 회사의 기초 체력은 오히려 약해져 있는 상황을 마주하게 됩니다. 돈을 좇았는데, 돈에서 점점 멀어지는 역설입니다.&lt;/p&gt;
&lt;p&gt;실제 사례를 보면 이 패턴이 더 선명해집니다. 구독형 서비스를 운영하던 한 스타트업은 분기 매출 목표를 채우기 위해 매달 신규 가입자에게 파격적인 할인 코드를 반복해서 발급했습니다. 신규 매출은 매번 목표를 넘겼지만, 할인 없이는 아무도 갱신하지 않는 구조가 조용히 자리 잡았습니다. 몇 분기 뒤 할인 정책을 거둬들이자, 매출은 그동안의 목표 달성 기록과는 무관하게 순식간에 반토막이 났습니다.&lt;/p&gt;
&lt;h2 id=&quot;부富는-목적이-아니라-결과라는-마키아벨리의-관점&quot;&gt;부(富)는 목적이 아니라 결과라는 마키아벨리의 관점&lt;/h2&gt;
&lt;p&gt;마키아벨리는 『군주론』에서 군주가 재산을 백성에게서 무리하게 거둬들이는 일을 경계했습니다. 재정이 부족하다고 세금을 무겁게 매기면 백성의 미움을 사고, 미움은 반란의 씨앗이 됩니다. 반대로 그가 인정하는 건전한 재정은, 백성을 지키고 나라를 안정시키는 과정에서 자연스럽게 쌓이는 곳간입니다. 부는 그 자체로 군주의 목적이 아니라, 다른 목적—안정과 방어—을 위한 수단이자 결과였습니다.&lt;/p&gt;
&lt;p&gt;이 구분이 스타트업에도 그대로 적용됩니다. 매출은 목적이 될 수 없습니다. 매출은 사용자가 문제를 해결받았다고 느끼고 그 대가를 지불한 결과입니다. 이 순서를 뒤집어, 매출이라는 결과를 직접 겨냥하기 시작하면, 정작 그 결과를 만들어내는 원인—문제 해결의 질—을 방치하거나 훼손하는 결정을 내리게 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;무엇이-왜곡되는가&quot;&gt;무엇이 왜곡되는가&lt;/h2&gt;
&lt;p&gt;돈을 목표로 삼을 때 가장 먼저 왜곡되는 것은 우선순위입니다. 사용자가 자주 겪는 사소하지만 근본적인 불편을 고치는 일보다, 당장 매출로 연결되는 기능—결제 단계 추가, 가격제 개편, 프로모션 배너—이 항상 우선순위 앞자리를 차지하게 됩니다. 이런 결정이 한두 번이면 큰 문제가 아니지만, 반복되면 제품은 조금씩 사용자보다 매출 그래프를 향해 기울어집니다.&lt;/p&gt;
&lt;p&gt;투자 유치를 준비하는 스타트업에서 특히 자주 보이는 왜곡도 있습니다. 다음 라운드의 지표를 좋게 보이기 위해, 실제로는 리텐션이 낮은 사업 모델을 매출 숫자만으로 그럴듯하게 포장하는 경우입니다. 투자자에게 보여줄 그래프는 우상향하지만, 그 그래프 아래에서는 이탈하는 사용자를 신규 유입으로 계속 메꾸고 있을 뿐인 구조가 숨어 있습니다. 이런 구조는 반드시 언젠가 드러나며, 드러나는 시점은 대개 회사가 그것을 감당하기 가장 어려운 순간입니다.&lt;/p&gt;
&lt;p&gt;이런 왜곡은 고객 접점에서도 똑같이 나타납니다. 이번 분기 손익을 맞추기 위해 고객 지원 인력을 줄이거나 환불 정책을 까다롭게 바꾸는 결정도 흔합니다. 당장의 비용은 줄고 손익 지표는 개선되지만, 그 결정으로 실망한 고객은 다음 갱신 시점에 조용히 떠납니다. 이탈은 그 결정을 내리는 순간에는 보이지 않는 비용이기 때문에, 무엇을 희생시켰는지는 한참 뒤에야 드러납니다.&lt;/p&gt;
&lt;h2 id=&quot;대리-지표와-진짜-지표&quot;&gt;대리 지표와 진짜 지표&lt;/h2&gt;
&lt;p&gt;이 왜곡을 막으려면 매출 대신 무엇을 봐야 하는지가 명확해야 합니다. 매출은 결과이므로, 그 결과를 만들어내는 원인 쪽의 지표—예를 들면 특정 문제를 해결한 뒤 사용자가 다시 돌아오는 비율, 추천 없이도 재구매가 일어나는 비율, 첫 사용에서 핵심 가치를 경험하기까지 걸리는 시간—를 함께 추적해야 합니다. 매출은 오르는데 이런 원인 지표는 정체되어 있다면, 그 매출 성장은 오래가지 못할 성장이라는 신호입니다.&lt;/p&gt;
&lt;p&gt;실제로 건강한 조직은 매출 목표를 세울 때도 그 매출이 어떤 원인 지표의 개선에서 나올 것인지를 먼저 정의합니다. “이번 분기 매출 20% 성장”이 아니라 “핵심 기능의 재사용률을 15%p 올리고, 그 결과로 매출이 성장한다”는 식입니다. 이렇게 순서를 명시해두면, 매출이 오르지 않을 때 무엇을 점검해야 하는지도 자연히 명확해집니다.&lt;/p&gt;
&lt;h2 id=&quot;돈은-따라오는-것&quot;&gt;돈은 따라오는 것&lt;/h2&gt;
&lt;p&gt;결론은 단순합니다. 목표는 언제나 “우리가 무엇을 해결하는가”에 있어야 하고, 돈은 그 해결이 잘 이루어졌을 때 따라오는 결과여야 합니다. 이 순서를 지키는 조직은 매출이 흔들리는 시기에도 무엇을 고쳐야 하는지 압니다. 문제 해결로 돌아가면 되기 때문입니다. 반대로 돈을 목표로 삼아온 조직은 매출이 흔들리면 대개 더 강한 프로모션, 더 공격적인 업셀로 대응합니다. 같은 병을 키우는 처방인 셈입니다.&lt;/p&gt;
&lt;p&gt;앞선 글에서 다룬 비전이 바로 이 지점에서 다시 중요해집니다. “우리가 해결하는 문제”가 조직 전체에 구체적으로 새겨져 있다면, 매출이라는 결과가 목표의 자리를 슬며시 차지하려 할 때 그것을 알아채고 되돌릴 기준이 있는 셈입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 또 다른 형태의 가짜 근간을 다룹니다. 대표 한 사람의 인맥과 관계로 굴러가는 사업, 그 접점이 사업의 전부가 되어버렸을 때의 위험입니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>매출</category><category>그로스</category><category>스타트업 군주론</category></item><item><title>사용자의 머릿속, 인지라는 빙산 — 선택집중·연관짓기·심성모형</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/06/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/06/</guid><description>사용자 경험은 결국 사용자의 머릿속에서 완성됩니다. 인지를 빙산에 비유하며, 그 아래에서 작동하는 선택집중·연관짓기·심성모형이라는 세 가지 인지처리 방식을 살펴봅니다.</description><pubDate>Wed, 08 Jul 2026 15:06:46 GMT</pubDate><content:encoded>&lt;p&gt;인지(Cognition)는 우리가 외부의 자극 및 정보를 받아들여 처리하는 정신적인 총체적 공정을 말합니다. 단순히 눈으로 보고 귀로 듣는 감각의 영역에 그치지 않고, 그렇게 받아들인 자극을 해석하고, 분류하고, 기억하고, 다시 꺼내어 활용하는 일련의 과정 전체를 아우르는 개념입니다.&lt;/p&gt;
&lt;p&gt;우리는 외부의 어떤 사물이나 환경을 접할 때 그로부터 감각적으로 느낄 수 있는 모든 표상들을 통해 정보를 얻습니다. 그리고 이들 중 더러는 무의식적으로 걸러내 버리고, 일부는 선택적으로 받아들여 자신만의 의미로 구성하게 됩니다. 중요한 것은, 어떤 대상에 대해 이렇게 형성된 의미의 총합이 곧 그 대상에 대한 사용자 경험이 된다는 점입니다. 같은 제품을 사용하더라도 사람마다 다른 경험을 하게 되는 이유가 바로 여기에 있으며, 따라서 UX디자인 분야에서 이 인지에 대한 이해는 단순한 배경지식이 아니라 디자인의 근본적인 출발점으로서 중요합니다.&lt;/p&gt;
&lt;h2 id=&quot;인지라는-빙산&quot;&gt;인지라는 빙산&lt;/h2&gt;
&lt;p&gt;인간의 인지는 흔히 빙산으로 은유되곤 합니다.&lt;/p&gt;
&lt;p&gt;진부한 은유이지만, 무언가 수면 아래에 거대한 것이 숨어있을 때 우리는 ‘빙산의 일각’이라는 표현을 즐겨 씁니다. 인간의 인지 역시 마찬가지여서, 이 빙산의 비유는 인지의 본질을 이해하는 데 꽤 유용한 틀을 제공합니다. 빙산이 수면 위로 드러낸 부분은 전체의 극히 일부에 불과하듯, 겉으로 보이는 의식(conscious)의 영역은 인지 전체에서 차지하는 비중이 생각보다 작습니다. 오히려 수면 아래 숨어있는 무의식(subconscious)의 영역이 훨씬 더 크고 광범위하며, 우리의 판단과 반응에 깊은 영향을 미칩니다.&lt;/p&gt;
&lt;p&gt;그리고 수면 위의 빙산만 관찰해서는 그 아래에 무엇이 있는지 정확히 가늠하기 어렵듯이, 사용자의 의식적인 반응만을 관찰해서는 그 이면에 작용하는 무의식의 메커니즘을 파악하기 어렵다는 점에서 이 은유는 인지의 특성을 잘 설명합니다.&lt;/p&gt;
&lt;p&gt;더 나아가, 빙산의 수면 아래 숨은 부분에 거대한 타이타닉 호가 부딪혀 사고가 발생했듯이, 사용자 경험 역시 디자이너가 미처 파악하지 못한 사용자의 무의식적 인지 패턴에 부딪혀 예상치 못한 결과를 초래할 수 있다는 점도 유사합니다. 겉으로 보기에 아무 문제없어 보이는 디자인이 사용자에게 불편함이나 혼란을 야기하는 경우가 바로 이런 맥락에서 발생하는 것입니다.&lt;/p&gt;
&lt;p&gt;그렇기 때문에 항해사들이 소나나 수중 탐사 같은 다양한 수단을 활용해 빙산의 숨은 면을 알아내고자 하듯, UX디자인을 하는 디자이너들 또한 이 인지라는 빙산의 전체 모습을 이해하려는 노력이 필요합니다. 사용자 리서치, 행동 분석, 심리학적 이론 등 여러 수단을 활용하여 목표로 하는 사용자들이 어떤 인지 과정을 통해 경험을 형성하고 있는지, 그리고 이 과정의 어느 지점에서 어떤 방식으로 개입하고 조정해야 더 나은 경험을 만들어낼 수 있는지를 연구해야 할 필요가 있는 것입니다.&lt;/p&gt;
&lt;p&gt;물론 심도 있게 인지공학의 깊은 곳까지 파고들자면 너무도 버겁고 어려운 일이겠지만, 그렇다고 해서 인지에 대한 이해를 아예 포기할 수는 없습니다. 우선은 인지의 핵심적인 메커니즘 몇 가지를 살펴보는 것으로 시작해보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;경험을-이루는-세-가지-인지처리&quot;&gt;경험을 이루는 세 가지 인지처리&lt;/h2&gt;
&lt;p&gt;외부의 사물이 감각기관을 통해 인지되고, 이것이 다시 기억으로 저장되어, 그 기억이 새로운 정보를 처리하는 데 다시 영향을 주는 순환적 구조로 보았을 때, 이 과정에서 크게 세 가지의 주요한 인지 처리가 발생합니다. 바로 선택집중(Selective Attention), 연관짓기(Chunking), 그리고 심성모형(Mental Model)입니다.&lt;/p&gt;
&lt;p&gt;이 세 가지는 각각 정보를 받아들이는 입구에서, 정보를 조직하는 과정에서, 그리고 정보를 해석하고 활용하는 단계에서 핵심적인 역할을 합니다. 하나씩 살펴보겠습니다.&lt;/p&gt;
&lt;h3 id=&quot;선택집중selective-attention&quot;&gt;선택집중(Selective Attention)&lt;/h3&gt;
&lt;p&gt;인지의 첫 번째 관문은 선택집중입니다. 우리는 카메라나 녹음기와 달리 감각기관에 잡히는 모든 정보를 빠짐없이 받아들일 수 없습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;실제로는 카메라나 녹음기도 중심부와 주변부에서의 정보량이 달라집니다. 다만 이것은 단순히 거리로 인한 물리적 한계인 반면, 인간의 선택집중은 물리적인 영역을 넘어 인지적으로 필요 없다고 여겨지는 정보를 삭제하는 수준으로 이뤄진다는 차이가 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;우리의 인지 자원은 한정되어 있기 때문에, 특정한 부분에 집중을 기울일 때 그 영역에서 가장 밀도 있는 정보를 받아들이게 되고, 그 집중의 영역 바깥에서는 정보의 수용성이 급격히 낮아집니다. 마치 손전등으로 어두운 방을 비추는 것처럼, 빛이 닿는 곳은 선명하게 보이지만 나머지 영역은 어둠 속에 남게 되는 것입니다.&lt;/p&gt;
&lt;p&gt;이때 무엇에 집중할 것인지를 이끄는 요인은 다양한데, 우리가 가진 기호나 관심사, 정보 자체가 지닌 위험도나 긴급성, 그리고 주변의 다른 정보와의 시각적 대비 등이 대표적입니다. 일반적으로 시인성이 높을수록 집중의 선택을 받을 가능성이 높지만, 반드시 그러한 것은 아닙니다. 이 선택에는 개인이 이미 가지고 있는 기존의 기억이나 경험이 깊이 영향을 주기 때문에, 같은 화면을 보더라도 사용자에 따라 어디에 집중하는지, 무엇을 먼저 인지하는지가 상당히 달라질 수 있습니다.&lt;/p&gt;
&lt;h3 id=&quot;연관짓기chunking&quot;&gt;연관짓기(Chunking)&lt;/h3&gt;
&lt;p&gt;선택집중을 통해 걸러진 정보가 우리에게 도달했다고 해서 끝이 아닙니다. 그다음 단계에서 우리의 인지는 또 하나의 중요한 처리를 수행하는데, 바로 받아들인 정보를 의미에 따라 묶어 그 개수를 줄여서 처리하는 것입니다.&lt;/p&gt;
&lt;p&gt;이와 관련해 매우 잘 알려진 ‘법칙’ 중 하나가 매직 넘버 7(Magic Number 7)인데, 인간이 단기적으로 처리할 수 있는 정보의 개수가 7개 남짓, 즉 7 플러스마이너스 2개 정도라는 내용입니다. 이 숫자 자체에 대해서는 후속 연구들에서 이견이 많고 실제로는 더 적을 수 있다는 주장도 있지만, 여기서 정말 중요한 것은 특정 숫자가 아니라 인간의 단기적 정보 처리 능력에는 분명한 한계가 존재한다는 사실 그 자체입니다.&lt;/p&gt;
&lt;p&gt;그리고 이 한계를 극복하기 위해 우리의 인지가 자연스럽게 사용하는 전략이 바로 연관짓기(Chunking)입니다. 즉, 서로 관련 없는 낱개의 정보들을 하나하나 개별적으로 받아들이고 처리하는 데는 막대한 인지 부하(workload)가 요구되거나 아예 처리 자체가 불가능해지지만, 의미적으로 관련 있는 정보들을 하나의 덩어리로 묶어서 처리하면 인지 부하를 크게 줄일 수 있고, 결과적으로 더 많은 양의 정보를 효율적으로 처리할 수 있게 됩니다.&lt;/p&gt;
&lt;h3 id=&quot;심성모형mental-model&quot;&gt;심성모형(Mental Model)&lt;/h3&gt;
&lt;p&gt;연관짓기가 들어오는 정보를 효율적으로 묶어서 처리하는 과정이라면, 심성모형은 한 발 더 나아가 그 정보들을 하나의 체계적인 구조로 조직화하는 과정입니다. 우리는 축적된 기억과 경험을 바탕으로 특정 대상이나 상황에 대한 정보의 구조체를 만들고, 이후 새로운 정보를 접할 때 이 구조체를 틀로 삼아 정보를 받아들이고 해석합니다.&lt;/p&gt;
&lt;p&gt;예를 들어 우리는 카메라 렌즈라는 대상에 대한 정보의 구조체를 각자 가지고 있습니다. 카메라에 대한 경험이 적은 사람은 동그란 외형과 비친 사물을 투영하는 기본적인 기능 정도에 그칠 수도 있습니다. 반면 사진을 오래 찍어온 사람이라면 조리개의 작동 원리, 셔터 속도와의 관계, 다양한 필터의 효과 등 세부적인 항목까지 그 구조에 풍부하게 포함되어 있을 것입니다.&lt;/p&gt;
&lt;p&gt;마찬가지로 총이라는 대상에 대해서도 우리는 각자의 정보 구조체를 가질 수 있습니다. 어떤 사람의 구조체에는 방아쇠와 손잡이 같은 기본적인 요소만 있을 수 있고, 더 많은 경험을 가진 사람이라면 가늠자, 안전장치, 탄창 같은 세부 사항들까지 체계적으로 구조화되어 있을 수 있습니다.&lt;/p&gt;
&lt;p&gt;이렇게 렌즈와 총 각각에 대해 나름의 정보 구조를 가진 사람이, 렌즈와 총의 형태를 결합한 듯한 낯선 물건을 마주하면 어떤 일이 벌어질까요. 비록 처음 보는 물건이고 한 번도 써보지 않은 물건이지만, 기존에 가지고 있던 렌즈와 총에 대한 구조가 자동적으로 활성화되면서 이 낯선 물건의 작동 방식과 동작을 놀랍도록 정확하게 가늠할 수 있게 됩니다. 아마도 총의 형태에서 방아쇠를 당기는 동작을, 렌즈의 형태에서 사진을 찍는 기능을 연결지어, 방아쇠를 당기면 겨누어진 대상의 사진이 찍힐 것으로 예상할 것입니다.&lt;/p&gt;
&lt;p&gt;이전에 접한 적 없는 대상임에도 불구하고 이런 유추가 가능한 것은, 우리의 인지가 과거의 경험을 바탕으로 만들어 놓은 정보의 구조체를 능동적으로 활용하기 때문입니다. 이러한 정보의 구조체가 바로 심성모형(Mental Model)입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;다음 글에서는 지금까지 살펴본 선택집중·연관짓기·심성모형이라는 세 가지 인지처리 방식이 실제 디자인에 어떤 구체적인 의미를 갖는지, 그리고 심성모형과 밀접하게 맞닿아 있는 개념인 어포던스(행동유도성)란 무엇인지를 다룹니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>인지심리학</category><category>심성모형</category><category>사용자 경험</category></item><item><title>프롬프트 엔지니어링 — AI에게 원하는 걸 정확히 얻어내는 법</title><link>https://blog.bepuljang.co.kr/vibecoding/07/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/07/</guid><description>좋은 프롬프트를 쓰는 실전 기술 — 구체성·맥락·범위, 그리고 원하는 결과를 얻어내는 다섯 가지 프롬프트 기법을 정리합니다.</description><pubDate>Wed, 08 Jul 2026 15:06:46 GMT</pubDate><content:encoded>&lt;p&gt;4편에서 아이디어를 프롬프트로 바꿔 첫 화면을 만들어봤습니다. 바이브코딩을 이어가다 보면 금방 깨닫는 사실이 하나 있습니다. &lt;strong&gt;결과물의 품질은 결국 “어떻게 요청하느냐”가 가른다&lt;/strong&gt;는 것입니다. 같은 도구, 같은 AI라도 프롬프트를 어떻게 쓰느냐에 따라 결과가 크게 달라집니다.&lt;/p&gt;
&lt;p&gt;이 편에서는 좋은 프롬프트를 쓰는 실전 기술, 이른바 &lt;strong&gt;프롬프트 엔지니어링&lt;/strong&gt;을 다룹니다. 이름은 거창하지만 핵심은 단순합니다. &lt;strong&gt;유능한 동료에게 일을 잘 맡기는 법&lt;/strong&gt;과 다르지 않습니다. 계속해서 북마크 앱을 예제로 사용합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;좋은-프롬프트의-세-가지-조건&quot;&gt;좋은 프롬프트의 세 가지 조건&lt;/h2&gt;
&lt;p&gt;좋은 프롬프트와 나쁜 프롬프트를 가르는 것은 세 가지입니다. &lt;strong&gt;구체성 · 맥락 · 범위.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;구체성&lt;/strong&gt; — 무엇을, 어떤 형태로 원하는지 분명히 적는다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;맥락&lt;/strong&gt; — 지금 프로젝트가 어떤 상태인지 함께 알려준다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;범위&lt;/strong&gt; — 한 번에 어디까지 할지 정한다.&lt;/li&gt;
&lt;/ul&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;프롬프트 예시&lt;/th&gt;&lt;th&gt;결과&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;나쁜 프롬프트&lt;/td&gt;&lt;td&gt;”북마크 앱에 기능 좀 추가해줘”&lt;/td&gt;&lt;td&gt;무슨 기능인지, 어떻게 생겼으면 하는지 AI가 알 수 없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;좋은 프롬프트&lt;/td&gt;&lt;td&gt;아래 기법 참고&lt;/td&gt;&lt;td&gt;무엇을·어떤 맥락에서·어디까지 할지 명확&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이제 이 세 조건을 실제 프롬프트로 옮기는 다섯 가지 기법을 살펴봅니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기법-1-한-번에-하나씩&quot;&gt;기법 1. 한 번에 하나씩&lt;/h2&gt;
&lt;p&gt;가장 먼저 지켜야 할 원칙은 &lt;strong&gt;한 번에 하나씩&lt;/strong&gt;입니다. 경험이 없으면 “태그 기능이랑 검색이랑 정렬 다 추가해줘”처럼 한꺼번에 요청하고 싶어집니다. 하지만 이 방식은 문제를 만들기 좋습니다.&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;방식&lt;/th&gt;&lt;th&gt;겉보기&lt;/th&gt;&lt;th&gt;실제&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;한 번에 여러 기능&lt;/td&gt;&lt;td&gt;빠를 것 같음&lt;/td&gt;&lt;td&gt;코드가 얽혀 나중에 수정하기 어렵고, 에러가 나도 원인 파악이 힘듦&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;하나씩 단계별&lt;/td&gt;&lt;td&gt;느릴 것 같음&lt;/td&gt;&lt;td&gt;각 단계에서 결과를 확인할 수 있고, 문제가 생기면 원인이 명확함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;오히려 하나씩 요청하는 편이 &lt;strong&gt;전체 속도는 더 빠릅니다.&lt;/strong&gt; 버그가 어디서 생겼는지 바로 알 수 있어 고치는 시간이 훨씬 줄어들기 때문입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기법-2-맥락을-구조화해서-준다&quot;&gt;기법 2. 맥락을 구조화해서 준다&lt;/h2&gt;
&lt;p&gt;AI는 지금 프로젝트가 어떤 상태인지 자동으로 다 알지 못합니다. 그래서 요청할 때 맥락을 함께 줘야 합니다. 다음 네 부분으로 나눠 쓰면 좋습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[현재 상태]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;지금 북마크 앱에는 URL과 제목을 저장하고 목록으로 보여주는 기능이 있어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;데이터는 localStorage에 저장돼 있고, 각 북마크는 { id, url, title } 구조야.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[추가할 기능]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;태그 기능을 추가하고 싶어. 북마크를 저장할 때 태그를 여러 개 달 수 있고,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;목록에서 태그를 클릭하면 해당 태그의 북마크만 필터링되게 해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[데이터 구조 변경]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;기존 북마크 데이터에 tags: [] 배열을 추가해줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;기존 데이터는 tags가 없으면 빈 배열로 처리하면 돼.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[범위 제한]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;이것만 먼저 해줘. 태그 편집이나 삭제는 나중에 추가할 거야.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 &lt;strong&gt;현재 상태 → 원하는 것 → 데이터 변경 → 범위 제한&lt;/strong&gt; 순서로 쓰면, AI가 기존 코드와 충돌 없이 원하는 대로 만들어줄 확률이 크게 올라갑니다. 프로젝트 구조를 &lt;code&gt;CLAUDE.md&lt;/code&gt;에 정리해뒀다면(3편), ‘현재 상태’는 “CLAUDE.md 참고해서”라는 한 줄로 대신할 수도 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기법-3-원하는-형태를-예시로-보여준다&quot;&gt;기법 3. 원하는 형태를 예시로 보여준다&lt;/h2&gt;
&lt;p&gt;말로 설명하기 어려운 것은 &lt;strong&gt;예시 하나가 백 마디 말보다 낫습니다.&lt;/strong&gt; 원하는 출력 형식이나 스타일이 분명하다면, 설명 대신 예시로 보여주세요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;삭제 버튼을 이런 형태로 바꿔줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- 위치: 카드 오른쪽 위 모서리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- 모양: 회색 × 아이콘, 마우스를 올리면 빨갛게&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;결과 형식을 지정할 때: “결과를 이런 표 형식으로 정리해줘”라고 하고 예시 한 줄을 붙인다.&lt;/li&gt;
&lt;li&gt;기존 것과 맞추고 싶을 때: “BookmarkCard 컴포넌트와 같은 스타일로 만들어줘”처럼 참고 대상을 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI는 추상적인 지시보다 &lt;strong&gt;구체적인 본보기&lt;/strong&gt;를 훨씬 잘 따라옵니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기법-4-모르면-되묻게-만든다&quot;&gt;기법 4. 모르면 되묻게 만든다&lt;/h2&gt;
&lt;p&gt;모든 걸 완벽하게 정해서 던질 필요는 없습니다. 오히려 애매한 부분은 &lt;strong&gt;AI가 되묻게 만드는 편&lt;/strong&gt;이 낫습니다. 실제 사람과 협업하듯, 결정을 함께 내려가는 방식입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;로그인 기능을 붙이고 싶은데, 방식(이메일/소셜)이나 저장 위치는 아직 못 정했어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;선택지와 장단점을 먼저 정리해주고, 결정이 필요한 부분은 나한테 물어봐줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;“확실하지 않은 부분이 있으면 먼저 물어봐줘.” 이 한 줄을 붙이면, AI가 임의로 결정하고 밀어붙이는 대신 확인 질문을 던집니다. 잘못된 전제 위에 코드가 쌓이는 것을 막아줍니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기법-5-안-되면-끊고-방향을-다시-잡는다&quot;&gt;기법 5. 안 되면 끊고 방향을 다시 잡는다&lt;/h2&gt;
&lt;p&gt;AI가 엉뚱한 방향으로 가기 시작하면, 끝까지 지켜보지 말고 &lt;strong&gt;바로 중단&lt;/strong&gt;시키는 게 낫습니다. 잘못된 코드가 쌓일수록 되돌리기 어렵습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;중단시키고, 무엇이 어긋났는지 짚어 교정 프롬프트를 줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;방금 방향이 내 의도와 달라. 나는 X를 원했는데 너는 Y로 갔어.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X를 기준으로 다시 해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;대화가 너무 길어져 맥락이 흐트러졌다면, &lt;code&gt;/clear&lt;/code&gt;로 대화를 초기화하고 CLAUDE.md를 바탕으로 새로 시작하는 것도 방법입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정리-좋은-프롬프트는-좋은-위임이다&quot;&gt;정리: 좋은 프롬프트는 좋은 위임이다&lt;/h2&gt;
&lt;p&gt;프롬프트 엔지니어링이라고 하면 뭔가 특별한 기술 같지만, 결국 &lt;strong&gt;일을 잘 맡기는 법&lt;/strong&gt;입니다. 유능한 동료에게 일을 부탁한다고 생각하면 됩니다. 무엇을 원하는지 구체적으로, 지금 상황이 어떤지 맥락과 함께, 한 번에 감당할 만큼만, 애매하면 되물어가며.&lt;/p&gt;
&lt;p&gt;이 감각이 손에 붙으면 같은 AI로도 훨씬 나은 결과를 얻게 됩니다. 프롬프트는 바이브코딩에서 가장 오래 쓰는 도구이자, 가장 크게 실력 차이가 나는 부분입니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 로컬에서만 동작하던 앱을 인터넷에 공개하는 방법, 즉 배포를 다룹니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>바이브코딩</category><category>Claude Code</category><category>프롬프트</category><category>프롬프트 엔지니어링</category></item><item><title>내적으로 명확한 비전이 제시되지 않는 위험에 대하여</title><link>https://blog.bepuljang.co.kr/startup-prince/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/startup-prince/01/</guid><description>마키아벨리의 『군주론』을 스타트업에 옮겨 읽는 시리즈, 그 첫 번째 이야기입니다. 비전이 없는 게 아니라 명확하게 제시되지 않은 위험이 어떻게 조직을 각자 다른 방향으로 흩어놓는지 살펴봅니다.</description><pubDate>Tue, 07 Jul 2026 16:52:33 GMT</pubDate><content:encoded>&lt;p&gt;마키아벨리는 『군주론』에서 권력을 얻고 지키는 법을 논했습니다. 그가 관찰한 군주들은 전쟁으로, 혼인으로, 때로는 순전한 운으로 영토를 얻었습니다. 그러나 그 영토를 오래 다스린 군주는 소수였습니다. 얻는 것과 지키는 것은 전혀 다른 문제였기 때문입니다.&lt;/p&gt;
&lt;p&gt;스타트업도 다르지 않습니다. 아이디어 하나로, 혹은 좋은 타이밍 하나로 사업을 시작하는 일은 상대적으로 쉽습니다. 어려운 것은 그것을 오래 지속 가능한 조직으로 키워내는 일입니다. 이 시리즈 『스타트업 군주론』은 그 사이에서 사업이 무너지는 여러 방식을 다룹니다. 겉보기에는 성장처럼 보이지만 실은 불안정한 근간 위에 선 것들, 조직을 이끄는 방식에서 벌어지는 오해들, 그리고 지켜야 할 것을 지키지 못해 무너지는 순간들까지—군주론의 틀을 빌려 하나씩 짚어보려 합니다.&lt;/p&gt;
&lt;p&gt;첫 번째로 다룰 위험은 가장 흔하면서도 가장 늦게 발견되는 것입니다. 비전이 없는 게 아니라, 비전이 명확하게 제시되지 않은 위험입니다.&lt;/p&gt;
&lt;h2 id=&quot;다들-열심인데-왜-다른-곳을-보고-있을까&quot;&gt;다들 열심인데, 왜 다른 곳을 보고 있을까&lt;/h2&gt;
&lt;p&gt;겉에서 보면 이상할 것이 없는 조직입니다. 개발팀은 밤늦게까지 기능을 쌓고, 세일즈팀은 매일 새로운 미팅을 잡고, 마케팅팀은 매주 캠페인을 돌립니다. 누구 하나 게으르지 않습니다. 오히려 다들 지나치게 열심입니다.&lt;/p&gt;
&lt;p&gt;문제는 그 열심의 방향입니다. 개발팀은 다음 분기 안에 기능을 최대한 많이 출시하는 것을 목표로 움직입니다. 세일즈팀은 계약 건수를 늘리는 데 집중합니다. 마케팅팀은 트래픽과 가입자 수를 최적화합니다. 셋 다 각자의 관점에서는 회사를 위해 최선을 다하고 있습니다. 그러나 반년이 지나고 나면, 기능은 많아졌는데 정작 핵심 사용자가 원하는 문제는 여전히 풀리지 않았고, 계약은 늘었는데 이탈률도 함께 늘었고, 가입자는 늘었는데 활성 사용자는 그대로인 상황을 마주하게 됩니다.&lt;/p&gt;
&lt;p&gt;누구도 잘못하지 않았습니다. 각자에게 주어진 목표를 성실히 좇았을 뿐입니다. 문제는 그 목표들이 애초에 하나의 방향을 가리키고 있지 않았다는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;군주의-목표가-불분명할-때-신하는-각자-해석한다&quot;&gt;군주의 목표가 불분명할 때, 신하는 각자 해석한다&lt;/h2&gt;
&lt;p&gt;『군주론』에서 마키아벨리가 반복해서 강조하는 것 중 하나는, 군주의 의도가 신하들에게 명확히 전달되어야 한다는 점입니다. 군주가 원하는 것이 영토의 확장인지, 안정적인 통치인지, 백성의 신망인지가 불분명하면, 신하들은 각자의 판단으로 그 공백을 채우기 시작합니다. 어떤 신하는 정복을 위해 무리하게 세금을 걷고, 어떤 신하는 안정을 위해 필요한 변화조차 미룹니다. 군주는 한 나라를 다스리고 있다고 생각하지만, 실제로는 여러 개의 서로 다른 나라가 그의 이름 아래 따로 운영되고 있는 셈입니다.&lt;/p&gt;
&lt;p&gt;스타트업의 창업자도 정확히 같은 위치에 있습니다. 창업자의 머릿속에는 분명한 그림이 있습니다. 다만 그 그림이 문서로, 대화로, 반복되는 언어로 조직 전체에 새겨지지 않았을 뿐입니다. 창업자는 자신이 이미 비전을 여러 번 말했다고 생각합니다. 실제로 그랬을 수도 있습니다. 그러나 그 비전이 각 팀의 일상적인 의사결정 앞에서 구체적인 기준으로 작동하고 있는지는 전혀 다른 문제입니다.&lt;/p&gt;
&lt;h2 id=&quot;비전은-선언문이-아니라-의사결정의-기준이다&quot;&gt;비전은 선언문이 아니라 의사결정의 기준이다&lt;/h2&gt;
&lt;p&gt;여기서 흔히 발생하는 오해가 있습니다. 비전을 한 문장으로 근사하게 정리해서 벽에 붙이거나 회사 소개서 첫 페이지에 넣으면, 비전 제시가 완료됐다고 여기는 것입니다. “세상을 더 편리하게 만든다”거나 “모두를 위한 금융을 만든다” 같은 문장은 듣기에 좋고 투자자 앞에서 발표하기에도 매끄럽습니다. 그러나 이런 문장이 실제 업무 현장에서 구체적인 질문에 답을 주지는 못합니다.&lt;/p&gt;
&lt;p&gt;진짜 비전은 이런 질문 앞에서 시험대에 오릅니다. 이번 분기에 신규 기능과 기존 기능 안정화 중 어디에 자원을 더 투입해야 하는가. 매출은 늘지만 우리가 정의한 핵심 사용자층에서 벗어난 고객 세그먼트를, 계속 쫓아야 하는가 포기해야 하는가. 성장 속도를 조금 늦추더라도 팀 문화를 지키는 결정을 내려야 하는 순간이 온다면, 그때 무엇을 우선할 것인가. 이런 질문에 대해 조직의 여러 사람이 비슷한 답을 낼 수 있다면, 비전이 제대로 전달되고 있다는 뜻입니다. 반대로 같은 질문에 부서마다 전혀 다른 답이 나온다면, 아무리 근사한 문장이 벽에 붙어 있어도 비전은 아직 조직 안에 살아있지 않은 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;암묵적-합의라는-착각&quot;&gt;암묵적 합의라는 착각&lt;/h2&gt;
&lt;p&gt;초기 스타트업에서 특히 자주 나타나는 함정은 “빠른 성장”이라는 말에 모두가 동의했다는 이유로, 비전이 이미 공유되었다고 믿는 것입니다. 그러나 “빠른 성장”은 그 자체로 아무것도 규정하지 않는 말입니다. 매출의 성장인지, 사용자 수의 성장인지, 브랜드 인지도의 성장인지에 따라 각 팀이 최적화해야 할 지표는 완전히 달라집니다.&lt;/p&gt;
&lt;p&gt;창업 초기, 팀의 규모가 작을 때는 이런 모호함이 크게 드러나지 않습니다. 창업자가 거의 모든 결정에 직접 관여하기 때문에, 방향이 어긋나도 창업자 한 사람의 판단으로 즉시 교정됩니다. 문제는 조직이 커지고 각 팀이 독립적으로 의사결정을 내리기 시작하는 순간부터입니다. 이때부터는 창업자 머릿속의 그림이 아니라, 각 팀이 실제로 이해하고 있는 목표가 조직의 방향을 결정합니다. 그리고 그 순간까지 비전이 명문화되지 않았다면, 팀마다 서로 다른 지표를 좇으며 조직은 여러 방향으로 조용히 흩어지기 시작합니다.&lt;/p&gt;
&lt;p&gt;이 흩어짐은 눈에 잘 보이지 않습니다. 각 팀의 실적 보고서는 여전히 개별적으로는 긍정적이기 때문입니다. 문제가 뚜렷하게 드러나는 것은 한참 뒤, 그 개별적인 성과들을 모두 합쳐 봐도 회사가 원래 가고자 했던 곳에 가까워지지 않았다는 사실을 깨닫는 시점입니다.&lt;/p&gt;
&lt;h2 id=&quot;비전을-명문화한다는-것&quot;&gt;비전을 명문화한다는 것&lt;/h2&gt;
&lt;p&gt;비전을 명확히 한다는 것은 근사한 슬로건을 만드는 작업이 아닙니다. 그것은 조직의 의사결정 앞에 놓일 구체적인 우선순위와 기준을 세우고, 그것을 반복해서 검증하는 작업입니다. 이번 분기의 우선순위는 무엇인가, 그 우선순위에 따르면 지금 눈앞의 선택 중 어느 것을 골라야 하는가, 그리고 여러 팀이 각자 내린 선택이 같은 방향을 가리키고 있는가를 창업자가 주기적으로 확인해야 합니다.&lt;/p&gt;
&lt;p&gt;이것은 한 번의 선언으로 끝나는 일이 아니라, 조직이 성장하는 동안 계속 반복되어야 하는 작업입니다. 군주가 신하들에게 자신의 목표를 명확히 전달하지 않으면, 신하들은 각자의 최선을 다해 서로 다른 나라를 만듭니다. 창업자가 조직에 자신의 비전을 계속해서 구체적으로 새기지 않으면, 팀들은 각자의 최선을 다해 서로 다른 회사를 만듭니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 이와 짝을 이루는 또 다른 위험을 다룹니다. 비전을 오해한 나머지 돈을 목표로 삼았을 때, 사업이 겪게 되는 어려움에 대한 이야기입니다.&lt;/p&gt;</content:encoded><category>스타트업 군주론</category><category>스타트업</category><category>창업</category><category>비전</category><category>스타트업 군주론</category></item><item><title>사용성, 편의성, 감성 — UX디자인이 실제로 다루는 세 가지 파라미터</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/05/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/05/</guid><description>UX디자인이 실제로 조정할 수 있는 세 가지 파라미터인 사용성, 편의성, 감성을 각각 정의하고, 이들 사이에 존재하는 트레이드오프를 구체적인 사례로 살펴봅니다.</description><pubDate>Tue, 07 Jul 2026 15:45:16 GMT</pubDate><content:encoded>&lt;p&gt;앞선 글에서는 UX 피라미드가 사용자 경험을 이루는 여섯 가지 속성 — 기능성, 신뢰성, 사용성, 편의성, 감성, 의미성 — 으로 구성되며, 이 중 UX디자인이 실질적으로 다룰 수 있는 영역은 가운데 층에 위치한 사용성·편의성·감성 세 가지라는 점을 확인했습니다. 이제 이 세 가지 파라미터 각각에 대해 좀 더 자세히 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;사용자-경험을-디자인하는-3가지-파라미터&quot;&gt;사용자 경험을 디자인하는 3가지 파라미터&lt;/h2&gt;
&lt;p&gt;먼저 사용성(Usability)입니다. 앞서 사용성은 정량적으로 지표화할 수 있는 객관적인 속성으로 분류된다고 말씀드렸습니다. 사용성이 측정하는 것은 사용자가 특정 기능을 수행하기까지 거쳐야 하는 과업의 단계와 그 복잡도입니다. 좀 더 구체적으로 말하면, 어떤 기능을 수행하는 데 있어서 사용자가 거치는 인지 절차의 단계(depth)나 과업(task)의 개수가 얼마나 소요되는지, 그리고 해당 기능이 제공하는 효용에 비해 투입되는 인지적 자산이 적절한지를 보는 것입니다. 사용성은 이러한 특성 덕분에 비교적 명확하게 수치화할 수 있다는 장점이 있습니다.&lt;/p&gt;
&lt;p&gt;예를 들어 어떤 가상의 서비스에서 ‘DM(Direct Message) 보내기’라는 활동에 ‘홈으로 이동’ &gt; ‘DM 아이콘 누르기’ &gt; ‘메시지 쓰기’ &gt; ‘보낼 사람 고르기’ &gt; ‘보내기 누르기’ &gt; ‘확인하기’와 같은 여섯 단계의 작업이 요구될 수 있습니다. 이 여섯 단계가 ‘DM 보내기’라는 기능의 효용에 비해 과도한 것인지, 적절한 것인지를 판단하는 것이 바로 사용성의 영역입니다.&lt;/p&gt;
&lt;p&gt;사용성이 ‘얼마나 많은 단계를 거쳐야 하는가’의 문제라면, 그다음 파라미터인 편의성(Conveniency)은 ‘그 단계들이 얼마나 자연스럽게 느껴지는가’의 문제입니다. 편의성은 주관적이고 정성적인 속성으로, ‘사용자가 기능을 쉽게 수행할 수 있는 정도’를 의미합니다. 설명만 보면 사용성과 혼동하기 쉽지만, 내용을 들여다보면 분명히 구별됩니다.&lt;/p&gt;
&lt;p&gt;차이를 이해하기 위해 구체적인 예를 들어보겠습니다. 우리가 ‘저장하기’라는 기능을 찾을 때 보통 ‘파일’이라는 구분 요소를 먼저 찾게 되는 것은, 이 둘이 개념적으로도 관련되어 있고 일반적으로도 함께 묶여 있기 때문입니다. 이것은 사용자의 기존 경험과 인지적 기대에 부합하는 구조입니다. 만약 ‘저장하기’가 ‘파일’ 대신 ‘도구’나 ‘편집’에 속해 있다면 사용자는 이 기능을 찾고 수행하는 데 어려움을 겪을 것입니다. 단계의 수 자체는 동일하더라도, 각 단계에서 사용자가 느끼는 인지적 부담은 전혀 달라지는 것입니다.&lt;/p&gt;
&lt;p&gt;편의성은 이처럼 구조와 배치가 사용자의 기대와 얼마나 부합하는지, 즉 얼마나 이해하기 쉬운지에 더 가까운 지표입니다. 같은 수의 단계라 하더라도 편의성이 높으면 사용자는 “쉽다”고 느끼고, 편의성이 낮으면 “복잡하다”고 느끼게 됩니다.&lt;/p&gt;
&lt;p&gt;마지막 파라미터인 감성(Pleasurability)은 사용자가 디자인을 통해 느끼는 정서적 만족도로, 우리가 디자인에 대해 흔히 떠올리는 심미적 가치와 크게 다르지 않습니다. 시각적인 아름다움, 인터랙션에서 느껴지는 즐거움, 브랜드가 전달하는 감성적 톤 등이 모두 이 영역에 속합니다. 세 가지 파라미터 중 피라미드 상 가장 상위에 있는 만큼 다루기 어려운 속성이지만, 흥미롭게도 디자이너들이 수세기 동안 해온 본연적인 작업 — 아름다움을 만들어내고 감정을 불러일으키는 조형적 작업 — 과 가장 닮아 있어 오히려 비교적 쉽게 달성되곤 합니다.&lt;/p&gt;
&lt;p&gt;다만 여기서 한 가지 주의해야 할 점이 있습니다. 경험은 시공간적으로 흐르며, 인지적 절차의 통합으로 형성됩니다. 하나의 화면이 아무리 아름다워도, 그것이 전체 사용 흐름 속에서 이질적이거나 앞뒤 맥락과 단절된다면 오히려 사용자의 정서적 경험을 해칠 수 있습니다. 때문에 이 감성적인 작업에서는 개별 요소의 완성도뿐 아니라 그 통합의 과정을 면밀히 살피고, 사용자가 거치는 전반적인 여정 자체를 하나의 정서적 흐름으로서 주의 깊게 관리할 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;이상의 내용을 종합하면, UX디자인은 이 세 가지 파라미터를 적절히 조정하여 목표하는 경험에 부합하도록 맞추는 작업이라고 정의할 수 있습니다. 여기서 한 가지 주목할 점은, 이 셋 중 두 가지 — 편의성과 감성 — 가 주관적인 가치라는 것입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;사용자에 따라 경험의 깊이, 문화적 배경, 취향과 선호도가 다르기 때문에, 편의성과 감성은 사용자를 어떻게 정의하느냐에 따라 완전히 다르게 해석될 수 있습니다. 누군가에게 직관적인 것이 다른 누군가에게는 낯설 수 있고, 누군가에게 아름다운 것이 다른 누군가에게는 불편할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결국 파라미터의 ‘적절한 조정’이란 보편적인 정답이 아니라, 특정 사용자 집단에 대한 깊은 이해를 전제로 한 맥락적 판단입니다. 앞서 이 시리즈에서 UX디자인을 선언하며 사용자에 대한 딥 다이브(deep dive)를 강조했던 것은 바로 이러한 이유 때문입니다. 시장 조사에서 다루는 소비자 관점이 아니라, 실제로 제품을 사용하는 사용자의 관점에서 보다 정성적이고 질적인 시각으로 그들을 파악해야, 비로소 의미 있는 사용자 경험을 설계하고 안착시킬 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;새로운-파라미터를-목표에-맞춰-조작하는-공정&quot;&gt;새로운 파라미터를 목표에 맞춰 조작하는 공정&lt;/h2&gt;
&lt;p&gt;이 지점에서 흔히 빠지기 쉬운 함정이 있습니다. ‘절차를 줄이면 효용성이 올라간다’, ‘직관적으로 만들면 편의적이다’, ‘깔끔하고 간결하면 예쁘다’라는 문장들은 단편적으로 보면 모두 맞는 말입니다. 하지만 이 세 가지 지표를 동시에 극대화하려 하거나, 모든 사용자를 만족시키는 이상적인 방향을 찾으려 하면 자칫 목표를 잃고 오히려 사용자 경험을 망치게 될 수 있습니다. 파라미터 간에는 필연적으로 트레이드오프(trade-off)가 존재하며, 하나를 높이면 다른 하나가 낮아지는 경우가 빈번하기 때문입니다.&lt;/p&gt;
&lt;p&gt;구체적인 예를 들어보겠습니다. 어떤 사용자는 모바일 기기를 흔드는 액션이 익숙하고 절차를 줄여준다고 생각할 수 있는 반면, 다른 사용자는 흔들기라는 조작 자체를 떠올리지 못해 명시적인 긴 절차를 거치는 것보다 훨씬 더 큰 어려움을 겪을 수 있습니다. 사용성을 높이려 한 선택이 편의성을 오히려 떨어뜨린 셈입니다.&lt;/p&gt;
&lt;p&gt;마찬가지로 어떤 사용자는 아이콘만으로 정리된 사용자 인터페이스에서 간결함과 미적 쾌감을 느낄 수도 있지만, 다른 사용자는 텍스트 레이블 없이는 각 아이콘이 무엇을 의미하는지 파악하기 어려워 오히려 좌절감을 느낄 수도 있습니다. 감성을 높이려 한 선택이 편의성을 저해한 경우입니다. 때문에 세 파라미터 사이에서 적절한 균형점을 찾는 것이 중요하며, 그 답은 결국 우리가 어떤 사용자의 어떠한 경험을 목표로 하느냐에 달려 있습니다.&lt;/p&gt;
&lt;p&gt;사용자 경험은 단순히 숫자로만 계산할 수 있는 문제가 아닙니다. 예를 들어 최근 자동차의 기어 조작 방식이 물리적 레버에서 다이얼이나 버튼식으로 바뀐 사례를 떠올려 보면 이해가 쉽습니다. 다이얼이나 버튼 방식은 공간을 절약하고 조작 단계를 단순화하지만, 오랜 기간 레버 조작에 익숙했던 운전자에게는 오히려 낯설고 불안한 조작으로 느껴질 수 있습니다. 동일한 변화가 누군가에게는 사용성의 개선이지만, 다른 누군가에게는 편의성의 후퇴가 되는 것입니다.&lt;/p&gt;
&lt;p&gt;이 점을 좀 더 깊이 생각해보면, 개별 사용자들은 저마다 자신만의 기존 경험과 가치관, 선호도, 그리고 디지털 리터러시 수준 등을 가지고 있습니다. 이러한 개인적 맥락들이 복합적으로 버무려져 새로운 제품이나 서비스에 대한 인식과 평가를 낳습니다. 같은 인터페이스를 보더라도 누군가는 “직관적이다”라고 느끼고 누군가는 “낯설다”고 느끼는 이유가 여기에 있습니다.&lt;/p&gt;
&lt;p&gt;UX디자인의 역할은 바로 이 다양한 사용자들 중에서 목표로 하는 사용자 집단을 골라내어 가시화하고, 그들의 경험과 가치관, 선호도를 깊이 이해한 위에서 목표하는 경험을 실현할 수 있도록 사용자 경험의 파라미터를 적절하게 조정하고 제시하는 데 있습니다.&lt;/p&gt;
&lt;p&gt;이를 실무적으로 풀어보면 이런 모습이 됩니다. 복잡하게 얽힌 기능들의 구성체에서 개별 기능이 제공하는 효용성과, 사용자들이 ‘직관적’이라고 느낄 만큼 충분한 인지적 단서를 배치하고, 전체적인 미감을 잘 버무려서, 사용자가 투입하는 노력의 대가로 적절한 보상(기능)을 제공하는 것입니다. 동시에 그 사용 과정이 어느 한 지점에서 튀거나 끊기지 않고, 처음부터 끝까지 정서적인 여정이 일관되게 흘러가며 목표한 경험 가치를 제공하도록 이끌어가는 것 — 좋은 UX디자인을 판단하는 기준은 바로 이러한 것들일 것입니다.&lt;/p&gt;
&lt;p&gt;지금까지 UX디자인의 세 가지 파라미터를 살펴보고, 이들을 어떻게 조정해야 하는지에 대해 이야기했습니다. 그런데 여기서 한 걸음 더 나아가 근본적인 질문을 던져볼 필요가 있습니다. 사용성과 편의성, 감성이라는 세 파라미터가 궁극적으로 좌우되는 곳은 과연 어디일까요? 절차의 수가 적절한지, 구조가 직관적인지, 미감이 부합하는지를 판단하는 것은 화면 위의 픽셀이 아니라, 결국 그것을 받아들이는 사용자의 머릿속입니다. 디자이너가 아무리 정교하게 파라미터를 조정하더라도, 그것이 사용자의 인지 과정에서 어떻게 처리되는지를 모른다면 그 조정은 근거 없는 감(感)에 의존할 수밖에 없습니다.&lt;/p&gt;
&lt;p&gt;파라미터를 조정한다는 것은 곧 사용자의 인지에 개입한다는 것이며, 따라서 UX디자이너에게는 이 인지가 어떤 원리로 작동하는지를 이해하는 것이 필수적인 역량이 됩니다. 다음 글에서는 이 인지(Cognition)의 구조 속으로 들어가, 사용자의 머릿속에서 실제로 어떤 일이 벌어지는지를 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용성</category><category>편의성</category><category>감성</category></item><item><title>MCP란 무엇인가 — AI가 도구와 대화하는 법</title><link>https://blog.bepuljang.co.kr/vibecoding/06/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/06/</guid><description>MCP(Model Context Protocol)의 개념과, Claude Code에 외부 도구를 연결하는 방법을 단계별로 설명합니다.</description><pubDate>Tue, 07 Jul 2026 15:45:16 GMT</pubDate><content:encoded>&lt;p&gt;지금까지 Claude Code를 설치하고, CLAUDE.md로 맥락을 기록하고, 첫 화면을 만들고, 프로젝트를 성장시키는 과정에서의 주의사항까지 살펴봤습니다. 이번 편에서는 AI가 외부 도구와 연결되어 더 강력하게 일할 수 있도록 해주는 &lt;strong&gt;MCP(Model Context Protocol)&lt;/strong&gt; 를 소개하고자 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;mcp란-무엇인가&quot;&gt;MCP란 무엇인가&lt;/h2&gt;
&lt;p&gt;MCP라는 말을 이해하기 위해, 먼저 모델(Model)과 프로토콜(Protocol)이라는 말을 살펴보겠습니다. 여기서 말하는 ‘모델’은 인공지능 업계에서 사용되는 인공지능 개체를 말합니다. 즉, ‘언어 모델(LM; Language Model)‘과 같은 단어에서 쓰이는 모델과 같습니다. 그리고 ‘프로토콜’이란 서로 다른 시스템 간에 통신을 위한 약속, 규약을 의미합니다. 즉, MCP란 모델(Model)에게 맥락(Context)을 공급하는 규약(Protocol)입니다.&lt;/p&gt;
&lt;p&gt;이 MCP는 2024년 말 Claude를 개발한 Anthropic이 공개한 모델 소통 방식인데, 현재는 업계의 표준 방식으로 Claude Code뿐만 아니라 다양한 AI 도구에서 지원하고 있습니다. MCP를 연결하면 AI가 외부 서비스(문서 사이트, 브라우저, 데이터베이스, 협업 도구 등)의 정보를 직접 가져오거나 작업을 수행할 수 있어, 도구와 데이터가 유기적으로 통합된 시스템으로 일하게 됩니다.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;MCP 없을 때&lt;/th&gt;&lt;th&gt;MCP 있을 때&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;AI가 알 수 있는 것&lt;/td&gt;&lt;td&gt;대화 내용, 열린 파일&lt;/td&gt;&lt;td&gt;외부 서비스 데이터까지 포함&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;작업 방식&lt;/td&gt;&lt;td&gt;코드만 작성&lt;/td&gt;&lt;td&gt;외부 서비스 조회·수정 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;예시&lt;/td&gt;&lt;td&gt;”이 함수 고쳐줘&quot;&lt;/td&gt;&lt;td&gt;&quot;이 라이브러리 최신 문서 찾아서 그대로 적용해줘”&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;즉 MCP는 AI에게 손과 눈을 더 달아주는 확장 슬롯이라고 볼 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;어떤-mcp를-붙일-수-있나&quot;&gt;어떤 MCP를 붙일 수 있나&lt;/h2&gt;
&lt;p&gt;MCP 서버는 종류가 다양합니다. 바이브코딩을 막 시작한 단계에서 특히 유용한 대표적인 예시입니다.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;MCP 서버&lt;/th&gt;&lt;th&gt;하는 일&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Context7&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;라이브러리·프레임워크의 최신 공식 문서를 가져와 정확한 사용법으로 코드 작성&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Playwright&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;실제 브라우저를 열어 만든 화면을 클릭·입력하며 동작 테스트&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Filesystem&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;지정한 폴더의 파일을 읽고 쓰기&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GitHub&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;이슈·PR 조회, 저장소 정보 확인&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 외에도 데이터베이스, 디자인 도구, 프로젝트 구조 추적 서비스 등 다양한 MCP가 있습니다. 앞선 글에서 &lt;a href=&quot;https://app.umtri.io&quot;&gt;Umtri.io&lt;/a&gt;를 소개하며 MCP를 언급했는데, 이를 연결하면 AI가 등록된 노드 구조·버그·이력을 직접 확인하고 새 계획에 반영하는 일까지 하나의 서비스처럼 이어서 처리할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claude-code에-mcp-연결하기&quot;&gt;Claude Code에 MCP 연결하기&lt;/h2&gt;
&lt;p&gt;연결은 터미널에서 &lt;code&gt;claude mcp add&lt;/code&gt; 명령으로 합니다. 서버마다 연결 방식(로컬에서 실행 또는 원격 URL 접속)이 조금씩 다른데, 공식 문서나 해당 서비스의 안내에 명령어가 그대로 나와 있습니다.&lt;/p&gt;
&lt;p&gt;예를 들어 원격 서버(HTTP 방식)를 붙이는 형태는 이렇습니다. &lt;code&gt;YOUR_TOKEN&lt;/code&gt; 부분은 로그인이 필요한 서비스에서 발급받는 토큰입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; mcp&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;름&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --transport&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; http&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --url&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; https://example.com/mcp&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;  --header&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Authorization: Bearer YOUR_TOKEN&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;로컬에서 실행하는 서버라면 이런 형태가 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; mcp&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;름&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; npx&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;서버-패키&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;지&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;명령을 실행하면 Claude Code가 해당 MCP 서버를 등록하고, 이후 Claude Code를 실행할 때마다 연결이 자동으로 활성화됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;연결 확인&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude Code를 실행한 뒤 &lt;code&gt;/mcp&lt;/code&gt; 를 입력하면 현재 연결된 MCP 서버 목록과 상태를 볼 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;인증-토큰은-안전하게&quot;&gt;인증 토큰은 안전하게&lt;/h2&gt;
&lt;p&gt;일부 MCP 서버는 로그인이 필요해 API 토큰을 요구합니다. 이 토큰은 계정에 대한 접근 권한을 가지므로, 코드 파일에 직접 넣으면 GitHub 같은 곳에 공개되는 위험이 있습니다.&lt;/p&gt;
&lt;p&gt;토큰은 환경 변수로 관리하는 것이 안전합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# .env 파일을 만들고&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;SERVICE_TOKEN=your_token_here&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; .env&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# .gitignore에 추가해서 git에 올라가지 않게 설정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;.env&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; .gitignore&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 MCP 등록 명령에서 토큰 값을 직접 쓰는 대신 환경 변수를 참조하면 됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;mcp는-언제-붙이면-좋을까&quot;&gt;MCP는 언제 붙이면 좋을까&lt;/h2&gt;
&lt;p&gt;처음부터 여러 MCP를 붙일 필요는 없습니다. 기본 개발은 Claude Code와 CLAUDE.md만으로도 충분히 시작할 수 있습니다. “불편이 생겼을 때 그 불편을 없애는 MCP 하나”를 붙이는 식으로 접근하면 됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;라이브러리 사용법이 자꾸 틀린다 → &lt;strong&gt;Context7&lt;/strong&gt;로 최신 문서 연결&lt;/li&gt;
&lt;li&gt;만든 화면을 매번 손으로 확인하기 번거롭다 → &lt;strong&gt;Playwright&lt;/strong&gt;로 브라우저 테스트&lt;/li&gt;
&lt;li&gt;프로젝트가 커져 구조·이력을 자동으로 추적하고 싶다 → 전용 서비스 MCP 검토&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;다음 편에서는 AI에게 원하는 걸 정확히 얻어내는 법, 즉 프롬프트 엔지니어링을 다룹니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>MCP</category><category>Claude Code</category><category>바이브코딩</category></item><item><title>사용자 경험을 이루는 6가지 속성 — UX 피라미드</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/04/</guid><description>UX디자인이 실제로 다루는 것은 무엇일까요? UX 피라미드라는 프레임워크를 통해 경험을 이루는 여섯 가지 속성을 나누고, 그 중 디자이너가 조정할 수 있는 영역이 어디인지 짚어봅니다.</description><pubDate>Tue, 07 Jul 2026 02:28:57 GMT</pubDate><content:encoded>&lt;p&gt;무언가를 디자인한다는 것은, 목표에 맞춰 디자인 대상이 가지고 있는 여러 속성들을 조정하여 가장 목표에 부합하는 형태를 제안하는 일입니다. 건축가가 공간의 크기와 동선, 채광과 재료를 조율하듯, 그래픽 디자이너가 색상과 타이포그래피, 여백의 비율을 다루듯, 모든 디자인 행위의 본질은 결국 대상이 지닌 속성들 사이에서 최적의 균형점을 찾아내는 데 있습니다.&lt;/p&gt;
&lt;p&gt;사용자의 경험을 디자인한다는 것도 마찬가지입니다. 다만 그 대상이 물리적 형태나 시각적 표현이 아니라, 사용자가 제품이나 서비스를 사용하면서 겪게 되는 일련의 경험이라는 점이 다를 뿐입니다. 일반적으로 디자인이 심미성과 기능성, 상징성 등의 속성들을 목표에 맞춰 조작하여 최적의 결과를 도출해왔듯이, 사용자 경험 디자인 역시 경험이 가진 고유한 속성들을 파악하고 이를 의도적으로 조정하여 디자인 목표에 최적화된 형태로 제안하는 것이 그 역할이라 하겠습니다. 그렇다면 자연스럽게 이런 질문이 떠오릅니다. 경험이 가진 속성이란 과연 무엇이며, 그것은 어떻게 분류되고, 디자이너는 그 중 무엇을 조정할 수 있을까요?&lt;/p&gt;
&lt;p&gt;이를 살펴보기 위해, 사용자의 경험을 구성하는 속성에 대한 여러 이론들 중에서도 대표적인 UX 피라미드 프레임워크를 통해 먼저 경험의 속성을 나눠보겠습니다. UX 피라미드는 사용자 경험을 이루는 속성들을 계층적으로 정리한 모델로, 가장 기본적이고 필수적인 속성부터 시작하여 점차 고차원적인 가치로 올라가는 구조를 가지고 있습니다. 이 프레임워크를 활용하면 사용자가 경험하는 다양한 측면들을 체계적으로 분리하여 살펴볼 수 있으며, 각 속성이 전체 경험에서 어떤 역할을 하는지를 보다 명확하게 파악할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;사용자-경험-피라미드-사용자-경험을-이루는-6가지-속성&quot;&gt;사용자 경험 피라미드: 사용자 경험을 이루는 6가지 속성&lt;/h2&gt;
&lt;p&gt;UX 피라미드라는 모델에 따르면, 사용자 경험은 아래에서부터 기능성(Functionality)—신뢰성(Reliability)—사용성(Usability)—편의성(Conveniency)—감성(Pleasurability)—의미성(Meaningfulness)의 순서로 쌓이는 여섯 개 층으로 이루어져 있습니다. 가장 아래층일수록 기본적이고 필수적인 속성이며, 위로 올라갈수록 더 고차원적이고 정성적인 가치를 담고 있습니다.&lt;/p&gt;
&lt;p&gt;이 피라미드의 각 층이 실제로 어떻게 작용하는지를 이해하는 가장 직관적인 방법은, 사용자가 ‘불편’을 느끼는 순간을 떠올려 보는 것입니다. 사용자가 어떤 제품이나 서비스에 대해 불편을 경험할 때, 그 불편은 위의 한 가지 이상의 속성에서 유래한 것일 수 있습니다.&lt;/p&gt;
&lt;p&gt;제품이나 서비스의 기능이 불만족스러워서일 수도 있고(유용성), 잦은 고장 때문일 수도 있으며(신뢰성), 원하는 기능을 활용하는 단계가 너무 복잡해서일 수도 있습니다(사용성). 또 사용하기에 어렵거나(편의성), 정서적으로 거부감이 들거나(감성), 본인의 가치관과 맞지 않아서일 수도 있습니다(의미성).&lt;/p&gt;
&lt;p&gt;사용자는 대개 자신의 불편을 “그냥 별로다”라고 뭉뚱그려 표현하지만, 그 이면에는 이처럼 서로 다른 층위의 속성들이 복합적으로 얽혀 있는 경우가 많습니다. 따라서 사용자 경험을 개선하기 위해서는 먼저 그 불편이 어느 속성에서 비롯된 것인지를 정확히 식별하는 것이 선행되어야 합니다.&lt;/p&gt;
&lt;p&gt;이렇게 여섯 가지로 나뉘는 속성들을 좀 더 넓은 시각에서 바라보면, 이들은 크게 두 가지 성격으로 구별됩니다. 하나는 객관적이고 정량적으로 지표화할 수 있는 속성들로, 기능성(Functionality; Usefulness), 신뢰성(Reliability), 사용성(Usability)이 여기에 해당합니다. 이들은 숫자나 데이터로 측정하고 비교할 수 있다는 특징을 가집니다.&lt;/p&gt;
&lt;p&gt;다른 하나는 주관적이고 정성적인 경험적 가치로 평가되는 속성들로, 편의성(Conveniency), 감성(Pleasurability), 의미성(Meaningfulness)이 그것입니다. 이 속성들은 동일한 조건에서도 사용자에 따라 전혀 다르게 느껴질 수 있으며, 수치화하기보다는 질적인 방법으로 파악해야 하는 영역입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이는 매슬로(A. Maslow)의 욕구 단계 이론을 접해본 적이 있다면 비슷함을 느낄 수 있습니다. 이 욕구 피라미드와 유사하게, 가장 아래층의 기본적이고 단순한 속성들로 시작하여 점차 고차원적이고 지표화하기 어려운 가치들로 이어지는 구조이기 때문입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;각각을 간단히 정의하면 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;기능성(Functionality): 제품 또는 서비스가 사용자에게 제공하는 기능적 효용도를 말합니다.&lt;/li&gt;
&lt;li&gt;신뢰성(Reliability): 사용자가 기대하는 기능이 오류 없이 수행되는 정도를 말합니다.&lt;/li&gt;
&lt;li&gt;사용성(Usability): 사용자가 어떤 기능을 수행하기까지 필요한 과업의 단계, 복잡도를 의미합니다.&lt;/li&gt;
&lt;li&gt;편의성(Conveniency): 사용자가 어떤 기능을 얼마나 쉽게 수행할 수 있는지, 그 직관성을 의미합니다.&lt;/li&gt;
&lt;li&gt;감성(Pleasurability): 사용자가 느끼는 감성적인 만족도를 의미합니다.&lt;/li&gt;
&lt;li&gt;의미성(Meaningfulness): 사용자가 느끼는 의미적 충족도를 의미합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여섯 가지 속성을 모두 나열하고 나면, 실무적인 관점에서 자연스럽게 드는 의문이 있습니다. 이 모든 속성을 디자이너가 다 다룰 수 있을까요? 결론부터 말하면, 사용자 경험 디자인이 주요하게 관여할 수 있는 속성은 중간의 사용성-편의성-감성 세 가지로 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;그 이유는 피라미드의 상하를 살펴보면 분명해집니다. 먼저 하단의 기능성과 신뢰성은 제품이나 서비스를 구성하는 기술력에 해당하는 내용입니다. 서버가 다운되거나 핵심 기능이 작동하지 않는 문제를 디자인만으로 해결할 수는 없으며, 이는 엔지니어링 영역의 몫입니다.&lt;/p&gt;
&lt;p&gt;반대로 최상단의 의미성은, 이 제품이나 서비스가 사용자의 삶에서 어떤 의미를 갖느냐는 문제로, 제품 또는 서비스의 시작 단계 즉 사업의 방향성과 비전에 관련되는 영역입니다. 이미 방향이 정해진 상태에서 디자인을 통해 유의미한 변화를 주기는 어렵습니다.&lt;/p&gt;
&lt;p&gt;결국 UX디자이너가 자신의 전문성을 가장 직접적으로 발휘할 수 있는 영역은 그 사이에 놓인 세 가지 속성입니다. 이러한 관점에서, UX디자인이 주요하게 작용하는 경험의 세 가지 속성을 개인적으로는 ‘UX디자인 파라미터(UX Design Parameters)‘라고 부릅니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;‘UX디자인 파라미터’라는 용어 자체는 개인적인 정의이며 공식화된 이론적 용어가 아니므로, 사용에 주의가 필요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;여섯 가지 속성 중 어디에 디자이너의 손이 닿을 수 있는지를 확인했으니, 다음 글에서는 이 세 가지 파라미터 — 사용성, 편의성, 감성을 하나씩 자세히 살펴봅니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>UX 피라미드</category><category>사용자 경험</category><category>디자인 이론</category></item><item><title>바이브코딩의 함정 — 쉬움이 오히려 어려움을 만든다.</title><link>https://blog.bepuljang.co.kr/vibecoding/05/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/05/</guid><description>바이브코딩으로 프로젝트를 키우다보면 쌓여가는 프로젝트에 대한 몰이해, 그리고 그로 인해 만나게 되는 좌절과 그 해결에 대한 이야기입니다.</description><pubDate>Tue, 07 Jul 2026 02:28:57 GMT</pubDate><content:encoded>&lt;p&gt;처음 며칠은 정말 신기합니다. 아이디어를 말하면 코드가 생기고, 화면이 바뀝니다. 기능이 하나씩 추가될 때마다 성취감이 생깁니다. 그런데 일정 수준 프로젝트가 커지기 시작하면 점점 이 과정이 어려워지기 시작합니다.&lt;/p&gt;
&lt;p&gt;예를 들어, “로그인 기능을 추가해줘”라고 했더니 한참 만든 코드가 기존 코드와 충돌하여 프로젝트 자체가 깨집니다. 어디서 충돌하는지 찾으며 AI서비스가 하루 종일 분석했는데, ‘찾았다’는 분석과는 달리 수정을 해도 계속 오류가 발생하고, 토큰과 시간만 낭비되며 문제가 좀처럼 해결되지 않습니다.&lt;/p&gt;
&lt;p&gt;모든 것을 안다고 생각했던, 그렇게 생각하도록 메시지를 던지는 AI 서비스와 바이브코딩의 함정입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;바이브코딩으로 기능을 계속 추가하다 보면 프로젝트 구조가 무너지는 이유는 두 가지입니다.&lt;/p&gt;
&lt;h3 id=&quot;ai는-생각보다-많은-것을-보지-않는다&quot;&gt;AI는 생각보다 많은 것을 보지 않는다&lt;/h3&gt;
&lt;p&gt;AI 서비스는 현재 열려 있는 파일과 현 세션의 대화 내용, 그리고 CLAUDE.md 정도를 참조하여 코드를 작성합니다. 기존에 만든 것이나 변경한 것을 사용자는 기억하고 있고 당연히 만든 당사자인 AI도 기억할 거라 착각하지만, 실제로는 꼭 필요한 내용들만 파악할 뿐, 모든 내용을 매번 완벽하게 파악하며 새로운 코드를 작성하지는 않습니다.&lt;/p&gt;
&lt;p&gt;만약 AI서비스가 모든 코드베이스와 스펙을 매 대화와 작성과정에서 파악했다면 현 시점의 형태보다 여러 모로 비효율적이었을 것이기 때문에 사실 이건 당연한 설계입니다. 문제는 이 때문에 특히 구축한지 오래된 코드와 충돌하는 설계를 주문했을 때 그 사실을 알지 못하고 오로지 현재 주문받은 작업을 잘 수행하는 데만 초점을 두어 작업합니다. 긍정적이고 자신감에 찬 어조와는 달리, 많이 알지 못하는 상태로 작업을 한다는 것입니다.&lt;/p&gt;
&lt;h3 id=&quot;사용자도-구조를-모른다&quot;&gt;사용자도 구조를 모른다&lt;/h3&gt;
&lt;p&gt;바이브코딩이 쉽다는 것은 어디까지나 ‘주문’의 영역에서의 이야기입니다. 오히려 코드 자체는 사용자가 알지 못하는 스타일로, 제대로 보지 않은 상태에서 수없이 작성된 상태이기 때문에 어떻게 구성되어있고 어떤 위험이 있는 채로 만들어졌는지 알지 못하는 상태인 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;그래서 문제가 생겼을 때에도 결국 AI의 코드 분석 결과에 의존하게 되는데, 이 분석 결과가 오판인 경우 문제는 바로 옆에 두고 주변만 빙빙 돌면서 잘못된 문제 분석으로 수정된 코드가 새로운 문제를 낳는,무한대로 반복되는 오류의 루프에 빠지기 시작합니다.&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;기간&lt;/th&gt;&lt;th&gt;증상&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;프로젝트 시작&lt;/td&gt;&lt;td&gt;기능이 새롭게 만들어짐, 말하는대로 원활히 만들어짐.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;프로젝트 성장&lt;/td&gt;&lt;td&gt;프로젝트가 커지고 복잡해짐, 점점 어떤 상태인지 모르는 블랙박스가 됨.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;문제 발생&lt;/td&gt;&lt;td&gt;새 기능을 추가하니 기존 기능이 깨짐. AI가 원인을 분석하지만, 오판.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;문제 확대&lt;/td&gt;&lt;td&gt;오판을 통해 수정된 내용이 새로운 버그를 만듬.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;무한 루프&lt;/td&gt;&lt;td&gt;버그가 중첩되어 분석 자체가 어려워짐, 새로 만드는 게 더 나은 상태.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;오류의-함정에-빠지지-않으려면&quot;&gt;오류의 함정에 빠지지 않으려면&lt;/h2&gt;
&lt;p&gt;이 문제에 대한 직접적인 해결책은 물론 코딩 실력과 경험일 수 있습니다. 그러나 이 함정에 빠지는 것 자체가 문제이기 때문에 이것을 예방하는 게 중요한데, 이 때 필요한 게 &lt;strong&gt;프로젝트 구조를 이해하고 프롬프트에서 AI서비스에게 주의해야 할 내용을 같이 전달하는 것&lt;/strong&gt;입니다.&lt;/p&gt;
&lt;p&gt;무엇이 만들어졌는지, 무엇이 무엇에 연결되어 있는지, 언제 어떤 기능이 추가됐는지를 알고 새로운 구조가 어떻게 추가될지, 어떠한 위험이 도사리는지를 알면 AI에게 “새로 기능을 추가할 때 지금 우리 프로젝트 구조의 이러한 지점들을 감안해줘”라고 필요한 맥락을 제공할 수 있고, 이를 통해 함정을 미리 알고 피할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;구조를-이해하고-기록하는-여러-가지-방법&quot;&gt;구조를 이해하고 기록하는 여러 가지 방법&lt;/h2&gt;
&lt;p&gt;아래의 방법들은 구조를 이해하고 기록하는데 널리 쓰이는 방법들입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;프로젝트 안의 문서 파일&lt;/strong&gt; — 앞선 3편에서 다룬 &lt;code&gt;CLAUDE.md&lt;/code&gt;나 &lt;code&gt;ARCHITECTURE.md&lt;/code&gt; 같은 마크다운 파일은 폴더 구조와 규칙을 기록하여 수정 과정에 생길 수 있는 충돌 문제를 수정해줍니다. 별도 도구 없이 바로 시작할 수 있고, Claude Code가 대화를 시작할 때 자동으로 읽어준다는 장점이 있습니다. 다만 단순 문서이기 때문에 검증 도구가 없는데, 실제와 다른 경우 오히려 문제를 만들수 있다는 점과 사용자가 읽고 파악하기에는 한계가 있다는 점이 단점입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;노트 도구&lt;/strong&gt; — Notion이나 Obsidian 같은 곳에 기능 추가 이력과 구조 메모를 남기는 방식입니다. 형식에 얽매이지 않고 자유롭게 쓸 수 있지만, 기록이 코드와 떨어져 있어서 기록이 ‘낡을’ 수 있습니다. 사용자가 꼼꼼하고 부지런히 관리해야 하며, 프롬프트에서 필요한 내용들을 정확히 전달해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;다이어그램 도구&lt;/strong&gt; — Mermaid나 Excalidraw로 구조를 그림으로 그려두는 방식입니다. 사용자가 이해하기에는 가장 좋은 형태입니다. 전체 그림을 한눈에 파악하기 좋지만, 구조가 바뀔 때마다 그림을 다시 손봐야하고 CLAUDE.md와 중복인 내용이 되어 효율성이 떨어집니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://app.umtri.io&quot;&gt;Umtri.io&lt;/a&gt; — Umtri.io는 이러한 문제를 해결하기 위해 BEPULJANG이 제작한 프로젝트 추적 도구입니다. MCP(Model Context Protocol)를 통해 AI서비스와 직접 연결되어 AI서비스가 만든 프로젝트를 기록하고 UI를 통해 시각적으로 보여주며, 새로운 프로젝트 계획 시 추가되는 노드나 연결 관계 등을 분석하여 발생할 수 있는 오류 지점들도 자동으로 파악합니다. 프로젝트가 일정 수준 이상 성장했다면, 도입하여 위험을 줄이고 프로젝트에 대한 이해도를 높일 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;기록은-언제-어떻게-시작할까&quot;&gt;기록은 언제, 어떻게 시작할까&lt;/h2&gt;
&lt;p&gt;처음부터 완벽하게 구조를 정의할 필요는 없습니다. 기록을 시작하기 좋은 시점은 &lt;strong&gt;첫 번째 핵심 기능이 완성됐을 때&lt;/strong&gt;입니다. 이때 현재 폴더 구조와 주요 파일의 역할을 &lt;code&gt;CLAUDE.md&lt;/code&gt;에 한 번 정리해두고, 이후 기능을 추가할 때마다 바뀐 부분만 덧붙이면 됩니다.&lt;/p&gt;
&lt;p&gt;핵심은 양이 아니라 꾸준함입니다. 새 컴포넌트를 만들었을 때 한 줄, 데이터 구조가 바뀌었을 때 한 줄. 이렇게 작은 기록이 쌓이면 몇 주 뒤 AI에게 “지금 우리 프로젝트 구조가 이래”라고 맥락을 건넬 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 Claude Code에 외부 도구를 연결하는 방법, 즉 MCP를 다룹니다. Umtri.io를 설명하면서 간략하게 언급되었는데, 다음 편을 통해 MCP가 무엇인지 자세히 살펴보겠습니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>바이브코딩</category><category>프로젝트 구조</category><category>문서화</category></item><item><title>경험이란 무엇인가 — 습득의 과정으로 본 사용자 경험</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/03/</guid><description>경험이란 습득의 과정입니다. 일상의 언어와 사전적 정의에서 출발해 인지와 행동, 시퀀스와 비가역성이라는 개념으로 경험이 형성되는 원리를 짚어보고, 그 안에서 UX디자이너가 하는 일이 무엇인지 다시 살펴봅니다.</description><pubDate>Mon, 06 Jul 2026 01:22:05 GMT</pubDate><content:encoded>&lt;p&gt;앞서 살펴본 글에서 우리는 소비자 관점이 아닌 사용자 관점에서 공감하고, 그들의 사용 환경 속에 직접 들어가 경험을 개선하겠다는 방향을 분명히 했습니다. 선언이 방향을 정했다면, 이제 그 방향을 따라 실제로 나아가야 할 차례입니다. 그러기 위해서는 무엇보다 먼저 ‘경험’이라는 것이 무엇인지를 이해하고, 그것을 어떻게 조작할 수 있는지를 파악해야 합니다.&lt;/p&gt;
&lt;p&gt;이전 글에서 UX디자인을 다이빙에 비유했던 것을 다시 빌려오면, 다이버가 뛰어드는 그 물, 즉 경험은 도도하게 끊임없이 흐르는 강에 대응할 수 있습니다. 강은 다이버의 의지와 무관하게 자신의 방향과 속도로 흘러가며, 그 안에 들어간 다이버는 강의 성질을 온몸으로 느끼게 됩니다. 그리고 그 강의 성격을 결정짓는 것은 바로 흐름의 원류입니다. 원류가 어디에서 시작되고 어떤 지형을 거치느냐에 따라 경험이라는 강의 수질과 흐름의 방향이 만들어지는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;경험-우리는-이미-알고-있다&quot;&gt;경험, 우리는 이미 알고 있다&lt;/h2&gt;
&lt;p&gt;그렇다면 경험이란 구체적으로 무엇일까요. 이를 이해하기 위해 우리가 일상에서 경험을 어떻게 주고받는지부터 살펴보겠습니다. 우리는 평소에 경험을 묻거나 답할 때, 어떤 대상에 대해서 ‘어떠했는지’ 또는 ‘어떻게 생각하는지’를 묻곤 합니다. “그 식당 어땠어?”, “새로 산 폰 괜찮아?” 같은 질문들이 바로 그것입니다. 이 둘은 모두 과거에 대한 질문이라는 공통점이 있습니다. 아직 겪지 않은 것에 대해 경험을 물을 수는 없으니, 여기서 일단 경험이란 것은 대상에 대해 과거에 발생했던 일들, 즉 상호작용에 대한 어떤 기억이라고 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;그리고 그에 대한 답을 떠올려보면, 보통 ‘좋다’, ‘나쁘다’ 또는 ‘편하다’, ‘불편하다’, ‘예쁘다’, ‘별로다’ 등 어떤 정서적인 평가에 해당하는 답변인 경우가 대부분입니다. 물론 특별히 인상이 강했던 부분에 대해서는 “어디가 어떻게 불편했다”거나 “이런 점이 특히 좋았다”는 식의 분석적인 답변이 추가되는 경우도 있겠지만, 일반적인 경우에는 지배적인 소수의 감성이 그 답변의 핵심이 되고, 이후에 덧붙는 말들 역시 대부분 그 감성을 뒷받침하거나 정당화하는 근거로 기능합니다. 우리가 경험을 회상할 때 세밀한 사실관계보다는 전체적인 느낌이 먼저 떠오르는 것도 이 때문입니다. 즉, 이러한 관찰을 종합하면 경험은 ‘대상에 대해 과거에 발생했던 상호작용에 따른 통합적인 정서의 기억’이라고 정리할 수 있습니다.&lt;/p&gt;
&lt;p&gt;지금까지의 정의는 우리의 일상적인 관찰로부터 귀납적으로 도출한 것입니다. 그런데 흥미롭게도, 이렇게 경험적으로 내린 정의에 덧붙여 사전적인 정의를 들여다보아도 경험은 놀라울 정도로 비슷하게 정리됩니다. 사전에서는 경험을 다음과 같이 정의합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ex·pe·ri·ence&lt;/strong&gt; /ikˈspirēəns/&lt;/p&gt;
&lt;p&gt;the process of getting knowledge or skill from doing, seeing, or feeling things
무언가를 하는 것, 보는 것, 또는 느끼는 것으로부터 지식이나 기술을 습득하는 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;사전적 정의를 우리의 맥락에서 다시 풀어보면, 경험은 외부의 자극으로부터 지식 또는 기술을 습득하는 과정이라고 정의할 수 있습니다. 이 짧은 정의 안에 UX디자인의 핵심이 압축되어 있는데, 여기서 특히 주목해야 할 키워드는 ‘습득’과 ‘과정’ 두 가지입니다. 경험이 단순한 결과물이 아니라 ‘습득’이라는 행위를 통해 형성되며, 그것이 하나의 ‘과정’으로서 시간 속에서 전개된다는 점이 중요합니다. 다시 말해, 이 ‘습득의 과정’이야말로 경험을 형성하는 근본 원리가 되는 것입니다.&lt;/p&gt;
&lt;p&gt;이 원리를 이해하면 UX디자인이 하는 일의 본질이 보다 선명해집니다. 우리가 UX디자인을 한다는 것은 바로 이 습득의 과정에 개입하고 이를 섬세하게 조작함으로써, 경험이라는 강의 수질과 흐름을 원하는 방향으로 변화시키는 것을 의미하기 때문입니다. 그렇다면 ‘습득’과 ‘과정’이 각각 구체적으로 무엇을 의미하는지, 그리고 이것이 디자인 실무에 어떻게 연결되는지를 좀 더 자세히 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;습득의-과정&quot;&gt;습득의 과정&lt;/h2&gt;
&lt;p&gt;먼저 ‘습득’부터 살펴보겠습니다. 습득을 다른 말로 표현하면 정보의 입력, 즉 인지(Cognition)가 됩니다. 우리가 가진 눈, 귀, 코, 피부 등의 감각기관을 통해 대상물의 형태, 색상, 질감, 소리, 냄새 등 다양한 면모에 대한 정보를 받아들이고, 이들을 두뇌 안에서 처리하며 기억으로 저장하는 일련의 과정이 바로 ‘습득’일 것입니다.&lt;/p&gt;
&lt;p&gt;그런데 여기서 UX디자이너가 마주하는 근본적인 난제가 등장합니다. 이 인지의 과정은 대부분 사용자의 머릿속에서 일어나는 내적인 현상이기 때문에, 현재까지의 기술로는 그것을 직접적으로 관찰하거나 정밀하게 분석하는 것이 사실상 불가능하다는 점입니다. 사용자가 제품을 보면서 무엇을 느끼고 어떤 판단을 내리는지, 그 실시간의 인지 과정을 들여다볼 방법이 없는 것입니다. 때문에 UX디자인을 수행하는 디자이너는 겉으로 드러나는 사용자의 표면적인 반응을 통해 보이지 않는 내부의 인지 상태를 유추할 수밖에 없게 됩니다. 이때, 대상에 대해 사용자가 의식하지 못한 채 자연스럽게 보여주는 무의식적인 표상을 우리는 ‘행동(Behavior)‘이라고 부릅니다. 행동은 인지의 그림자와 같아서, 직접 볼 수 없는 인지를 간접적으로 읽어낼 수 있는 거의 유일한 창구인 셈입니다.&lt;/p&gt;
&lt;p&gt;습득이 경험의 ‘무엇’에 해당한다면, ‘과정’은 경험의 ‘어떻게’에 해당합니다. 이 ‘과정’에 대해 살펴보면, 경험이라는 것은 시간적으로는 아주 찰나에 불과한 순간일지라도 그 안에는 반드시 어떤 흐름이 존재합니다. 제품을 처음 대면하고, 사용하고, 보관하거나 휴대하는 등 분석할 수 있는 시퀀스(Sequence)를 통해 경험은 형성되는 것입니다. 예를 들어 커피 한 잔을 마시는 경험조차도 컵을 집어 드는 순간, 입술에 닿는 온도, 한 모금 넘기는 맛, 내려놓는 무게감이라는 시퀀스를 거칩니다.&lt;/p&gt;
&lt;p&gt;그리고 시간은 곧 공간을 수반하기 때문에, 경험이라는 것은 아무리 작은 규모일지라도 단위적으로는 분명한 시간적, 공간적인 절차를 통해 형성되는 것입니다. 이러한 절차적 특성은 경험의 개선과 아주 밀접하게 관련되는데, 시퀀스의 어느 지점에서 어떤 변화를 주느냐에 따라 전체 경험의 질이 달라지기 때문입니다. 또한 여기서 간과할 수 없는 것이 시간과 공간이 갖는 비가역성, 즉 되돌릴 수 없는 성질입니다. 한번 지나간 순간은 다시 돌아오지 않으며, 사용자가 특정 시점에서 받은 인상은 이후의 경험 전체를 물들입니다. 이 비가역성은 경험을 쌓아가는 절차에서 매 순간의 관리가 얼마나 중요한지를 분명하게 암시합니다.&lt;/p&gt;
&lt;h2 id=&quot;인지와-행동-사이에서--ux디자이너라는-역할&quot;&gt;인지와 행동 사이에서 — UX디자이너라는 역할&lt;/h2&gt;
&lt;p&gt;이제 습득과 과정이라는 두 축을 종합하여 소결해보겠습니다. 경험을 디자인한다는 것은 결국 행동이라는 창구를 통해 사용자의 인지 과정을 관찰하고, 그 관찰로부터 얻은 통찰을 바탕으로 대상물을 디자인함으로써 원하는 방향으로 행동의 변화를 유도하며, 궁극적으로는 인지의 변화를 추구하는 일련의 작업이라고 정리할 수 있습니다. 말하자면 보이지 않는 인지를 바꾸기 위해 보이는 행동을 관찰하고, 다시 보이는 대상물을 변화시켜 보이지 않는 인지에 영향을 미치는, 간접적이면서도 정교한 작업인 것입니다. 이 과정에서 앞서 ‘수면’으로 비유한 사용자의 무의식 경계를 끊임없이 넘나들며 사용자 행동이 원하는 방향으로 조정되고 있는지를 살피고, 사용자와 동기화하고 공감하여 그들의 경험을 추론하는 것이 무엇보다 중요합니다. 결국 UX디자이너는 사용자의 무의식과 대화하는 사람이라고도 할 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;이처럼 경험 디자인이 인지와 행동이라는 보이지 않는 영역을 다루는 작업이라는 사실은, 자연스럽게 UX디자인에 요구되는 역량이 기존의 소비자 지향 디자인과는 상당히 달라지는 원인이 됩니다. 그리고 이러한 역량의 차이가 UX디자인이 독립적인 학문이자 분야로서 새롭게 개척되는 결과를 낳았습니다. 기존의 디자인에서는 디자이너 개인의 영감과 직관을 통해 소비자에게 호소력이 있는 스타일과 특질을 제시하는 부분이 핵심 역량이었습니다. 아름다운 형태를 만들어내는 조형 능력, 트렌드를 읽는 감각, 시각적 임팩트를 전달하는 표현력 등이 중시되었던 것입니다.&lt;/p&gt;
&lt;p&gt;반면에 UX디자인에서는 사용자의 관점에서 얼마나 깊이 공감하고 이해하여, 겉으로 드러나지 않는 그들의 내면을 정확히 추론할 수 있는지가 관건이 됩니다. 이는 단순히 ‘예쁘게 만드는 능력’만으로는 도달할 수 없는 영역이며, 인간의 인지와 행동에 대한 폭넓은 이해를 필요로 합니다. 1999년 IDEO가 진행한 ‘Reimagining the Shopping Cart’ 프로젝트가 이를 잘 보여주는데, 이 프로젝트에 참여한 사람들의 이력을 살펴보면 산업디자이너 및 엔지니어를 포함해 심리학, 건축학, 경영학, 언어학, 생물학 등 놀라울 정도로 다양한 배경의 사람들이 하나의 팀을 이루어 쇼핑카트라는 단일 제품을 디자인하는 모습을 볼 수 있습니다. 하나의 제품을 디자인하는 데 왜 이렇게 다양한 분야의 전문가가 필요할까요. 그것은 사용자를 진정으로 이해하기 위해서는 어느 한 분야의 시각만으로는 부족하며, 인간의 경험이라는 복잡한 현상을 다각도에서 조명할 수 있는 다양한 관점과 역량의 동원이 필수적이기 때문입니다.&lt;/p&gt;
&lt;p&gt;이 모든 논의를 하나로 모아 정리해보겠습니다. 좋은 UX디자인은 사용자의 인지 과정을 면밀히 관찰하고, 그 과정에서 발생하는 질적인, 혹은 행동적인 문제를 발견하여, 이를 디자인을 통해 사용자 스스로도 모르는 사이에 자연스럽게 개선시키는 디자인이라고 정리할 수 있습니다. 사용자가 “무언가 달라졌다”고 의식하기보다는 “왠지 더 편해졌다”, “자연스럽게 잘 된다”고 느끼게 만드는 것이 좋은 UX디자인이 지향하는 바입니다.&lt;/p&gt;
&lt;p&gt;이 글의 시작에서 빌려온 강의 비유를 다시 가져와 마무리하자면, 강의 원류를 찾아 그 수질과 수량을 개선하고 흐르는 길을 세심하게 인도하면 깨끗하면서도 안정적이고 아름다운 강을 볼 수 있듯이, UX디자이너의 역할은 경험의 원류를 찾아 그 흐름을 바꾸는 일입니다. 물론 사용자가 축적해온 거대한 경험의 흐름에 비해, 디자이너가 가하는 개별적인 조정은 처음에는 너무도 미미해 보일 수 있습니다. 한두 가지 인터랙션을 바꾸는 것이 전체 경험을 어떻게 바꿀 수 있겠느냐는 의구심이 들 수도 있습니다.&lt;/p&gt;
&lt;p&gt;하지만 결국 어떤 거대한 흐름도 작은 것들이 모여 만들어내는 것입니다. 강도 결국은 수많은 작은 물줄기가 합쳐져 이루어지듯이, 경험의 세부를 하나하나 바꿔가면 어느 지점에서는 급격히 전체 흐름이 디자인 목표에 가까워지는 전환점을 맞이하게 됩니다. 이 과정을 인내하며, 자신의 직관이나 영감에 의존하기보다 관찰과 공감이라는 무기를 믿고 꾸준히 나아가는 것, 이것이 UX디자이너에게 요구되는 최고의 역량이자 동시에 가장 어려운 숙제이기도 합니다.&lt;/p&gt;
&lt;p&gt;경험이 습득의 과정이라는 것을 확인했으니, 다음 글에서는 그 경험을 이루는 구체적인 속성들, 즉 경험을 이루는 여섯 가지 파라미터를 살펴보고 그중 UX디자인이 주로 다루는 파라미터가 무엇인지 짚어보겠습니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>경험</category><category>인지</category><category>행동</category></item><item><title>바이브코딩으로 첫 화면 만들기 — 아이디어를 코드로 바꾸기</title><link>https://blog.bepuljang.co.kr/vibecoding/04/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/04/</guid><description>아이디어를 프롬프트로 바꾸는 방법과 AI와 주고받으며 코드를 완성하는 흐름을 실전 예제로 설명합니다.</description><pubDate>Mon, 06 Jul 2026 01:22:05 GMT</pubDate><content:encoded>&lt;p&gt;CLAUDE.md까지 작성했다면 이제 본격적으로 코드를 만들어볼 준비가 됐습니다. 이 글에서는 실제로 Claude Code를 사용해 간단한 웹 서비스의 첫 화면을 만드는 과정을 처음부터 끝까지 따라가봅니다.&lt;/p&gt;
&lt;p&gt;예제로는 &lt;strong&gt;북마크 앱&lt;/strong&gt;(링크를 모아두는 서비스)을 만들어봅니다. “나중에 읽을 링크를 저장해두는 간단한 서비스”입니다. 복잡하지 않으면서도 실제 서비스와 비슷한 구조를 가지고 있어 바이브코딩을 익히기에 좋습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;아이디어를-프롬프트로-바꾸는-방법&quot;&gt;아이디어를 프롬프트로 바꾸는 방법&lt;/h2&gt;
&lt;p&gt;바이브코딩에서 가장 먼저 익혀야 할 기술은 &lt;strong&gt;아이디어를 최대한 상세하고 자세하게 기술하는 것&lt;/strong&gt;입니다. AI서비스에 대해 환상을 가진 사람들은 AI는 사람과 달리 막연한 주문에도 원하는 결과물을 내준다고 생각하지만, 사실 그건 어디까지나 재미로 만드는 결과물 수준에서일 뿐, 예상과 다른 결과가 오차로 동작하는 산업 프로젝트에서는 맞지 않습니다. 사람이나 AI나 막연한 요구에서 생각할 수 있는 결과물의 범위는 너무 넓기 때문에, 상세하게 설명하여 그 오차를 줄여야 예상한 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;p&gt;즉, 좋은 프롬프트와 나쁜 프롬프트의 차이는 구체성에 있습니다.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;프롬프트 예시&lt;/th&gt;&lt;th&gt;문제점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;나쁜 프롬프트&lt;/td&gt;&lt;td&gt;”북마크 앱 만들어줘”&lt;/td&gt;&lt;td&gt;어떤 기술을 쓸지, 어떻게 생겼으면 하는지 전혀 모름&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;보통 프롬프트&lt;/td&gt;&lt;td&gt;”React로 북마크 저장하는 앱 만들어줘”&lt;/td&gt;&lt;td&gt;기술은 명시했지만 기능, 디자인, 범위 불명확&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;좋은 프롬프트&lt;/td&gt;&lt;td&gt;아래 참고&lt;/td&gt;&lt;td&gt;기술, 기능, 시각적 목표, 제약 조건 모두 포함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;좋은 첫 프롬프트는 이렇게 작성합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;북마크를 저장하고 목록으로 보여주는 간단한 웹 앱을 만들어줘.URL과 제목을 입력하면 목록에 추가하는 거야. 그리고 저장된 목록은 카드 형태로 표시하고. 각 카드에는 삭제 버튼이 있어서 삭제도 할 수 있어야 해. 일단 최소로 만들고 세부적인 내용은 추가해가자. 일단 React Vite 기반으로 만들려고 하는데 어떻게 만들면 좋을까?&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;프롬프트 작성 원칙&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;무엇을 만들지 명확하게&lt;/strong&gt;: 프로젝트에서 꼭 수행해야 하는 핵심적인 기능들과 그 형태를 최대한 상세하게 적습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;기능 범위 한정&lt;/strong&gt;: 한 번에 너무 많은 것을 요청하지 않습니다. 작게 시작하고 단계적으로 추가합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;모르는 내용은 묻기&lt;/strong&gt;: 모든 스펙을 무리하게 정할 필요 없습니다. 한번에 모든 것을 전달하기보다, 실제 사람과 대화할 때처럼 모르는 내용은 물어가며 같이 결정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ai와-주고받으며-코드를-완성하는-흐름&quot;&gt;AI와 주고받으며 코드를 완성하는 흐름&lt;/h2&gt;
&lt;p&gt;Claude Code에 위 프롬프트를 입력하면 AI가 프로젝트 구조를 만들고 파일을 작성합니다. 이때부터는 &lt;strong&gt;대화를 주고받으며 결과를 다듬는 과정&lt;/strong&gt;이 시작됩니다.&lt;/p&gt;
&lt;h3 id=&quot;1단계-프로젝트-생성&quot;&gt;1단계: 프로젝트 생성&lt;/h3&gt;
&lt;p&gt;터미널에서 작업할 폴더로 이동한 뒤 Claude Code를 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 작업 폴더 만들기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; bookmark-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; bookmark-app&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Claude Code 실행&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code가 실행되면 &lt;code&gt;&gt;&lt;/code&gt; 프롬프트가 나타납니다. 여기에 위에서 준비한 프롬프트를 입력합니다.&lt;/p&gt;
&lt;p&gt;AI가 작업을 시작하면 이런 메시지들이 보입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Creating project structure...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Writing src/App.jsx...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Writing src/components/BookmarkList.jsx...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Writing src/components/AddForm.jsx...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;파일을 만들고 코드를 작성하는 과정을 실시간으로 볼 수 있습니다. 초반에는 특히 만드는 과정을 유심히 보시는 게 좋은데, 코드베이스가 없는 상태일수록 방향을 잘못 잡거나 프로젝트 의도를 오해하는 경우가 많기 때문입니다. 제대로 작성이 되지 않으면 언제든 중단시키고 정정하는 프롬프트를 통해 의도에 맞는 방향으로 이끌어갑니다.&lt;/p&gt;
&lt;h3 id=&quot;2단계-실행해보기&quot;&gt;2단계: 실행해보기&lt;/h3&gt;
&lt;p&gt;파일 생성이 끝나면 Claude Code가 실행 방법을 알려줍니다. 예를 들어 React Vite 기반 프로젝트라면 보통 이렇습니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;터미널에 나타나는 주소(&lt;code&gt;http://localhost:5173&lt;/code&gt; 같은 형태)를 브라우저에 입력하면 방금 만든 화면이 보입니다.&lt;/p&gt;
&lt;h3 id=&quot;3단계-수정-요청하기&quot;&gt;3단계: 수정 요청하기&lt;/h3&gt;
&lt;p&gt;결과물을 보면 마음에 들지 않는 부분이 있을 것입니다. 그때는 Claude Code에 구체적으로 수정을 요청합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;디자인 수정 요청 예시&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;카드 배경에 연한 회색(#f5f5f5)을 넣고, 카드 사이 간격은 조금 더 넓혀줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;삭제 버튼은 assets 폴더에 추가한 아이콘으로 바꿔줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;기능 수정 요청 예시&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;북마크 추가할 때 URL이 http:// 또는 https://로 시작하지 않으면&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&quot;올바른 URL을 입력해주세요&quot;라는 경고를 보여줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 작은 단위로 수정을 요청하는 것이 중요합니다. 한 번에 많은 수정을 요청하면 AI가 예상치 못한 방향으로 코드를 바꾸는 경우가 생깁니다.&lt;/p&gt;
&lt;h3 id=&quot;4단계-반복&quot;&gt;4단계: 반복&lt;/h3&gt;
&lt;p&gt;수정 → 확인 → 추가 수정 사이클을 반복합니다. 이 반복의 과정이 중요한데, 모든 창작은 아주 얇지만 완성도 높은 구성요소가 쌓여서 만들어진다는 점을 유념해야 합니다. 바이브코딩 역시 크게 다르지 않습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;결과물-확인하기&quot;&gt;결과물 확인하기&lt;/h2&gt;
&lt;p&gt;프로젝트에 따라 다르지만, 이 예제에서 예시로 든 React Vite의 경우 개발 서버에서 열어두면 실시간으로 수정사항이 반영됩니다. 프로젝트 기반에 따라 적합한 방법으로 결과물을 확인합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;eg) Vite 개발 서버 실행 상태 (Terminal)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  VITE v5.x.x  ready in 300 ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ➜  Local:   http://localhost:5173/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ➜  Network: http://192.168.x.x:5173/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 &lt;code&gt;http://localhost:5173/&lt;/code&gt;를 브라우저에 입력하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;자주 쓰는 개발 서버 명령어&lt;/strong&gt;&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;명령어&lt;/th&gt;&lt;th&gt;역할&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/td&gt;&lt;td&gt;개발 서버 시작 (자동 새로고침 포함)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl + C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;개발 서버 종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/td&gt;&lt;td&gt;배포용 파일 생성 (나중에 사용)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;npm run preview&lt;/code&gt;&lt;/td&gt;&lt;td&gt;빌드된 파일을 로컬에서 미리보기&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&quot;자주-겪는-문제와-해결-방법&quot;&gt;자주 겪는 문제와 해결 방법&lt;/h2&gt;
&lt;p&gt;바이브코딩으로 첫 화면을 만들다 보면 문제 상황을 자주 마주칩니다. AI서비스가 스스로 문제를 인식하고 해결하는 경우도 많지만, AI가 직접 문제 메시지를 읽을 수 없는 상황이거나 아예 독립된 환경에서 재현되는 경우 사용자가 문제 상황을 설명하고 분석하도록 해야 합니다.&lt;/p&gt;
&lt;p&gt;일반적으로는 에러가 나면 터미널에 빨간 글씨로 메시지가 출력됩니다. 이것을 그대로 복사해서 Claude Code에 붙여넣으면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;아래 에러가 나고 있어. 고쳐줘.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[에러 메시지 전체를 여기에 붙여넣기]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;사람이 직접 수행하는 코딩 과정에서도 이 트러블슈팅(Trouble Shooting) 과정이 가장 어렵고 중요한데, 이 과정을 잘 수행하는 것이 바이브코딩의 성패를 좌우한다고 해도 과언이 아닐 정도입니다. 이 부분에서 많은 경험과 역량이 요구됩니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;여기까지-만든-것&quot;&gt;여기까지 만든 것&lt;/h2&gt;
&lt;p&gt;이 단계가 끝났다면 브라우저에서 실제로 동작하는 북마크 앱의 첫 버전이 만들어진 셈입니다. 아직 로컬(내 컴퓨터)에서만 동작하고, 새로고침하면 저장된 내용이 유지되는 정도지만, &lt;strong&gt;아이디어가 실제 동작하는 화면이 됐습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음 편에서는 바이브코딩 과정에서 종종 마주치는 문제를 다룹니다. 기능을 추가할수록 프로젝트 구조가 무너지는 현상과, 이를 어떻게 관리할 수 있는지입니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>바이브코딩</category><category>Claude Code</category><category>프롬프트</category><category>React</category></item><item><title>UX디자인은 왜 등장했나 — 소비자에서 사용자로</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/02/</guid><description>UX디자인은 어느 날 갑자기 생긴 개념이 아닙니다. 장식에서 상품 기획으로, 다시 사용자의 인지로 — 디자인의 관심이 옮겨온 흐름을 따라가며 &apos;UX디자인&apos;이라는 선언의 배경을 짚습니다.</description><pubDate>Sun, 05 Jul 2026 12:12:20 GMT</pubDate><content:encoded>&lt;p&gt;UX디자인이 기존의 디자인과 무엇이 다른지를 이해하려면, 먼저 디자인이라는 분야가 어떤 흐름 속에서 변화해왔는지를 살펴볼 필요가 있습니다. 디자인의 역사를 돌아보는 것은 단순한 회고가 아니라, UX디자인이 왜 등장해야 했는지를 이해하기 위한 필수적인 과정입니다.&lt;/p&gt;
&lt;p&gt;UX디자인은 어느 날 갑자기 하늘에서 떨어진 개념이 아닙니다. 산업의 성장과 기술의 발전, 그리고 사회 구조의 변화가 디자인에 이전과는 질적으로 다른 새로운 숙제를 안겨주었고, 그 숙제에 대한 응답으로서 자연스럽게 형성된 것입니다. 그렇기에 이 흐름을 이해하지 않고서는 UX디자인의 본질을 온전히 파악하기 어렵습니다.&lt;/p&gt;
&lt;h2 id=&quot;물산의-풍요-장식에서-상품의-매력으로&quot;&gt;물산의 풍요: 장식에서 상품의 매력으로&lt;/h2&gt;
&lt;p&gt;출발점부터 살펴보겠습니다. 현대적인 개념의 산업 디자인은 ‘공예’에서 출발한 것으로 여겨집니다. 산업의 초기 단계에서는 물산이 부족했고, 사람들에게 가장 절실했던 것은 당장의 기능성(유용성)이었습니다. 제품이 본연의 기능을 제대로 수행하는가, 즉 도구로서의 역할을 충실히 해내는가가 다른 무엇보다 중요했던 시기였습니다.&lt;/p&gt;
&lt;p&gt;이 때문에 기능공의 작업을 통해 확보되는 기능성이 다른 상위적 경험보다 더 우선시되었고, 디자인이라는 행위는 독립적으로 인식되기보다 기능 구현의 부수적인 영역에 머물러 있었습니다. 이러한 배경 속에서 디자인의 초기 형태는, 기본적인 기능 이상의 사용 경험을 원하는 일부 상류층을 대상으로 심미적인 가치를 전달하는 장식으로서의 역할을 수행했습니다. 쉽게 말해, 기능은 기능공이 담당하고 디자인은 그 위에 아름다움을 입히는 분업 구조였던 셈입니다. 이 초기의 역할 분담은 생각보다 뿌리 깊은 인식을 남겼는데, 지금까지도 ‘디자인’이라는 단어를 들었을 때 미학이나 고부가가치를 먼저 떠올리게 되는 원인이 바로 여기에 있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;‘상위적 경험’은 UX 피라미드 관점에서의 개념으로, 이 시리즈의 뒤편에서 더 자세히 다룹니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그러나 이러한 구도는 오래 지속되지 못했습니다. 산업이 성숙하고 물산이 풍요로워지면서, 기능성의 충족은 더 이상 차별화 요소가 되지 못했습니다. 대부분의 제품이 기본적인 기능을 충분히 수행하게 되자 소비자들은 자연스럽게 기능성 이상의 경험을 원하기 시작했고, 이러한 소비자 시장은 빠르게 확대되었습니다.&lt;/p&gt;
&lt;p&gt;마케팅 측면에서 심미성과 감성이 중요한 지표를 차지하기 시작했으며, 이를 충족하기 위해서는 기존처럼 ‘기능적으로 만들어진 형태에 사후적으로 장식을 더하는’ 수준으로는 한계가 분명했습니다. 제품의 형태 자체가 처음부터 심미적이고 감성적인 가치를 담아내야 했고, 이를 위해서는 디자인이 공정의 뒷단이 아닌 앞단에서 주도권을 가져야 했습니다. 이에 따라 산업 공정의 순서 자체가 뒤바뀌기 시작합니다. 디자인이 기능공보다 앞서서 형태와 청사진을 제시하고, 기능공은 이 기획에 맞춰 기능을 구현하는 방향으로 변모한 것입니다.&lt;/p&gt;
&lt;p&gt;디자인이 더 이상 기능의 부속물이 아니라 제품 기획의 선도적인 역할을 담당하게 된 전환점이었습니다. 그리고 이 과정에서 디자인의 관심은 자연스럽게 매대에서 잘 팔릴 수 있는, 즉 ‘소비자’ 지향적인 방향으로 옮겨졌습니다. 소비자가 무엇에 끌리는지, 어떤 트렌드와 라이프스타일이 시장을 지배하는지를 살피고 이를 선도하는 것이 디자인의 핵심 과업이 된 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;기술의-발전-인터페이스가-복잡해지다&quot;&gt;기술의 발전: 인터페이스가 복잡해지다&lt;/h2&gt;
&lt;p&gt;이처럼 디자인이 소비자 중심의 기획으로 자리를 잡아가고 있었지만, 이것만으로는 충분하지 않았습니다. 마케팅 시점에서의 단발적인 기획, 즉 ‘매대 앞에서의 매력’에 머무르던 디자인에 또 한 번의 근본적인 변화가 요구되었는데, 그 변화를 촉발한 것은 사회적 변화, 특히 기술의 급격한 발전이었습니다.&lt;/p&gt;
&lt;p&gt;예를 들어 반도체와 집적기술의 발전은 제품의 컨버전스(Convergence) 움직임으로 이어졌습니다. 기존에 개별적으로 분화되어 각자의 역할을 수행하던 제품들이 하나의 기기 안에 합쳐진, 복합 제품의 등장이었습니다. 카메라, 음악 플레이어, 전화기, 수첩이 각각 존재하던 세상에서 이들이 하나의 기기로 수렴하기 시작한 것입니다.&lt;/p&gt;
&lt;p&gt;이전의 디버전스(Divergence) 환경에서는 개별 제품의 물리적 형태가 그 기능과 밀접하게 연계되어 있었고, 그 연계는 대체로 직관적이었습니다. 카메라는 카메라처럼 생겼고 전화기는 전화기처럼 생겼기 때문에, 형태만 보아도 사용 방법을 어느 정도 유추할 수 있었습니다. 그러나 여러 기기가 하나로 합쳐진 환경에서는 동일한 인터페이스가 여러 가지 서로 다른 기능을 수행해야 하는 숙제가 발생했습니다. 그 결과 인터페이스는 불가피하게 중첩되었으며, 이 중첩된 기능 구조를 사용자에게 이해시키기 위해서는 이전과는 비교할 수 없이 많은 인지적 단서와 안내가 필요하게 되었습니다.&lt;/p&gt;
&lt;p&gt;컨버전스의 문제에 더해, RF·블루투스·Wifi 등 무선 기술의 발전과 소프트 키 인터페이스(Soft key Interface)의 확산도 이 변화에 중요하게 작용했습니다. 이전까지 사용자의 환경은 물리적인 선이나 고정된 버튼 등으로 제한되어 있었고, 그 제한은 역설적으로 사용 방식을 명확하게 규정해주는 역할을 했습니다. 그런데 무선 기술과 소프트 키가 이 물리적 제약을 해방시키면서, 사용자의 환경은 이전과 비교할 수 없이 자유로워졌습니다.&lt;/p&gt;
&lt;p&gt;문제는 이 자유가 양날의 검이었다는 점입니다. 제공자의 입장에서는 사용자의 행동을 유도하고 예측하기가 훨씬 어려워졌고, 원하는 행동을 이끌어내기 위한 새로운 차원의 노력이 필요해졌습니다. 사용자의 입장에서도 마찬가지였습니다. 어떤 부분과 어떻게 인터랙션하면 원하는 기능을 사용할 수 있는지에 대한 형태적 단서가 모호해졌기 때문에, 이를 감각적으로 인식하고 따라갈 수 있는 사용상의 가이드가 절실해진 것입니다.&lt;/p&gt;
&lt;p&gt;즉, 업계 전반에 걸쳐 사용자의 인지 과정과 사용 절차에 대한 보다 면밀한 관찰과 배려가 요구되기 시작했습니다. 그리고 감각적인 인식과 형태를 전통적으로 담당해오던 디자인이라는 분야는, 바로 이 숙제를 정면으로 받아들이며 비로소 ‘소비자’가 아닌 ‘사용자’를 바라보기 시작했습니다. 스마트폰의 확산은 이 모든 변화의 대표격이자 상징으로 혁신적인 변화를 유도했습니다.&lt;/p&gt;
&lt;h2 id=&quot;소비자가-아닌-사용자를-보겠다는-선언&quot;&gt;소비자가 아닌 ‘사용자’를 보겠다는 선언&lt;/h2&gt;
&lt;p&gt;이러한 격변의 흐름 속에서 등장한 것이 바로 UX디자인입니다. 앞서 언급했듯이 디자인은 그 이전에도 항상 사용자의 경험을 고민해왔습니다. 그럼에도 ‘사용자 경험 디자인(UX Design)‘이라는 용어로 이 개념을 기존의 디자인과 명시적으로 분리하는 것은, 일종의 선언이자 관점의 근본적인 이동입니다.&lt;/p&gt;
&lt;p&gt;왜냐하면 이전의 디자인이 고민하던 사용자의 경험은 주로 마케팅 관점에서의 ‘소비자’로서의 사용자에 국한된 것이었기 때문입니다. 다시 말해, 제품을 구매하는 순간의 매력에 초점이 맞춰져 있었습니다. 매대에서 경쟁 제품보다 괜찮아 보이는 특질(feature)을 제시하는 것이 핵심이었고, 주전자의 손잡이는 어떤 재질로 할 것인지, 물이 끓을 때 어떤 소리가 나게 할 것인지와 같은 감각적 호소력에 기반한 기획이 주로 이루어졌습니다. 이것은 물론 중요한 고민이지만, 구매 이후 사용자가 제품과 맺게 되는 지속적인 관계까지 깊이 들여다보는 것과는 성격이 달랐습니다.&lt;/p&gt;
&lt;p&gt;반면 사용자 경험 디자인은 이와는 다른 깊이에서 출발합니다. 제품이 구매된 이후, 사용자가 실제로 제품을 사용하는 절차 그 자체를 바라보겠다는 것입니다. 사용의 흐름 속에서 사용자와 동기화(synchronize)되어, 사용자의 인지적 경험 측면에서 문제가 되는 절차는 없는지, 있다면 이를 해소하기 위해 어떤 해결이 필요할지를 탐구하겠다고 선언합니다. 이는 곧, 소비자 관점에서 다루던 수면(surface) 위의 매력을 지나 더 깊이 잠재된 사용자의 인지라는 물속으로 잠수(deep-dive)하는 것을 의미합니다. 겉으로 보이는 형태와 감성을 넘어, 사용자의 머릿속에서 벌어지는 인지적 과정까지 디자인의 영역으로 끌어들이겠다는 전환인 셈입니다.&lt;/p&gt;
&lt;p&gt;이 잠수의 깊이를 좀 더 명확히 정의해보겠습니다. 사용자 경험 디자인의 핵심은 사용 환경에의 동기화, 그리고 그 사용 환경에서 벌어지는 인지적 절차와 사건들을 이해하고 이를 의도적으로 조작하는 데 있습니다. 사용자가 무엇을 보고, 무엇을 기대하며, 어떤 순서로 행동하는지를 파악하고 그 흐름에 맞추어 경험을 설계하는 것이 UX디자인의 본질입니다.&lt;/p&gt;
&lt;p&gt;이러한 레벨에서 기획이 이뤄진다면, 그것이 어떠한 형태를 취하고 있든 ‘UX디자인적이다’라고 이야기할 수 있습니다. 반대로, UX디자인의 방법론을 아무리 충실하게 따랐다고 해도 사용자와 진정으로 공감하고 그들의 인지 과정을 분석하지 못했다면, 이는 도구만 빌려 쓴 것일 뿐 UX디자인으로서 실행되었다고 보기 어렵습니다. 형식이 아닌 관점이 UX디자인을 규정하는 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;진보가-아니라-새로운-관점&quot;&gt;진보가 아니라, 새로운 관점&lt;/h2&gt;
&lt;p&gt;다만 여기서 한 가지 균형 잡힌 시각을 덧붙일 필요가 있습니다. 언제나 새로운 것이 정답이고 이전의 것이 오답이라고 볼 수 없듯이, 소비자 관점의 디자인에 비해 UX디자인이 무조건 우월하다고 보는 시각 역시 잘못입니다. 디자인은 언제나 그 프로젝트의 목표와 효율을 따라야 하며, UX디자인은 그러한 맥락에서 필요하다고 판단되는 때에 채택되면 되는 것입니다.&lt;/p&gt;
&lt;p&gt;사용자의 경험과 인지적 흐름에 대한 깊은 숙고가 필요한 프로젝트라면 마땅히 수행해야 하겠지만, 이미 답이 명확한 상황에서 형식적으로 논리를 짜맞추는 흐름은 오히려 위험합니다. 앞서 사용한 잠수의 비유를 이어가자면, 얕은 물에 다이빙하면 몸이 다치는 법입니다. 다이브할 만한 깊은 인지적 배경이 존재하지 않는 프로젝트에서 무리하게 UX디자인 프로세스를 진행하면, 투입된 비용과 시간에 비해 그 결과는 초라할 수밖에 없습니다. UX디자인의 가치는 그것이 적용되는 맥락의 적절성에서 비롯됩니다.&lt;/p&gt;
&lt;p&gt;지금까지 UX디자인이 왜 등장했는지, 그리고 그것이 기존의 디자인과 어떤 점에서 다른 관점을 취하는지를 살펴보았습니다. 그렇다면 이제 자연스럽게 다음 질문으로 넘어가야 합니다. 이 다이빙의 대상, 즉 UX디자인이 다루고자 하는 ‘경험’이라는 것은 대체 무엇일까요? 그것은 어떤 원리로 형성되며, 우리는 그것을 어떻게 하면 원하는 방향으로 조정할 수 있을까요?&lt;/p&gt;
&lt;p&gt;UX디자인의 선언은 마쳤으니, 다음 글에서는 그 선언이 겨냥하는 대상 자체 — ‘경험’이란 무엇인가로 들어갑니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>디자인 역사</category><category>사용자 경험</category><category>인터페이스</category></item><item><title>CLAUDE.md — AI가 내 프로젝트를 이해하고 기억하는 방법</title><link>https://blog.bepuljang.co.kr/vibecoding/03/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/03/</guid><description>Claude Code가 프로젝트 구조와 규칙을 기억하게 만드는 CLAUDE.md 파일의 작성법을 좋은 예시와 나쁜 예시로 설명합니다.</description><pubDate>Sun, 05 Jul 2026 12:12:20 GMT</pubDate><content:encoded>&lt;p&gt;Claude Code를 설치했다면 이제 본격적으로 프로젝트를 만들어볼 차례입니다. 그런데 한 가지 문제가 있습니다. Claude Code는 매우 강력하지만, 내 프로젝트에 대해 아무것도 모릅니다. 어떤 기술을 쓰는지, 폴더가 어떻게 구성되어 있는지, 어떤 규칙을 따르는지 전혀 알지 못합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;는 이 문제를 해결합니다. 프로젝트 폴더 안에 놓으면 Claude Code가 작업을 시작할 때마다 자동으로 이 파일을 읽어 프로젝트의 맥락을 이해합니다. 잘 작성된 &lt;code&gt;CLAUDE.md&lt;/code&gt; 하나가 AI의 작업 품질을 크게 바꿔놓습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claudemd가-필요한-이유&quot;&gt;CLAUDE.md가 필요한 이유&lt;/h2&gt;
&lt;p&gt;바이브코딩을 처음 시작하면 이런 경험을 하게 됩니다.&lt;/p&gt;
&lt;p&gt;처음에는 Claude Code가 원하는 대로 코드를 잘 만들어줍니다. 그런데 시간이 지나 프로젝트가 커지면 AI가 엉뚱한 방식으로 코드를 추가하기 시작합니다. 기존에 쓰던 라이브러리 대신 다른 것을 쓰거나, 폴더 구조 규칙을 무시하거나, 이미 있는 함수를 다시 만들거나 합니다.&lt;/p&gt;
&lt;p&gt;이유는 간단합니다. &lt;strong&gt;대부분의 AI는 대화창에 있는 현재의 세션 내용만 알고 있기 때문입니다.&lt;/strong&gt; 새 대화를 시작하거나 시간이 지나면 이전에 정했던 규칙과 구조를 기억하지 못합니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;를 포함한 로컬 문서들은 이 문제를 해결하는 가장 기본적이고 효과적인 방법입니다. Claude Code는 매 작업 시작 시 이 파일들을 읽어 프로젝트의 현재 상태와 규칙을 파악합니다.&lt;/p&gt;
&lt;p&gt;이를 위해 프로젝트의 최상위 폴더(루트 디렉토리)에 &lt;code&gt;CLAUDE.md&lt;/code&gt;라는 이름으로 파일을 만듭니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;my-project/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  CLAUDE.md       ← 여기에 둡니다&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  package.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code는 프로젝트 폴더에서 실행될 때 자동으로 이 파일을 찾아 읽습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;init-명령을-통한-claudemd-자동-생성&quot;&gt;&lt;code&gt;/init&lt;/code&gt; 명령을 통한 CLAUDE.md 자동 생성&lt;/h2&gt;
&lt;p&gt;사실 &lt;code&gt;CLAUDE.md&lt;/code&gt;를 처음부터 손으로 쓸 필요는 없습니다. Claude Code에는 &lt;strong&gt;&lt;code&gt;/init&lt;/code&gt;&lt;/strong&gt; 이라는 전용 명령이 있습니다.처음 프로젝트를 시작하거나 진행 중이던 프로젝트에 Claude를 처음 도입한다면, 프로젝트 폴더에서 Claude Code를 실행한 뒤 아래의 명령을 입력하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 명령을 입력하면 Claude Code가 현재 폴더의 파일들 — &lt;code&gt;package.json&lt;/code&gt;, 폴더 구조, 설정 파일 등 — 을 스스로 훑어보고 프로젝트에 맞는 &lt;code&gt;CLAUDE.md&lt;/code&gt; 초안을 자동으로 만들어주는 것을 확인할 수 있습니다. 기술 스택·폴더 구조·실행 방법 같은 기본 뼈대가 한 번에 채워집니다.&lt;/p&gt;
&lt;p&gt;다만 &lt;code&gt;/init&lt;/code&gt;이 만든 파일을 그대로 두면 안 됩니다. Claude Code가 코드만 보고 짐작한 내용이라 실제 의도와 다르거나 빠진 규칙이 있을 수 있습니다. &lt;code&gt;/init&lt;/code&gt;은 어디까지나 &lt;strong&gt;편리한 출발점&lt;/strong&gt;입니다. 아래에서 설명하는 ‘좋은 &lt;code&gt;CLAUDE.md&lt;/code&gt;’의 기준으로 직접 읽어보고 다듬거나, Claude Code와의 대화를 통해 구체적인 내용을 수정하는 과정이 필요합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이미 &lt;code&gt;CLAUDE.md&lt;/code&gt;가 있는 상태에서 &lt;code&gt;/init&lt;/code&gt;을 다시 실행하면 기존 내용을 토대로 새롭게 프로젝트를 파악해 문서를 보완할 수도 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claudemd에-담아야-할-내용&quot;&gt;CLAUDE.md에 담아야 할 내용&lt;/h2&gt;
&lt;p&gt;좋은 &lt;code&gt;CLAUDE.md&lt;/code&gt;의 판단은 새로운 팀원이 프로젝트를 이해할 수 있도록 상세하게 설명하는 문서인지 생각하면 됩니다. 대체로 아래의 내용들이 포함됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 프로젝트 개요&lt;/strong&gt;
이 프로젝트가 무엇을 하는 서비스인지 한두 문장으로 설명합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 기술 스택&lt;/strong&gt;
어떤 언어와 프레임워크, 라이브러리를 사용하는지 명시합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 폴더 구조&lt;/strong&gt;
주요 폴더가 어떤 역할을 하는지 설명합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 실행 방법&lt;/strong&gt;
개발 서버를 어떻게 실행하는지, 빌드는 어떻게 하는지 적습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 중요 규칙과 주의사항&lt;/strong&gt;
코딩 스타일, 절대 건드리면 안 되는 파일, 특별히 주의해야 할 사항을 적습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;좋은-claudemd-vs-나쁜-claudemd&quot;&gt;좋은 CLAUDE.md vs 나쁜 CLAUDE.md&lt;/h2&gt;
&lt;p&gt;실제 예시로 비교해봅니다.&lt;/p&gt;
&lt;h3 id=&quot;나쁜-claudemd--너무-짧고-추상적&quot;&gt;나쁜 CLAUDE.md — 너무 짧고 추상적&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;# 내 프로젝트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;React로 만든 웹사이트입니다.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 정도 정보로는 Claude Code가 어떤 버전의 React를 쓰는지, 상태 관리는 어떻게 하는지, 스타일링은 어떤 방식인지 알 수 없습니다. 이 문서로도 작업을 진행할 수는 있겠지만, 오류를 범할 가능성이 커서 프로젝트의 안정성과 유지도 차원에서 위험 요인이 됩니다.&lt;/p&gt;
&lt;h3 id=&quot;좋은-claudemd--구체적이고-실용적&quot;&gt;좋은 CLAUDE.md — 구체적이고 실용적&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;# 프로젝트 개요&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;온라인 독서 모임 플랫폼이다. 사용자가 모임을 만들고, 책을 등록하고, 일정을 관리할 수 있다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;## 기술 스택&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 프론트엔드: React 18, Vite, TailwindCSS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 백엔드: Node.js 20, Express 4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 데이터베이스: PostgreSQL 16&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 상태 관리: Zustand (Redux 사용하지 않음)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;## 폴더 구조&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  components/   공통 UI 컴포넌트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  pages/        페이지 단위 컴포넌트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  hooks/        커스텀 훅&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  api/          API 호출 함수&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;server/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  routes/       API 라우터&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  data/         DB 쿼리 함수&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;## 실행 방법&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;```bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 프론트엔드&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# 백엔드&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; server&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &amp;#x26;&amp;#x26; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;## 중요 규칙&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 스타일링은 반드시 TailwindCSS 클래스만 사용합니다. 인라인 스타일, CSS 파일 추가 금지.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; API 호출은 &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;`src/api/`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 폴더 안에 함수로 만들고, 컴포넌트에서 직접 fetch 호출 금지.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; TypeScript는 사용하지 않습니다. JavaScript만 씁니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 새 패키지 설치 전에 반드시 확인을 요청하세요.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;프로젝트의 목표와 지향점, 기술적 사양, 구조, 배포와 주의사항들이 포함되어 있습니다. 프로젝트에 대해 잘 모르는 상태에서 수정을 진행하더라도 오해의 범위가 크게 줄어들며, 치명적인 실수를 줄이거나 없앨 수 있어 바이브코딩 프로젝트의 안정성이 올라갑니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;프로젝트의-시기와-성격에-따라-다르게&quot;&gt;프로젝트의 시기와 성격에 따라 다르게&lt;/h2&gt;
&lt;p&gt;프로젝트를 막 시작해서 아직 구조가 없거나 애초에 모든 항목을 작성할 수 없는 프로젝트라면, 준비된 내용들만 기술해도 됩니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;markdown&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;# 프로젝트 개요&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;카페 메뉴 추천 웹서비스를 만들려고 한다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;사용자가 기분과 날씨를 선택하면 어울리는 음료를 추천해준다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF;font-weight:bold&quot;&gt;## 기술 방향&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 최대한 단순하게, 라이브러리를 많이 쓰지 않는 방향으로&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; 백엔드 없이 프론트엔드만으로 구현&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HTML, CSS, 바닐라 JavaScript로 시작&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 식으로 프로젝트 성격이나 시기 등에 따라 문서의 크기나 범주가 달라질 수 있습니다. 중요한 것은 프로젝트를 잘 이해하고 기억할 수 있도록 돕는 ‘일종의 &lt;code&gt;인수인계&lt;/code&gt; 문서로서 내용이 잘 갖춰졌는가’ 판단하는 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claudemd-업데이트&quot;&gt;CLAUDE.md 업데이트&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;는 한 번 쓰고 끝나는 문서가 아닙니다. 프로젝트의 변화에 따라 주기적으로 업데이트해야 합니다.&lt;/p&gt;
&lt;p&gt;업데이트가 필요한 상황은 이렇습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;새 라이브러리나 프레임워크를 도입했을 때&lt;/li&gt;
&lt;li&gt;폴더 구조가 크게 바뀌었을 때&lt;/li&gt;
&lt;li&gt;새로운 코딩 규칙을 정했을 때&lt;/li&gt;
&lt;li&gt;Claude Code가 계속 같은 실수를 반복할 때 (그 실수를 주의사항으로 추가)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;특히 마지막 상황이 중요합니다. Claude Code가 같은 방식으로 틀린다면 그것은 &lt;code&gt;CLAUDE.md&lt;/code&gt;에 명시되지 않은 규칙이 있다는 신호입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정리&quot;&gt;정리&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;는 Claude Code와 함께 프로젝트를 만들 때 가장 기본이 되는 파일입니다. 이 파일을 잘 작성해두면 Claude Code가 프로젝트의 맥락을 이해하고 일관성 있는 코드를 만들어냅니다. 짧아도 괜찮으니, 지금 당장 프로젝트에 기술 스택과 주요 규칙만 담은 &lt;code&gt;CLAUDE.md&lt;/code&gt;부터 만들어보세요.&lt;/p&gt;
&lt;p&gt;다음 편에서는 Claude Code와 함께 실제로 첫 번째 화면을 만드는 과정을 단계별로 따라가봅니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>Claude Code</category><category>CLAUDE.md</category><category>바이브코딩</category></item><item><title>UX디자인에 대한 흔한 오해</title><link>https://blog.bepuljang.co.kr/uxd-manifesto/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/uxd-manifesto/01/</guid><description>채용 공고에도, 기획서에도, 포트폴리오에도 등장하는 UX디자인. 익숙한 만큼 오해도 많은 이 개념을 두 가지 대표적 오해에서 출발해 다시 들여다봅니다.</description><pubDate>Fri, 03 Jul 2026 14:21:42 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UX디자인(사용자 경험 디자인).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;너무 익숙하고 자연스럽게 많이 쓰이는 용어입니다. 기업의 채용 공고에서, 프로젝트 기획서에서, 디자인 포트폴리오에서 우리는 이 용어를 일상적으로 접합니다. 이 익숙함은 우리가 이 용어와 개념을 충분히 알고 있다고 생각하게 만듭니다.&lt;/p&gt;
&lt;p&gt;그러나 조금만 관심을 갖고 들여다보면, UX디자인은 그 용어와 개념에 대한 오해가 상당히 많은 분야이기도 합니다. 불완전한 이해 위에서 여러 프로젝트가 진행되면서, 오해는 교정되기보다 오히려 관행으로 굳어져 재생산되어 왔습니다.&lt;/p&gt;
&lt;p&gt;소위 ‘전문가’로 통칭되는 사람들 사이에서도 사정은 크게 다르지 않습니다. 누군가는 UX디자인을 단순히 ‘사용자의 경험을 생각’하면 되는 것이라고 뭉뚱그려 정의하고, 또 누군가는 페르소나나 시나리오 같은 UX디자인 기법의 결과물이 제시되면 그것만으로 UX디자인 공정이 완수되었다고 간주합니다.&lt;/p&gt;
&lt;p&gt;이 두 시각은 언뜻 서로 무관해 보이지만, 공교롭게도 UX디자인에 대한 가장 대표적인 오해의 양 극단에 자리하고 있습니다. 하나는 UX디자인의 경계를 지나치게 넓게 잡아 사실상 모든 디자인 행위와 구별할 수 없게 만들고, 다른 하나는 그 경계를 지나치게 좁게 잡아 특정 산출물의 생산으로 환원해 버립니다. 넓은 쪽의 오해는 UX디자인의 정체성을 희석시키고, 좁은 쪽의 오해는 그 정신을 형식 속에 가두어 버립니다.&lt;/p&gt;
&lt;p&gt;이 두 극단 사이 어딘가에 UX디자인의 본질이 있을 것입니다. 그것을 찾기 위해, 먼저 각각의 오해가 어디에서 비롯되었는지부터 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;오해-1-사용자의-경험을-생각하는-디자인&quot;&gt;오해 1. “사용자의 경험을 생각하는 디자인”&lt;/h2&gt;
&lt;p&gt;‘사용자의 경험을 생각’한다는 말은 틀린 말이 아닙니다. 다만 너무 넓습니다. 본래 ‘디자인’이란 것이 사용자의 경험을 고려하지 않은 경우는 오히려 드물기 때문입니다.&lt;/p&gt;
&lt;p&gt;산업 디자인의 태동기부터 디자이너는 제품을 쓸 사람의 손에 맞는 형태를, 눈에 매력적인 색상을, 생활에 어울리는 비례를 고민해왔습니다. 의자를 디자인하는 사람은 앉는 이의 편안함을 생각했고, 포스터를 디자인하는 사람은 보는 이의 시선 흐름을 고려했습니다. 이것이 사용자의 경험을 생각하는 것이 아니라면 무엇이겠습니까. 이렇게 접근하면 결국 ‘디자인 = UX디자인’이라는 등식이 성립하게 되고, 그렇다면 굳이 ‘UX’라는 수식어를 붙여 별도의 영역으로 분리한 이유를 설명할 수가 없습니다.&lt;/p&gt;
&lt;p&gt;그러나 UX디자인이라는 용어와 개념이 별도로 만들어지고 사용되고 있다는 사실 자체가, 기존의 디자인과는 차별화되는 무엇인가가 분명히 존재한다는 방증입니다. 그 ‘무엇인가’를 규명하기 위해서는 ‘사용자를 생각한다’는 포괄적 선언을 넘어, UX디자인이 사용자의 경험을 ‘어떤 방식으로’, ‘어떤 깊이에서’ 다루는지를 보다 세밀하게 정의할 필요가 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;오해-2-ux디자인-기법이-사용된-디자인&quot;&gt;오해 2. “UX디자인 기법이 사용된 디자인”&lt;/h2&gt;
&lt;p&gt;넓은 정의의 반대편에는, 기법들—즉 UX디자인 방법론을 통해 산출되는 결과물의 형태—로 UX디자인을 규정하려는 시각이 있습니다. 이쪽은 반대로 너무 좁습니다.&lt;/p&gt;
&lt;p&gt;방법론은 말 그대로 도구입니다. 도구를 통해 그것이 봉사하는 목적을 유추할 수는 있지만, 도구 자체를 목적과 동일시하는 것은 명백한 오류입니다. 우리가 디자인을 할 때 마커나 포토샵과 같은 도구를 사용한다고 해서 디자인의 본질을 마커 렌더링이나 포토샵 에디팅으로 정의할 수 없는 것과 같은 이치입니다. 마커를 아무리 능숙하게 다루어도 조형적 사고가 없다면 그것은 디자인이 아니라 채색 기술에 불과하듯, UX디자인 방법론 역시 UX디자인의 개념과 정신이 그 안에 흐를 때 비로소 의미를 갖습니다.&lt;/p&gt;
&lt;p&gt;이 위험은 실무 현장에서 생각보다 자주 현실이 됩니다. 페르소나 문서를 작성했다고 해서 사용자를 이해한 것이 아니고, 시나리오를 도출했다고 해서 경험을 설계한 것이 아닙니다. 이러한 기법들이 UX디자인의 근본적인 질문—이 사용자는 왜 이렇게 행동하는가, 이 맥락에서 무엇이 경험을 형성하는가—없이 기계적으로 수행된다면, 그것은 형식만 빌려온 껍데기에 불과합니다.&lt;/p&gt;
&lt;p&gt;반대로, 어떤 정해진 기법이나 양식 없이도 사용자의 인지 구조와 행동 패턴에 깊이 공감하고 이를 디자인 판단에 일관되게 반영할 수 있다면, 그것이야말로 UX디자인적인 접근이라 할 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;그래서-ux디자인은-무엇인가&quot;&gt;그래서 UX디자인은 무엇인가&lt;/h2&gt;
&lt;p&gt;두 가지 오해를 살펴보았습니다. 너무 넓게 정의하면 UX디자인은 모든 디자인에 녹아들어 고유한 의미를 잃고, 너무 좁게 정의하면 특정 기법의 수행으로 축소됩니다. 그렇다면 UX디자인은 정확히 어떻게 정의할 수 있을까요?&lt;/p&gt;
&lt;p&gt;이 질문에 한 문장으로 깔끔하게 답할 수 있다면 좋겠지만, 성급한 한 문장은 또 다른 오해의 씨앗이 될 수 있습니다. 그래서 이 시리즈는 명쾌한 정의 하나를 제시하기보다, 그 답을 찾아가는 여정 자체를 제안하고자 합니다. UX디자인이 어떤 시대적 배경과 문제의식 속에서 등장했고 기존의 디자인 전통과 어떤 차별점을 두고 스스로를 선언했는지, 그리고 그것이 핵심적으로 다루는 ‘경험’이란 것이 인간의 내면에서 어떤 원리로 형성되고 또 어떻게 의도적으로 조형될 수 있는지를 하나씩 짚어보려 합니다.&lt;/p&gt;
&lt;p&gt;이 여정은 크게 세 갈래로 흐릅니다. 먼저 UX디자인이라는 선언이 왜 필요했는지를 역사적 맥락 속에서 살펴봅니다. 다음으로 경험을 구성하는 근본 원리로 들어가, 사용자의 인지가 어떻게 작동하고 행동이 어떤 메커니즘으로 형성되며 감정이 판단에 어떤 영향을 미치는지를 이해합니다. 마지막으로 이러한 이해를 바탕으로, 실제 디자인 과정에서 사용자의 경험을 어떻게 관찰하고 분석하고 설계할 수 있는지 그 절차와 도구를 다룹니다.&lt;/p&gt;
&lt;p&gt;이 시리즈가 궁극적으로 이야기하려는 것은 도구가 아니라 관점이며, 기법이 아니라 정신입니다. 물론 그 과정에서 구체적인 도구와 기법도 당연히 등장하겠지만, 이들은 어디까지나 관점과 정신이 실현되는 통로이지 그 자체가 목적이 아닙니다. 도구를 익히기 전에 왜 그 도구가 필요한지를 이해하는 것, 기법을 적용하기 전에 그 기법이 무엇을 포착하려는 것인지를 아는 것—이것이 이 시리즈가 제안하는 UX디자인 학습의 순서입니다.&lt;/p&gt;
&lt;p&gt;다음 글에서는 이 여정의 출발점으로, UX디자인이 대체 어떤 시대적 배경 속에서 하나의 ‘선언’으로 등장했는지를 디자인의 역사에서부터 짚어봅니다.&lt;/p&gt;</content:encoded><category>UX디자인 선언</category><category>UX디자인</category><category>사용자 경험</category><category>디자인</category></item><item><title>Claude Code 설치 방법 — 터미널부터 첫 대화까지</title><link>https://blog.bepuljang.co.kr/vibecoding/02/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/02/</guid><description>Claude Code를 처음 설치하는 과정을 터미널 사용법, Node.js 설치, 로그인(구독 또는 API 키)부터 첫 번째 프롬프트까지 단계별로 안내합니다.</description><pubDate>Fri, 03 Jul 2026 13:49:41 GMT</pubDate><content:encoded>&lt;p&gt;바이브코딩을 시작하려면 가장 먼저 도구를 설치해야 합니다. 이 글에서는 Claude Code를 처음 설치하는 과정을 터미널 사용법부터 첫 번째 대화까지 단계별로 안내합니다. 개발 경험이 없어도 따라올 수 있도록 각 단계를 최대한 자세히 설명합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;터미널이란-무엇인가&quot;&gt;터미널이란 무엇인가&lt;/h2&gt;
&lt;p&gt;터미널은 ‘끝단’, ‘단말’이라는 그 용어 자체의 말 그대로, 컴퓨터가 외부와 소통하는 가장 말단의 창입니다. 이 용어는 컴퓨터의 역사와 관련이 있는데, 방을 채울 정도로 커다란 메인프레임 컴퓨터에 접근하기 위한 소통 기기에서 비롯되었습니다.&lt;/p&gt;
&lt;p&gt;현대의 터미널은 컴퓨터에 텍스트 명령을 입력해서 작업을 수행하는 도구를 말하는데, 마우스로 아이콘을 클릭하는 대신, 키보드로 명령어를 입력해 프로그램을 설치하거나 실행합니다. 이를 커맨드 줄 인터페이스(CLI; Command Line Interface)라고 합니다.&lt;/p&gt;
&lt;p&gt;처음에는 낯설게 느껴지지만, CLI에 익숙해지면 특히 바이브코딩을 할 때에는 매우 편해지는데, 정확한 명령어를 이용하면 많은 기능을 손쉽게 수행할 수 있기 때문입니다. AI서비스가 이러한 부분들을 편하게 만들어 줄 수 있기 때문에 GUI(Graphic User Interface)로 작업을 찾아 수행하는 것보다 훨씬 빠르고 쉽게 업무를 처리할 수 있습니다. 본문의 코드 명령어를 복사하여 그대로 사용하면 이러한 장점들을 느낄 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;터미널 여는 방법&lt;/strong&gt;&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;운영체제&lt;/th&gt;&lt;th&gt;방법&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;macOS&lt;/td&gt;&lt;td&gt;&lt;code&gt;Command + Space&lt;/code&gt;로 Spotlight 검색 → “터미널” 입력 → Enter&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Windows&lt;/td&gt;&lt;td&gt;&lt;code&gt;Windows + R&lt;/code&gt; → &lt;code&gt;cmd&lt;/code&gt; 입력 → Enter (또는 PowerShell 검색)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;터미널을 열면 아래와 같은 화면이 나타납니다. 커서가 깜빡이고 있다면 명령어를 입력할 준비가 된 것입니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;사용자이름@컴퓨터이름 ~ %&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;사전-준비-nodejs-설치&quot;&gt;사전 준비: Node.js 설치&lt;/h2&gt;
&lt;p&gt;Claude Code는 Node.js 환경에서 동작합니다. 먼저 Node.js가 설치되어 있는지 확인합니다.&lt;/p&gt;
&lt;p&gt;터미널에 아래 명령어를 입력하고 Enter를 누릅니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;v20.0.0&lt;/code&gt; 같은 버전 숫자가 나오면 이미 설치된 것입니다. 아무것도 나오지 않거나 오류가 뜨면 Node.js를 설치해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node.js 설치 방법&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://nodejs.org&quot;&gt;nodejs.org&lt;/a&gt;에 접속해 LTS 버전(Long Term Support, 안정 버전)을 다운로드합니다. 설치 파일을 실행하고 기본 설정 그대로 완료합니다.&lt;/p&gt;
&lt;p&gt;설치 후 터미널을 새로 열고 &lt;code&gt;node --version&lt;/code&gt;을 다시 실행해 버전이 표시되면 정상입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claude-code-설치&quot;&gt;Claude Code 설치&lt;/h2&gt;
&lt;p&gt;Node.js가 준비됐으면 Claude Code를 설치합니다. 터미널에 아래 명령어를 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -g&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; @anthropic-ai/claude-code&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-g&lt;/code&gt;는 ‘global’을 의미하며, 컴퓨터 전체에서 사용할 수 있도록 ‘전역’ 설치한다는 의미입니다. 즉, 이렇게 설치된 프로그램은 앞으로 어떤 폴더에서도 실행될 수 있습니다. 설치에는 1~2분 정도 걸립니다.&lt;/p&gt;
&lt;p&gt;설치가 완료되면 아래 명령어로 확인합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;버전 번호가 출력되면 정상적으로 설치된 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;로그인-방법-정하기-구독-또는-api-키&quot;&gt;로그인 방법 정하기: 구독 또는 API 키&lt;/h2&gt;
&lt;p&gt;Claude Code를 사용하려면 로그인이 필요합니다. 로그인 방법은 크게 두 가지이며, 대부분의 개인 사용자에게는 첫 번째 방법을 권장합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;방법 1 : Claude 구독으로 로그인 (권장)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Claude Pro나 Max 같은 구독 요금제를 쓰고 있다면, 별도의 API 키 발급이나 크레딧 충전 없이 그 계정으로 바로 로그인할 수 있습니다. 사용량은 구독 요금제 한도 안에서 처리되므로, 매달 정액으로 쓰면서 사용할 때마다 비용이 얼마 나올지 신경 쓰지 않아도 됩니다. 아직 구독이 없다면 &lt;a href=&quot;https://claude.ai&quot;&gt;claude.ai&lt;/a&gt;에서 요금제를 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;방법 2: Anthropic API 키 사용&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;구독 대신 사용한 만큼 비용을 지불하는 방식(pay-as-you-go)을 원한다면 API 키를 발급받아 사용할 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://console.anthropic.com&quot;&gt;console.anthropic.com&lt;/a&gt;에 접속해 계정을 만들고 로그인합니다.&lt;/li&gt;
&lt;li&gt;왼쪽 메뉴에서 &lt;code&gt;API Keys&lt;/code&gt;를 선택한 뒤 &lt;code&gt;Create Key&lt;/code&gt;를 눌러 키를 만듭니다. 키는 &lt;code&gt;sk-ant-&lt;/code&gt;로 시작하는 긴 문자열이며, 생성 직후 한 번만 표시되므로 안전한 곳에 복사해 둡니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Billing&lt;/code&gt; 메뉴에서 크레딧을 충전합니다. 처음이라면 $5~10 정도면 가벼운 바이브코딩 작업을 꽤 오래 할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;API 키 방식은 사용한 토큰만큼 요금이 청구됩니다. 구독 로그인은 정액제라 사용량 예측이 쉽고, 초보자라면 어느 쪽이든 부담이 크지 않습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&quot;claude-code-첫-실행&quot;&gt;Claude Code 첫 실행&lt;/h2&gt;
&lt;p&gt;터미널에서 작업할 폴더로 이동한 뒤 Claude Code를 실행합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;claude&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;처음 실행하면 로그인 방법을 선택하는 화면이 나타납니다. 구독으로 로그인하려면 Claude 계정 로그인을 선택합니다. 웹 브라우저가 열리면 계정으로 로그인해 인증을 마칩니다. API 키를 쓰기로 했다면 해당 방법을 선택한 뒤 앞에서 복사한 키를 붙여넣고 Enter를 누릅니다.&lt;/p&gt;
&lt;p&gt;로그인이 완료되면 아래와 같은 화면이 나타납니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Claude Code&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&gt;&lt;/code&gt; 뒤에 커서가 깜빡이면 준비가 된 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;첫-번째-프롬프트-보내기&quot;&gt;첫 번째 프롬프트 보내기&lt;/h2&gt;
&lt;p&gt;Claude Code와 첫 대화를 시작해봅니다. &lt;code&gt;&gt;&lt;/code&gt; 뒤에 아래를 입력하고 Enter를 누릅니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;간단한 HTML 파일을 하나 만들어줘. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;제목은 &quot;안녕, 바이브코딩&quot;이고, 가운데 정렬된 큰 텍스트로 &quot;AI와 함께 만든 첫 페이지&quot;라고 &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;표시해줘.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Claude Code가 파일을 생성하려고 할 때 권한을 묻는 메시지가 나타나면 승낙하고 Enter를 누릅니다.&lt;/p&gt;
&lt;p&gt;잠시 후 &lt;code&gt;.html&lt;/code&gt; 파일이 생성됩니다. 이 파일을 브라우저에서 열면 방금 요청한 페이지가 나타납니다. 첫 번째 바이브코딩에 성공한 것입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;자주-쓰는-claude-code-명령어&quot;&gt;자주 쓰는 Claude Code 명령어&lt;/h2&gt;
&lt;p&gt;Claude Code를 사용하면서 알아두면 유용한 기본 명령어입니다.&lt;/p&gt;





































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;명령어&lt;/th&gt;&lt;th&gt;설명&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;claude&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Claude Code 실행&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/help&lt;/code&gt;&lt;/td&gt;&lt;td&gt;사용 가능한 명령어 목록 표시&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/clear&lt;/code&gt;&lt;/td&gt;&lt;td&gt;대화 내용 초기화&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/compact&lt;/code&gt;&lt;/td&gt;&lt;td&gt;대화 내용 요약&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/mcp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;MCP (Model Context Protocols) 목록 호출&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;/exit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Claude Code 종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl + C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;현재 작업 중단&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;이 중 &lt;code&gt;/compact&lt;/code&gt;는 세션에서 진행된 대화 내용을 압축하여 이후에 진행될 대화 과정에서 소모되는 토큰을 절약하는 명령입니다. 너무 자주 사용되면 맥락이 자주 끊어져 방해가 되지만, 적당하게 잘 사용하면 토큰 사용량 관리에 큰 도움이 됩니다. &lt;code&gt;/mcp&lt;/code&gt;에 대해서는 추후 MCP에 대해 소개하면서 다시 이야기할 예정입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;폴더-이동-방법&quot;&gt;폴더 이동 방법&lt;/h2&gt;
&lt;p&gt;터미널에서 특정 프로젝트 폴더로 이동하려면 &lt;code&gt;cd&lt;/code&gt; 명령어를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 폴더경로&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;예를 들어 바탕화면에 &lt;code&gt;my-project&lt;/code&gt;라는 폴더를 만들고 그 안에서 작업하려면 아래와 같이 입력합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# macOS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ~/Desktop/my-project&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Windows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; C:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\U&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;sers&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\사&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;용자이름&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\D&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;esktop&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\m&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;y-project&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;현재 어느 폴더에 있는지 확인하려면 아래 명령어를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# macOS / Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;pwd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Windows&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h2 id=&quot;정리&quot;&gt;정리&lt;/h2&gt;
&lt;p&gt;지금까지 터미널을 열고, Node.js와 Claude Code를 설치하고, API 키를 발급해서 첫 번째 프롬프트를 보내는 과정을 마쳤습니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 Claude Code가 내 프로젝트를 제대로 이해하도록 &lt;code&gt;CLAUDE.md&lt;/code&gt; 파일을 작성하는 방법을 다룹니다. 이 파일 하나가 AI의 작업 품질을 크게 바꿔놓습니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>Claude Code</category><category>설치</category><category>터미널</category><category>바이브코딩</category></item><item><title>바이브코딩이란?</title><link>https://blog.bepuljang.co.kr/vibecoding/01/</link><guid isPermaLink="true">https://blog.bepuljang.co.kr/vibecoding/01/</guid><description>AI가 코드를 대신 써주는 바이브코딩의 개념, 적합한 상황, 그리고 Cursor·Claude Code·Copilot 등 대표 도구를 비교합니다.</description><pubDate>Thu, 02 Jul 2026 06:29:52 GMT</pubDate><content:encoded>&lt;p&gt;AI가 코드를 대신 써주는 시대가 왔다는 말을 들어보셨나요? 최근 ‘바이브코딩(Vibe Coding)‘이라는 단어가 빠르게 퍼지고 있습니다. 기존의 직접 개발에서 중시하던 논리나 로직보다 분위기나 느낌(Vibe)을 중심으로 코딩한다는 의미인데, 자연어를 이해하고 이를 코드로 직접 번역해줄 수 있는 AI 서비스들이 등장하면서 이러한 용어가 생겨나게 된 것입니다.&lt;/p&gt;
&lt;p&gt;즉, 코드를 직접 작성하지 않고, AI와 대화하며 소프트웨어를 만드는 이 방식은 ‘개발 경험이 없는 사람도 실제 서비스를 만들 수 있게’ 해주고 있습니다.&lt;/p&gt;
&lt;p&gt;이 글에서는 바이브코딩이 정확히 무엇인지, 어떤 도구들이 있는지, 그리고 어떻게 시작하면 되는지를 정리합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;바이브코딩이란-무엇인가&quot;&gt;바이브코딩이란 무엇인가&lt;/h2&gt;
&lt;p&gt;바이브코딩이라는 용어를 처음 사용한 것으로 알려진 AI 연구자 안드레이 카르파시(Andrej Karpathy)는 자신의 개발 방식을 이렇게 설명했습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“완전히 LLM에 자신을 맡기고, 코드를 거의 보지 않으며, 오류 메시지를 그대로 복사해서 붙여넣는다.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;즉, &lt;strong&gt;코드를 읽고 이해하는 것보다, AI에게 무엇을 만들고 싶은지 설명하는 것&lt;/strong&gt;에 집중하고 코드를 짜는 데 필요하던 인지적 비용을 더 좋은 서비스를 만들기 위한 ‘느낌’에 투자한다는 것입니다.&lt;/p&gt;
&lt;p&gt;기존 개발 방식과 비교하면 이렇습니다.&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;구분&lt;/th&gt;&lt;th&gt;기존 개발 방식&lt;/th&gt;&lt;th&gt;바이브코딩&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;주된 작업&lt;/td&gt;&lt;td&gt;직접 코드 작성&lt;/td&gt;&lt;td&gt;프롬프트로 AI에게 지시&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;필요 지식&lt;/td&gt;&lt;td&gt;프로그래밍 언어, 알고리즘&lt;/td&gt;&lt;td&gt;원하는 것을 명확히 설명하는 능력&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;속도&lt;/td&gt;&lt;td&gt;구현 속도가 지식에 비례&lt;/td&gt;&lt;td&gt;아이디어를 빠르게 코드로 전환 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;오류 대응&lt;/td&gt;&lt;td&gt;직접 디버깅&lt;/td&gt;&lt;td&gt;오류 내용을 AI에게 전달&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;진입 장벽&lt;/td&gt;&lt;td&gt;높음&lt;/td&gt;&lt;td&gt;낮음&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;바이브코딩이 가능해진 배경에는 GPT-4, Claude, Gemini 같은 대형 언어 모델의 코드 이해 능력이 크게 향상된 것이 있습니다. 이제 AI는 단순히 코드 조각을 생성하는 수준을 넘어, 프로젝트 전체 구조를 이해하고 맥락에 맞는 코드를 작성할 수 있습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;바이브코딩-누구에게-유용한가&quot;&gt;바이브코딩, 누구에게 유용한가&lt;/h2&gt;
&lt;p&gt;위에서 설명한 바와 같이, 바이브코딩의 본질은 기존에 서비스를 개발하는 역량을 일정 수준 가진 사용자가 자신의 역량과 에너지를 ‘바이브’에 투자하여 더 좋은 서비스를 더 효율적으로 만들어내는 데 있습니다. 따라서, 모든 경우에 바이브코딩이 통하거나 유용하다기보다는 아래와 같이 경우에 따라 바이브코딩이 잘 맞을 수도, 한계를 보일 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;바이브코딩이 잘 맞는 경우&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;아이디어를 빠르게 프로토타입으로 만들고 싶을 때&lt;/li&gt;
&lt;li&gt;개발 경험은 없지만 서비스를 직접 만들어보고 싶을 때&lt;/li&gt;
&lt;li&gt;반복적인 구현 작업을 빠르게 처리하고 싶을 때&lt;/li&gt;
&lt;li&gt;사이드 프로젝트나 MVP를 빠르게 검증하고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;바이브코딩이 한계를 보이는 경우&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;보안이 매우 중요한 시스템을 구축할 때&lt;/li&gt;
&lt;li&gt;성능 최적화가 핵심인 대규모 서비스를 구축할 때&lt;/li&gt;
&lt;li&gt;복잡한 알고리즘 설계가 필요할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;즉, 바이브코딩은 아이디어를 빠르게 구현하고 검증하는 단계에서 강력한 도구입니다. 아무런 지식이나 경험 없이 서비스를 온전히 만들고 운영할 수 있다고 생각할 수 있지만, 실제로는 기존의 도구보다 월등히 편한 도구일 뿐, 결국 중요한 지식과 역량은 사용자가 갖춰야 하는 점을 주의해야 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;대표-바이브코딩-도구-비교&quot;&gt;대표 바이브코딩 도구 비교&lt;/h2&gt;
&lt;p&gt;현재 시장에는 다양한 AI 코딩 도구가 있습니다. 각 도구의 특성을 이해하면 자신의 상황에 맞는 도구를 선택하는 데 도움이 됩니다.&lt;/p&gt;





























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;도구&lt;/th&gt;&lt;th&gt;유형&lt;/th&gt;&lt;th&gt;특징&lt;/th&gt;&lt;th&gt;가격&lt;/th&gt;&lt;th&gt;추천 대상&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;IDE&lt;/td&gt;&lt;td&gt;VS Code 기반 에디터. 코드베이스 전체를 이해하고 수정&lt;/td&gt;&lt;td&gt;월 $20 (무료 플랜 있음)&lt;/td&gt;&lt;td&gt;기존 개발자, 큰 프로젝트&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;CLI&lt;/td&gt;&lt;td&gt;터미널 기반. 파일 시스템 전체 접근, MCP 연동 지원&lt;/td&gt;&lt;td&gt;API 사용량 기반&lt;/td&gt;&lt;td&gt;자동화, 복잡한 프로젝트&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;IDE 플러그인&lt;/td&gt;&lt;td&gt;VS Code, JetBrains 등에서 자동완성 위주 지원&lt;/td&gt;&lt;td&gt;월 $10~19&lt;/td&gt;&lt;td&gt;기존 개발 환경 유지하면서 AI 보조 원하는 개발자&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Windsurf&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;IDE&lt;/td&gt;&lt;td&gt;Cursor와 유사. Codeium 기반&lt;/td&gt;&lt;td&gt;무료 플랜 있음&lt;/td&gt;&lt;td&gt;비용 부담 없이 시작하고 싶은 입문자&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bolt.new&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;웹&lt;/td&gt;&lt;td&gt;브라우저에서 바로 사용. 설치 불필요. 배포까지 포함&lt;/td&gt;&lt;td&gt;무료 플랜 있음&lt;/td&gt;&lt;td&gt;설치 없이 바로 시작하고 싶은 완전 초보자&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;v0 (Vercel)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;웹&lt;/td&gt;&lt;td&gt;UI 컴포넌트 생성 특화. React/Next.js 중심&lt;/td&gt;&lt;td&gt;무료 플랜 있음&lt;/td&gt;&lt;td&gt;프론트엔드 UI 빠르게 만들고 싶을 때&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Replit Agent&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;웹&lt;/td&gt;&lt;td&gt;코드 작성부터 실행, 배포까지 웹에서 처리&lt;/td&gt;&lt;td&gt;유료&lt;/td&gt;&lt;td&gt;환경 설정 없이 전체 흐름을 경험하고 싶을 때&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;도구별-상세-특징&quot;&gt;도구별 상세 특징&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt;
현재 바이브코딩 도구 중 가장 많이 사용되는 도구입니다. VS Code를 기반으로 만들어져 기존 코드 에디터와 유사한 경험을 제공합니다. 프로젝트 전체 코드를 AI가 이해하고, 파일 간 관계를 파악하며 코드를 수정합니다. 이미 개발 경험이 있거나 규모 있는 프로젝트를 다루는 사람에게 적합합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;
Anthropic이 만든 터미널 기반 AI 코딩 도구입니다. IDE가 아닌 터미널(명령줄)에서 동작하며, 파일을 읽고 쓰고 삭제하는 등 시스템 전반에 접근할 수 있습니다. MCP(Model Context Protocol)를 지원해 외부 서비스와 연동이 가능한 것이 특징입니다. 자동화 작업이나 복잡한 프로젝트 구조를 다룰 때 강점을 보입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt;
GitHub과 Microsoft가 만든 AI 코딩 보조 도구입니다. VS Code, JetBrains, Vim 등 다양한 에디터에 플러그인 형태로 설치합니다. 기존에 사용하던 에디터 환경을 유지하면서 AI 자동완성 기능을 추가하고 싶은 개발자에게 적합합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bolt.new&lt;/strong&gt;
설치 없이 브라우저에서 바로 사용할 수 있는 도구입니다. 프로젝트 생성부터 배포까지 브라우저 안에서 처리합니다. 환경 설정의 진입 장벽이 없어 완전 초보자가 바이브코딩을 처음 경험해보기에 좋습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;이-시리즈는-claude-code를-중심으로-설명합니다&quot;&gt;이 시리즈는 Claude Code를 중심으로 설명합니다.&lt;/h2&gt;
&lt;p&gt;바이브코딩 도구는 여러 가지가 있고, 각각 장단점이 다릅니다. 이 시리즈에서는 &lt;strong&gt;Claude Code&lt;/strong&gt;를 기준으로 설명할 예정입니다.&lt;/p&gt;
&lt;p&gt;Claude Code를 선택한 이유는 터미널 기반이라 환경을 직접 컨트롤할 수 있고, MCP 연동으로 외부 도구와 연결이 가능하며, 파일 시스템 전체에 접근해 복잡한 프로젝트 구조도 다룰 수 있기 때문입니다. 바이브코딩의 본질인 ‘바이브’ 만으로 코딩을 하기에 가장 적합한 도구라는 점에서 선정하였습니다.&lt;/p&gt;
&lt;p&gt;다음 편에서는 Claude Code를 실제로 설치하는 방법을 터미널 사용법부터 단계별로 안내합니다.&lt;/p&gt;</content:encoded><category>누구나 따라하는 바이브코딩</category><category>바이브코딩</category><category>AI 코딩</category><category>Claude Code</category><category>Cursor</category></item></channel></rss>