<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title> 번뜩 </title>
    <link>https://tech-interview.tistory.com/</link>
    <description>CS 지식과 공부하다 배운 것, 경험한 것 등을 기록하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Mon, 18 May 2026 19:05:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Blxxming</managingEditor>
    <image>
      <title> 번뜩 </title>
      <url>https://tistory1.daumcdn.net/tistory/3868248/attach/8e434b77b66d4342baa61d4465fdb377</url>
      <link>https://tech-interview.tistory.com</link>
    </image>
    <item>
      <title>[AI][Claude] Command, Skill, Subagent</title>
      <link>https://tech-interview.tistory.com/325</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Command, Skill, Subagent&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code의 확장 메커니즘 중 Command, Skill, Subagent는 형태가 비슷해서 점점 커지는 개념(Command &amp;lt; Skill &amp;lt; Subagent)으로 묶어 정리하기 쉬운데, 실제 분기점은 그 축이 아니다. 이 글은 차이를 정리하고, 어떤 상황에 무엇을 써야 하는지 짚는다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 왜 이렇게 헷갈릴 수밖에 없는가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 개념이 헷갈리는 데는 이유가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;셋 다 &lt;code&gt;.claude/&lt;/code&gt; 하위 디렉토리에 markdown으로 정의한다.&lt;/li&gt;
&lt;li&gt;셋 다 사용자가 직접 만드는 커스텀 확장이다.&lt;/li&gt;
&lt;li&gt;셋 다 frontmatter + 본문 markdown이라는 같은 형식을 쓴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기에 더해, 2026년 1월 Claude Code 2.1.0 릴리스에서 Custom slash command가 Skill로 통합됐다. 공식 릴리스 노트의 표현을 그대로 옮기면 &quot;슬래시 커맨드와 스킬을 병합하여 멘탈 모델을 단순화한다, 동작 변화는 없다&quot;이다.&amp;nbsp;이제 &lt;code&gt;.claude/commands/deploy.md&lt;/code&gt;와 &lt;code&gt;.claude/skills/deploy/SKILL.md&lt;/code&gt;는 둘 다 &lt;code&gt;/deploy&lt;/code&gt;를 만들고 동일하게 동작한다. 같은 이름이면 skill이 우선한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기존 .claude/commands/ 파일은 그대로 작동한다. 하지만 새로 만든다면 skill 형태가 권장된다. 디렉토리 구조 + frontmatter 옵션이 더 풍부하기 때문이다.&lt;/blockquote&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 51px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Command&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;사용자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;/로 명시적으로 부르는 단축 진입점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skill&lt;/td&gt;
&lt;td&gt;모델이 description 매칭으로 자동 발견해서 끌어다 쓰는 노하우 묶음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subagent&lt;/td&gt;
&lt;td&gt;별도 컨텍스트에서 일하고 결과만 돌려주는 전문 동료&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Command는 사실상 &quot;user-invoked Skill&quot;이다. Skill 정의에 &lt;code&gt;disable-model-invocation: true&lt;/code&gt;를 켜면 사용자만 부를 수 있는 형태가 되고, 이게 사실상 예전의 Command다. 통합되기 전후로 동작이 같다는 게 이런 의미다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 진짜&amp;nbsp;차이는&amp;nbsp;&quot;크기&quot;가&amp;nbsp;아니라&amp;nbsp;&quot;어디서&amp;nbsp;실행되는가&quot;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Command, Skill, Subagent를 정의 파일 분량으로 비교하면 점점 커지는 그라데이션처럼 보인다. Command는 프롬프트 한 덩어리, Skill은 디렉토리에 부속 파일까지, Subagent는 시스템 프롬프트에 도구 권한까지. 그래서 &quot;좀 무거운 작업은 subagent 급&quot;이라는 직관이 생기기 쉽다. 하지만 정의 파일의 길이는 부차적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;진짜 분기점은 크기가 아니다. 어디서 실행되느냐다&lt;/span&gt;. &lt;span style=&quot;background-color: #ffffff;&quot;&gt;500줄짜리&amp;nbsp;거대한&amp;nbsp;skill도&amp;nbsp;결국&amp;nbsp;skill이다.&amp;nbsp;시스템&amp;nbsp;프롬프트&amp;nbsp;10줄짜리&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;작은&amp;nbsp;subagent도&amp;nbsp;여전히&amp;nbsp;subagent다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;항목&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Command&amp;nbsp;/&amp;nbsp;Skill&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Subagent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;실행 위치&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메인&amp;nbsp;Claude&amp;nbsp;컨텍스트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;별도&amp;nbsp;인스턴스,&amp;nbsp;자체&amp;nbsp;컨텍스트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;읽은 파일&amp;middot;도구 결과&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메인&amp;nbsp;컨텍스트에&amp;nbsp;누적&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;subagent&amp;nbsp;안에만&amp;nbsp;누적,&amp;nbsp;메인에는&amp;nbsp;요약만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;호출 주체&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;사용자(slash)&amp;nbsp;또는&amp;nbsp;모델(auto-invoke)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메인&amp;nbsp;Claude가&amp;nbsp;위임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;적합한 용도&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메인&amp;nbsp;흐름에서&amp;nbsp;그대로&amp;nbsp;이어갈&amp;nbsp;작업&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;메인을&amp;nbsp;더럽히지&amp;nbsp;않고&amp;nbsp;격리할&amp;nbsp;작업&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨텍스트가 폭발하는 시나리오&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증 흐름을 분석한다고 해보자. 관련 파일이 30개쯤 흩어져 있다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Skill로&amp;nbsp;처리한&amp;nbsp;경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;메인 Claude가 30개 파일을 직접 Read한다. 파일 내용 전체가 메인 컨텍스트에 쌓인다. 분석이 끝났을 때 컨텍스트의 상당 부분이 인증 코드로 차 있다. 이 상태에서 후속 질문(&quot;이제 결제 모듈도 봐줘&quot;)을 하면, 결제 파일을 읽으면서 앞서 본 인증 컨텍스트가 점점 밀려난다. 길게 가는 세션에서 이 누적이 치명적이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Subagent로 처리한 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인은 auth-researcher에 위임만 한다. subagent가 별도 컨텍스트에서 30개 파일을 읽고, 분석을 마친 뒤 요약만 메인에 돌려준다. 메인 컨텍스트에는 &quot;인증은 이런 구조다&quot;라는 한 덩어리만 남는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;같은 작업, 같은 결과다. 차이는 메인 컨텍스트의 깨끗함이다. 후속 작업이 많을수록 차이가 벌어진다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 차이점 및 활용 가이드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;PR 리뷰&quot;라는 한 가지 작업을 Command, Skill, Subagent으로 각각 만들어 결과물이 어떻게 다른지 비교해보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Command 버전 : 사용자가 명시적으로 부른다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.claude/skills/review/SKILL.md&lt;/code&gt;로 만든다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기존 .claude/commands/review.md 형태도 동일하게 동작한다.&lt;/blockquote&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: review
description: 변경사항을 체크리스트로 리뷰
disable-model-invocation: true
---

현재 변경사항을 다음 항목으로 리뷰해줘.

1. 에러 핸들링이 빠진 곳
2. 하드코딩된 값
3. 테스트가 필요한 부분
4. 네이밍이 어색한 부분

각 항목은 `파일명:라인번호` 형태로 인용한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;disable-model-invocation: true&lt;/code&gt;를 켰기 때문에 사용자가 &lt;code&gt;/review&lt;/code&gt;를 직접 입력해야만 발동한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;h3 data-ke-size=&quot;size23&quot;&gt;Skill 버전 : 모델이 알아서 발동한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 형태에서 &lt;code&gt;disable-model-invocation&lt;/code&gt;만 빼고 description을 자세히 써준다. 디렉토리에 부속 파일도 같이 둔다.&lt;/p&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;.claude/skills/review/
├── SKILL.md
├── checklist.md
└── examples/
    ├── good-review.md
    └── bad-review.md&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: review
description: 사용자가 코드 리뷰, PR 리뷰, 변경사항 검토를 요청할 때 자동 발동. diff, commit, pull request 키워드를 감지하면 활성화한다.
---

팀의 코드 리뷰 가이드는 checklist.md에 있다. 좋은/나쁜 리뷰 예시는 examples/ 디렉토리를 참고한다.

(체크리스트 + 톤 가이드 + 예시 reference)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;/review&lt;/code&gt;를 명시적으로 치지 않아도, &quot;방금 바꾼 거 한 번 봐줘&quot; 같은 자연스러운 요청에 description 매칭으로 알아서 끌려 들어온다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;발동 주체: 모델 (description 매칭)&lt;/li&gt;
&lt;li&gt;실행 위치: 메인 컨텍스트&lt;/li&gt;
&lt;li&gt;supporting 파일 덕분에 팀 가이드, 예시, 헬퍼 스크립트를 같이 묶을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Subagent 버전 : 별도 컨텍스트에서 처리한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.claude/agents/code-reviewer.md&lt;/code&gt;로 만든다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: code-reviewer
description: 변경사항을 별도 컨텍스트에서 정밀 리뷰. PR 단위 분석에 사용.
tools: Read, Grep, Glob
---

너는 시니어 코드 리뷰어다. 다음 절차로 일한다.

1. `git diff`로 변경사항 전체를 파악
2. 영향받는 모든 파일을 Read
3. 관련 테스트 파일을 Grep으로 확인
4. 다음 구조로 보고서 반환
   - Summary
   - Issues (severity별)
   - Suggestions
   - Test gaps

Write 권한이 없다. 분석과 보고만 한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 Claude가 &quot;code-reviewer로 이번 PR 리뷰해줘&quot;라고 위임하면, 별도 인스턴스가 자기 컨텍스트에서 모든 파일을 읽고 분석해서 보고서만 돌려준다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;발동 주체: 메인 Claude의 위임&lt;/li&gt;
&lt;li&gt;실행 위치: 별도 컨텍스트&lt;/li&gt;
&lt;li&gt;메인은 보고서만 받는다.&lt;/li&gt;
&lt;li&gt;tools로 도구 권한을 제한할 수 있어서 안전하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;활용 가이드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10개 파일 규모의 PR을 각각 처리했다고 해보자. 작업이 끝난 뒤 메인 컨텍스트에 남는 것은 다음과 같다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Command&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;변경된 파일 10개 내용 + 체크리스트 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Skill&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;변경된 파일 10개 내용 + 가이드 + 예시 + 체크리스트 응답&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Subagent&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;보고서 한 덩어리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Command와 Skill은 메인에서 직접 처리하기 때문에 읽은 파일이 컨텍스트에 그대로 쌓인다. Subagent는 별도 컨텍스트에서 처리하고 결과만 던져주기 때문에 메인은 깔끔하게 유지된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;짧은 체크리스트, 결과를 바로 메인 대화에서 이어 쓸 작업&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Command (= user-invoked Skill)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;자동으로 끌려 들어왔으면 좋겠고, 가이드/예시가 풍부한 작업&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Skill (auto-invoke)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;큰 코드베이스 분석, 메인 컨텍스트 보호가 중요한 작업&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Subagent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;도구 권한을 제한해야 하는 작업 (Write 금지 등)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Subagent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;매번 같은 30개 파일을 읽어야 하는 리서치성 작업&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Subagent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;의심스러우면 두 질문만 던지면 된다. &quot;메인 컨텍스트에 결과 디테일이 남아있어야 하나?&quot; &quot;예&quot;면 Skill, &quot;아니오, 요약만 있으면 됨&quot;이면 Subagent다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 자주 빠지는 함정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Subagent 남발하면 디테일을 잃는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;격리가 좋다고 해서 모든 걸 subagent로 보내면, 메인은 매번 깔끔한 요약만 받게 된다. 깔끔한데 정작 후속 작업이 안 된다. 예를 들어 리뷰 보고서를 받았는데 &quot;auth.py:42에 race condition 가능성&quot;이라는 줄이 있다. 메인 Claude는 그 코드를 본 적이 없어서 후속 질문에 답하려면 다시 파일을 읽어야 한다. 즉, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;격리는 컨텍스트를 절약하는 대신 디테일에 대한 직접 접근을 잃는 거래&lt;/span&gt;다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;description이 너무 generic하면 엉뚱한 상황에 발동한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill의 auto-invoke는 description 매칭이다. &quot;코드 분석&quot;처럼 광범위한 description을 쓰면, 단순한 코드 질문에도 skill이 끌려 들어온다. 매번 불필요하게 supporting 파일까지 컨텍스트로 들어오니까 토큰만 낭비된다. description은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&quot;언제 발동해야 하는지&quot; 와 &quot;언제 발동하면 안 되는지&quot; 가 모두 명확&lt;/span&gt;해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Subagent에 도구 권한을 너무 많이 주면 격리의 의미가 흐려진다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Subagent의 가치 중 하나는 도구 권한을 제한할 수 있다는 점이다. &lt;code&gt;tools: Read, Grep, Glob&lt;/code&gt;만 준 reviewer는 코드를 절대 수정할 수 없다. 그런데 &quot;혹시 모르니까&quot; Write까지 다 풀어주면 격리된 일꾼이 아니라 그냥 또 다른 메인 에이전트가 된다. &lt;span style=&quot;background-color: #f6e199;&quot;&gt;권한 최소화는 subagent의 핵심 효용&lt;/span&gt;이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;같은 이름의 command/skill 충돌&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.claude/commands/deploy.md&lt;/code&gt;와 &lt;code&gt;.claude/skills/deploy/SKILL.md&lt;/code&gt;가 둘 다 있으면 skill이 우선한다. 마이그레이션 중간에 이걸 모르고 양쪽을 다 두면, 자기가 의도한 command가 안 불리고 다른 skill이 동작하는 경우가 생긴다. 옮길 때는 한쪽을 깔끔히 비워두자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 같이 알면 좋은 확장들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본문에서 다룬 기능 외에도 Claude Code의 확장 메커니즘은 더 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;CLAUDE.md&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;가장&amp;nbsp;단순한&amp;nbsp;baseline.&amp;nbsp;항상&amp;nbsp;적용되는&amp;nbsp;프로젝트&amp;nbsp;컨벤션&amp;nbsp;저장소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Hooks&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;이벤트&amp;nbsp;기반&amp;nbsp;발동&amp;nbsp;(PreToolUse,&amp;nbsp;PostToolUse&amp;nbsp;등).&amp;nbsp;발동&amp;nbsp;방식이&amp;nbsp;다른&amp;nbsp;카테고리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Plugins&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Skills&amp;nbsp;+&amp;nbsp;Subagents&amp;nbsp;+&amp;nbsp;Commands를&amp;nbsp;묶어&amp;nbsp;배포하는&amp;nbsp;패키지&amp;nbsp;단위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;MCP&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;외부&amp;nbsp;도구&amp;middot;데이터&amp;nbsp;연결.&amp;nbsp;본&amp;nbsp;글의&amp;nbsp;셋과는&amp;nbsp;다른&amp;nbsp;축의&amp;nbsp;확장&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/skills&quot;&gt;Extend Claude with skills - Claude Code Docs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778053168739&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Extend Claude with skills - Claude Code Docs&quot; data-og-description=&quot;Create, manage, and share skills to extend Claude's capabilities in Claude Code. Includes custom commands and bundled skills.&quot; data-og-host=&quot;code.claude.com&quot; data-og-source-url=&quot;https://code.claude.com/docs/en/skills&quot; data-og-url=&quot;https://code.claude.com/docs/en/skills&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btaQMD/dJMb82eQYB9/j6BXU8qEm692ugQ18WftKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/sQ0gB/dJMb84X2HJQ/GxWuRSgp5sJLDeqcRNgYTK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/skills&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://code.claude.com/docs/en/skills&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btaQMD/dJMb82eQYB9/j6BXU8qEm692ugQ18WftKK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/sQ0gB/dJMb84X2HJQ/GxWuRSgp5sJLDeqcRNgYTK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Extend Claude with skills - Claude Code Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create, manage, and share skills to extend Claude's capabilities in Claude Code. Includes custom commands and bundled skills.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.claude.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/sub-agents&quot;&gt;Subagents - Claude Code Docs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778053170327&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Create custom subagents - Claude Code Docs&quot; data-og-description=&quot;Create and use specialized AI subagents in Claude Code for task-specific workflows and improved context management.&quot; data-og-host=&quot;code.claude.com&quot; data-og-source-url=&quot;https://code.claude.com/docs/en/sub-agents&quot; data-og-url=&quot;https://code.claude.com/docs/en/sub-agents&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/crLCOl/dJMb88e4EhB/7twEnS8QcYSLFNX6gTeQV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cjuPIP/dJMb81G1kEN/xkUoHL4q4pTiknvPrxd971/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/sub-agents&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://code.claude.com/docs/en/sub-agents&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/crLCOl/dJMb88e4EhB/7twEnS8QcYSLFNX6gTeQV1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cjuPIP/dJMb81G1kEN/xkUoHL4q4pTiknvPrxd971/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Create custom subagents - Claude Code Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create and use specialized AI subagents in Claude Code for task-specific workflows and improved context management.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.claude.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code&quot;&gt;claude-code GitHub&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778053172518&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - anthropics/claude-code: Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, a&quot; data-og-description=&quot;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/anthropics/claude-code&quot; data-og-url=&quot;https://github.com/anthropics/claude-code&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b0pY5C/dJMb8YXPw9M/ObGoxYzSFkWC9MHYb7ScBk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/fNjUo/dJMb9eTTyRE/o5t8KtGxWGbENwKCpFlcd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/anthropics/claude-code&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b0pY5C/dJMb8YXPw9M/ObGoxYzSFkWC9MHYb7ScBk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/fNjUo/dJMb9eTTyRE/o5t8KtGxWGbENwKCpFlcd1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - anthropics/claude-code: Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, a&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md&quot;&gt;Claude Code Release Notes (2.1.0 - Commands/Skills 통합)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1778053174722&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;claude-code/CHANGELOG.md at main &amp;middot; anthropics/claude-code&quot; data-og-description=&quot;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md&quot; data-og-url=&quot;https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/blFJhq/dJMb8QMfZTg/Dp1DZ3JDOxT4Pu2rLohzZk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/rA5q2/dJMb9jOqRSq/gZDrqIaPc6614j1UQHPIc0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/blFJhq/dJMb8QMfZTg/Dp1DZ3JDOxT4Pu2rLohzZk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/rA5q2/dJMb9jOqRSq/gZDrqIaPc6614j1UQHPIc0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;claude-code/CHANGELOG.md at main &amp;middot; anthropics/claude-code&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  AI/✏ Claude</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/325</guid>
      <comments>https://tech-interview.tistory.com/325#entry325comment</comments>
      <pubDate>Wed, 6 May 2026 16:05:49 +0900</pubDate>
    </item>
    <item>
      <title>[AI][Claude] CLI subprocess 호출 : 프로젝트에 API 없이 AI 붙이기</title>
      <link>https://tech-interview.tistory.com/324</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트에&amp;nbsp;API&amp;nbsp;없이&amp;nbsp;AI&amp;nbsp;붙이기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 요약, 분류, 번역 같은 AI 기능을 넣고 싶다. 그런데 API 호출을 사용하여 실험 단계에서 이것저것 돌려보다 보면 한 달에 수십 달러가 우습게 나간다. 이미 구독을 쓰고 있다면, API 호출 대신 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;Claude Code CLI를 subprocess로 불러서&lt;/span&gt; 같은 일을 할 수 있다. Anthropic이 공식적으로 지원하는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;헤드리스 모드를 활용&lt;/span&gt;하는 방법이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이 방식이 맞는 상황인지 먼저 확인해 보자.&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 126px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;상황&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;적합도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;혼자 쓰는 사이드 프로젝트, 로컬 자동화&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;매우 적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;프롬프트 실험, 반복 테스트&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;적합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;배치 처리 (하루 수십~수백 건)&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;구독 리밋 체크 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;외부 사용자에게 서비스 제공&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; API로 가야 함 &lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;24/7 백그라운드 자동화&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; 레이트 리밋 자주 걸림 &lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 종량제는 개인 프로젝트에 최적화돼 있지 않다. Anthropic API 요금은 본래 B2B 서비스 워크로드 기준으로 설계된다. 숫자만 보면 저렴해 보이지만, 개인 프로젝트 맥락에 올려놓으면 이야기가 달라진다. 예를 들어 사이드 프로젝트에 문서 요약 기능 하나를 붙였다고 해보자. 문서당 평균 3천 토큰 입력 / 500 토큰 출력이고, 개발 중에 프롬프트 튜닝하면서 하루 100번쯤 실험적으로 돌린다면 Opus 기준 계산은 이렇다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력: 3000 &amp;times; 100 = 30만 토큰 &amp;rarr; $1.5 / 일&lt;/li&gt;
&lt;li&gt;출력: 500 &amp;times; 100 = 5만 토큰 &amp;rarr; $1.25 / 일&lt;/li&gt;
&lt;li&gt;하루 약 $2.75, 한 달 약 &lt;b&gt;$82&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;반면 Pro 구독은 월 $20 정액이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다른 대안은 모두 어딘가 부족하다.&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;대안&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;한계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;API 직접 호출&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;비용 예측 불가, 청구서 공포&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;무료 티어(Free)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;일일 제한, 자동화 실질 불가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;로컬 LLM (Ollama 등)&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Claude 대비 성능 격차, 세팅/유지 부담&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Claude.ai에서 수동 복붙&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;자동화 불가, 파이프라인 못 만듦&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Claude Code CLI subprocess 호출&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 원래 터미널에서 대화형으로 쓰는 코딩 CLI지만, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;code&gt;-p&lt;/code&gt;(또는 &lt;code&gt;--print&lt;/code&gt;) 플래그를 붙이면 비대화형(non-interactive) 모드로 돌아간다.&lt;/span&gt; 이 모드는 과거에 &lt;b&gt;headless mode&lt;/b&gt;라고 불렸고, 공식 문서에도 CI/CD, 스크립트, 자동화 용도로 쓰라고 안내돼 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Claude Code는 구독 계정으로 인증된다. &lt;code&gt;claude login&lt;/code&gt; 한 번이면 Pro/Max 구독으로 연결된다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt; 모드에서도 그 인증이 그대로 쓰인다. 즉, API 키 없이 subprocess 호출로 모델을 쓸 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;환경 변수에 ANTHROPIC_API_KEY가 설정돼 있으면 구독이 아니라 API로 결제된다. subprocess 호출 전에 반드시 이 변수를 비워둬야 한다.&lt;/blockquote&gt;
&lt;pre id=&quot;code_1776847374631&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;unset ANTHROPIC_API_KEY
claude login   # 구독 계정으로 인증
claude -p &quot;Say hello in 15 words&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Claude Code &lt;code&gt;-p&lt;/code&gt; 기본기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;가장 단순한 호출&lt;/h3&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;claude -p &quot;2 + 2는?&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트를 인자로 넘기면, Claude가 답을 stdout으로 뱉고 종료된다. 파이프로 stdin을 받을 수도 있다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;cat report.txt | claude -p &quot;이 문서를 세 줄로 요약해줘&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자주 쓰는 플래그&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;플래그&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;역할&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;-p&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;--print&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;비대화형 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--output-format&amp;nbsp;json&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;구조화된 JSON 결과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--output-format&amp;nbsp;stream-json&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;스트리밍 JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--allowedTools&amp;nbsp;&quot;Read,Edit&quot;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Claude가 쓸 수 있는 도구를 제한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--append-system-prompt&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;시스템 프롬프트에 지시 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--system-prompt&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;시스템 프롬프트 전체 교체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--continue&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;직전 대화 이어가기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--resume&amp;nbsp;&amp;lt;session_id&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;특정 세션 이어가기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;--bare&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;자동 탐색 스킵해서 시작 시간 단축&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;기본 호출은 시작할 때마다 hooks, skills, plugins, MCP 서버, CLAUDE.md 등을 자동 탐색한다. subprocess로 대량 호출할 때는 이 오버헤드가 누적된다. 자동화 용도라면 --bare를 붙이자.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 구조화된 출력 받아내기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;subprocess 결과를 프로그램이 파싱하려면 JSON이 답이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;--output-format&amp;nbsp;json&lt;/h3&gt;
&lt;pre id=&quot;code_1776847704700&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;claude -p &quot;함수 이름 리스트를 뽑아줘&quot; --output-format json&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 이런 형태로 result&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;필드만 파싱하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;type&quot;: &quot;result&quot;,
  &quot;subtype&quot;: &quot;success&quot;,
  &quot;result&quot;: &quot;실제 응답 텍스트...&quot;,
  &quot;duration_ms&quot;: 1234,
  &quot;total_cost_usd&quot;: 0.01,
  &quot;session_id&quot;: &quot;...&quot;,
  &quot;structured_output&quot;: null
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;--json-schema&lt;/code&gt;로 스키마 강제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력을 특정 구조에 맞추고 싶으면 JSON Schema를 명시할 수 있다. 이러면 Claude가 스키마에 맞춰 출력한다. 후처리에서 정규식 파싱하는 지옥을 피할 수 있다. 단, --json-schema를 쓰면 파싱된 결과는 result가 아니라 structured_output 필드에 dict 형태로 들어온다.&lt;/p&gt;
&lt;pre class=&quot;scilab&quot;&gt;&lt;code&gt;claude -p &quot;이 파일에서 함수 이름만 뽑아줘&quot; \
  --output-format json \
  --json-schema '{
    &quot;type&quot;: &quot;object&quot;,
    &quot;properties&quot;: {
      &quot;functions&quot;: {
        &quot;type&quot;: &quot;array&quot;,
        &quot;items&quot;: { &quot;type&quot;: &quot;string&quot; }
      }
    },
    &quot;required&quot;: [&quot;functions&quot;]
  }' &amp;lt; auth.py&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대화 이어가기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약 한 번 &amp;rarr; 후속 질문 같은 흐름이라면 &lt;code&gt;--continue&lt;/code&gt;를 쓰면 된다.&amp;nbsp;&lt;code&gt;--continue&lt;/code&gt;는 &quot;직전 세션&quot;을 찾기 때문에 병렬 실행에는 적합하지 않다. 여러 흐름을 동시에 돌려야 하면 &lt;code&gt;--resume &amp;lt;session_id&amp;gt;&lt;/code&gt;로 세션 ID를 명시적으로 관리하자.&lt;/p&gt;
&lt;pre id=&quot;code_1776847837308&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;claude -p &quot;이 코드베이스의 성능 이슈를 분석해줘&quot;
claude -p &quot;방금 찾은 이슈 중 DB 관련만 추려줘&quot; --continue
claude -p &quot;각 이슈에 대한 수정안을 JSON으로 정리&quot; --continue --output-format json&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;4. Python subprocess로 감싸기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Python에서 Claude Code CLI를 subprocess로 불러 쓰는 가장 기본 형태이다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot;&gt;&lt;code&gt;import subprocess
import json

def ask_claude(prompt: str) -&amp;gt; dict:
    result = subprocess.run(
        [&quot;claude&quot;, &quot;-p&quot;, &quot;--bare&quot;, &quot;--output-format&quot;, &quot;json&quot;, prompt],
        capture_output=True,
        text=True,
        timeout=60,
    )
    data = json.loads(result.stdout)
    if data.get(&quot;subtype&quot;) != &quot;success&quot;:
        raise RuntimeError(f&quot;claude error: {data}&quot;)
    return data

res = ask_claude(&quot;파이썬에서 리스트 정렬하는 한 줄짜리 코드&quot;)
print(res[&quot;result&quot;])
print(f&quot;소요 시간: {res['duration_ms']}ms&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;긴 입력은 stdin으로&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프롬프트가 길거나 동적 콘텐츠가 많으면 인자 길이 제한에 걸린다. 이럴 땐 stdin으로 파이프하자.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot;&gt;&lt;code&gt;def summarize_file(path: str) -&amp;gt; str:
    with open(path, &quot;r&quot;, encoding=&quot;utf-8&quot;) as f:
        content = f.read()
    result = subprocess.run(
        [&quot;claude&quot;, &quot;-p&quot;, &quot;--bare&quot;, &quot;이 문서를 세 줄로 요약해줘&quot;],
        input=content,
        capture_output=True,
        text=True,
        timeout=120,
    )
    return result.stdout.strip()&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실전 활용 예시&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이메일 분류기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;받은 메일함을 훑어서 카테고리와 긴급도를 태깅한다. 스키마를 강제하면 파싱이 깔끔해진다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;import json
import subprocess

SCHEMA = {
    &quot;type&quot;: &quot;object&quot;,
    &quot;properties&quot;: {
        &quot;category&quot;: {
            &quot;type&quot;: &quot;string&quot;,
            &quot;enum&quot;: [&quot;업무&quot;, &quot;광고&quot;, &quot;뉴스레터&quot;, &quot;개인&quot;, &quot;기타&quot;]
        },
        &quot;urgency&quot;: {&quot;type&quot;: &quot;string&quot;, &quot;enum&quot;: [&quot;high&quot;, &quot;mid&quot;, &quot;low&quot;]},
        &quot;summary&quot;: {&quot;type&quot;: &quot;string&quot;}
    },
    &quot;required&quot;: [&quot;category&quot;, &quot;urgency&quot;, &quot;summary&quot;]
}

def classify_email(body: str) -&amp;gt; dict:
    result = subprocess.run(
        [
            &quot;claude&quot;, &quot;-p&quot;, &quot;--bare&quot;,
            &quot;--output-format&quot;, &quot;json&quot;,
            &quot;--json-schema&quot;, json.dumps(SCHEMA),
            &quot;이 이메일을 분류하고 요약해:&quot;
        ],
        input=body,
        capture_output=True,
        text=True,
        timeout=60,
    )
    data = json.loads(result.stdout)
    return data[&quot;structured_output&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Git 커밋 메시지 생성기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스테이지된 변경사항을 기반으로 커밋 메시지를 만들어 주는 훅이다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;#!/usr/bin/env bash
# .git/hooks/prepare-commit-msg
DIFF=$(git diff --cached)
[ -z &quot;$DIFF&quot; ] &amp;amp;&amp;amp; exit 0

MSG=$(echo &quot;$DIFF&quot; | claude -p --bare \
  --append-system-prompt &quot;You output only a conventional commit message, no explanation.&quot; \
  &quot;Generate a conventional commit message for this diff&quot;)

echo &quot;$MSG&quot; &amp;gt; &quot;$1&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 주의사항과 함정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;레이트 리밋&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구독은 5시간 롤링 윈도우 기준이다. subprocess로 무한 루프 돌려서 갈기면 금방 한도에 걸린다. Pro에서&amp;nbsp;자주&amp;nbsp;막힌다면&amp;nbsp;루프에&amp;nbsp;지수&amp;nbsp;백오프를&amp;nbsp;넣거나,&amp;nbsp;그래도&amp;nbsp;자주&amp;nbsp;걸리면&amp;nbsp;윈도우&amp;nbsp;리셋을&amp;nbsp;기다리거나&amp;nbsp;Max로&amp;nbsp;올려야&amp;nbsp;한다.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;import time

for item in items:
    try:
        process(item)
    except RuntimeError as e:
        if &quot;rate limit&quot; in str(e).lower():
            time.sleep(60)
            continue
        raise&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;헤드리스 모드의 한정된 동작&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;-p&lt;/code&gt; 모드는 대화형 모드와 다르다. &lt;code&gt;/commit&lt;/code&gt; 같은 사용자 호출 슬래시 커맨드는 동작하지 않는다. 권한 프롬프트가 뜰 상황이 되면 그냥 실패한다. 이걸 피하려면 &lt;code&gt;--allowedTools&lt;/code&gt;로 필요한 도구만 화이트리스트 해야 한다. &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;라는 플래그도 있지만, 이름 그대로 위험하다. 본인 PC의 격리된 디렉토리가 아니면 쓰지 말자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프롬프트 인젝션 리스크&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 입력(웹 폼, 크롤링한 HTML, 사용자 입력)을 프롬프트에 그대로 끼워 넣고 &lt;code&gt;--allowedTools &quot;Bash&quot;&lt;/code&gt; 같은 걸 허용하면 원격 코드 실행 취약점이 된다. 외부 입력을 쓸 거면 도구 권한을 최소한으로 제한하자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;복합 작업은 쪼개라&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번의 &lt;code&gt;claude -p&lt;/code&gt; 호출에서 &quot;웹 검색 + 페이지 fetch + 대규모 문서 작성&quot;을 한 번에 시키면 응답이 멈추는 현상이 보고된 적이 있다. subprocess 방식으로 자동화할 때는 한 호출 = 한 단위 작업으로 쪼개는 게 안정적이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ToS와 선의의 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code 구독은 본인이 개발할 때 쓰는 도구다. 구독 인증을 서버에 띄워 다른 사용자에게 서비스를 제공하거나, 24/7 백그라운드 자동화로 사실상 API 트래픽을 구독으로 치환하는 건 구독의 선을 넘는다. 로컬에서 본인 프로젝트에 쓰는 subprocess 호출은 정상 사용에 가깝다. 서비스화 단계로 가면 API로 전환하는 게 맞다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/headless&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://code.claude.com/docs/en/headless&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776848122995&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Run Claude Code programmatically - Claude Code Docs&quot; data-og-description=&quot;Use the Agent SDK to run Claude Code programmatically from the CLI, Python, or TypeScript.&quot; data-og-host=&quot;code.claude.com&quot; data-og-source-url=&quot;https://code.claude.com/docs/en/headless&quot; data-og-url=&quot;https://code.claude.com/docs/en/headless&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVcp2q/dJMb8YpXGtW/Hxf0NFeOPARsSQixabgKd1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/c1nYxP/dJMb8XkhGdI/ABK1DCv9V0NxstKD23IHk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://code.claude.com/docs/en/headless&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://code.claude.com/docs/en/headless&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVcp2q/dJMb8YpXGtW/Hxf0NFeOPARsSQixabgKd1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/c1nYxP/dJMb8XkhGdI/ABK1DCv9V0NxstKD23IHk0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Run Claude Code programmatically - Claude Code Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Use the Agent SDK to run Claude Code programmatically from the CLI, Python, or TypeScript.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;code.claude.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code&quot;&gt;claude-code GitHub&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776848026097&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - anthropics/claude-code: Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, a&quot; data-og-description=&quot;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/anthropics/claude-code&quot; data-og-url=&quot;https://github.com/anthropics/claude-code&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dvQcJD/dJMb9efghWT/k2ACzPDulGQXaxOOV6oVyk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bWS3qN/dJMb9eTRYqr/YmkVKKQv4PGw7c3JSI2yY1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/anthropics/claude-code&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/anthropics/claude-code&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dvQcJD/dJMb9efghWT/k2ACzPDulGQXaxOOV6oVyk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bWS3qN/dJMb9eTRYqr/YmkVKKQv4PGw7c3JSI2yY1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - anthropics/claude-code: Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, a&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflo...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://claude.com/pricing&quot;&gt;Claude Code pricing &amp;amp; plans&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776848028522&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Plans &amp;amp; Pricing | Claude by Anthropic&quot; data-og-description=&quot;Choose the Claude plan that fits how you solve problems. Free, Pro, Max, Team, and Enterprise tiers, plus API pricing for developers.&quot; data-og-host=&quot;claude.com&quot; data-og-source-url=&quot;https://claude.com/pricing&quot; data-og-url=&quot;https://claude.com/pricing&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YnLjz/dJMb9fZxDFp/kkep2K7lOkPecZBkKDL3v1/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/KSJgA/dJMb8WMrUHs/cEgDdMtr1k28rEFvphih71/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260&quot;&gt;&lt;a href=&quot;https://claude.com/pricing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://claude.com/pricing&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YnLjz/dJMb9fZxDFp/kkep2K7lOkPecZBkKDL3v1/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/KSJgA/dJMb8WMrUHs/cEgDdMtr1k28rEFvphih71/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Plans &amp;amp; Pricing | Claude by Anthropic&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Choose the Claude plan that fits how you solve problems. Free, Pro, Max, Team, and Enterprise tiers, plus API pricing for developers.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;claude.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  AI/✏ Claude</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/324</guid>
      <comments>https://tech-interview.tistory.com/324#entry324comment</comments>
      <pubDate>Wed, 22 Apr 2026 17:24:04 +0900</pubDate>
    </item>
    <item>
      <title>[AI] BMAD : 코드 한 줄이 아닌 프로젝트 전체를 맡기는 법</title>
      <link>https://tech-interview.tistory.com/323</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드 한 줄이 아닌 프로젝트 전체를 맡기는 법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI에게 작은 함수 하나, 컴포넌트 한 개를 만들어 달라고 부탁하는 일은 이제 너무 익숙해졌다. 그런데 막상 &quot;업무 관리 도구를 처음부터 만들어 줘&quot; 같은 요청을 던져 보면 결과물은 늘 어딘가 부족하다. 구조는 엉성하고, 기능 사이의 연결이 깨지고, 며칠 뒤 수정을 요청하면 AI는 자기가 뭘 만들었는지조차 잊어버린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 그 한계를 메우기 위해 등장한&amp;nbsp;&lt;b&gt;BMAD(Breakthrough Method for Agile AI-Driven Development)&lt;/b&gt;라는 방법론을 소개하고, 실제로 업무 관리 툴 하나를 처음부터 만들 때 BMAD를 어떻게 적용하는지 보편적인 흐름으로 정리해 본다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. BMAD&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BMAD&lt;/b&gt;는&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AI 에이전트 기반 소프트웨어 개발 방법론&lt;/span&gt;이다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;AI를 활용해 소프트웨어를 체계적으로 설계 &amp;rarr; 구현 &amp;rarr; 검증 까지 이어주는 워크플로우 프레임워크&lt;/span&gt;&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;역할별 전문 에이전트가 각자의 책임만 진다.&lt;/span&gt;&amp;nbsp;한 명의 AI가 모든 걸 떠안지 않는다. 분석가, PM, UX 디자이너, 아키텍트, 스크럼 마스터, 개발자, QA가 각각 자기 영역만 본다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;모든 단계는 문서(Artifact)로 남고, 다음 단계는 그 문서를 읽어서 시작한다.&lt;/span&gt;&amp;nbsp;AI는 문맥을 잃기 쉬운데, 문서가 매개체가 되어 다음 단계 에이전트에게 맥락을 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치는 간단하다. 설치하면 프로젝트 루트에&amp;nbsp;_bmad/&amp;nbsp;디렉토리와 명령어들이 생기고, Claude Code &amp;middot; Cursor &amp;middot; GitHub Copilot 같은 AI IDE에서 슬래시 커맨드로 호출할 수 있게 된다.&lt;/p&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;npx bmad-method install
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 왜 BMAD가 필요한가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 AI 사용 방식의 흐름은 단순하다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;프롬프트 &amp;rarr; 코드 생성 &amp;rarr; 끝
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조가 없다.&amp;nbsp;프로젝트가 커지면 AI는 매번 처음부터 컨텍스트를 다시 파악해야 한다. 토큰만 잡아먹고, 일관성은 떨어진다.&lt;/li&gt;
&lt;li&gt;재현이 안 된다.&amp;nbsp;같은 프롬프트를 넣어도 매번 다른 답이 나온다.&lt;/li&gt;
&lt;li&gt;개인의 프롬프트 실력에 결과 품질이 종속된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BMAD는 이 흐름을 다음처럼 바꾼다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Intent &amp;rarr; PRD &amp;rarr; Architecture &amp;rarr; Spec &amp;rarr; Story &amp;rarr; Code
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단계별로 산출물(문서)을 남기면서 진행한다.&lt;/li&gt;
&lt;li&gt;AI는 그때그때 필요한 문서만 골라 읽는다 (컨텍스트 윈도우의 한계 극복).&lt;/li&gt;
&lt;li&gt;각 단계마다 전용 Skill이 작업 프롬프트를 구체화하고 검증한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요약하자면,&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AI가 길을 잃지 않도록 문서가 가이드 레일 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. BMAD의 핵심 구성 요소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BMAD의 중심은 코드가 아니라&amp;nbsp;&lt;b&gt;문서&lt;/b&gt;다. 단계별로 책임이 명확히 분리된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;단계&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;산출물&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;답하는 질문&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;PRD&amp;nbsp;(Product&amp;nbsp;Requirements&amp;nbsp;Document)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;제품 요구사항&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&quot;무엇을,&amp;nbsp;왜&amp;nbsp;만드는가?&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Architecture&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;시스템 구조도&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&quot;어떤&amp;nbsp;구조로&amp;nbsp;만들&amp;nbsp;것인가?&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Tech&amp;nbsp;Spec&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;기술&amp;nbsp;명세&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&quot;구현은&amp;nbsp;어떻게&amp;nbsp;할&amp;nbsp;것인가?&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Epic&amp;nbsp;/&amp;nbsp;Story&amp;nbsp;/&amp;nbsp;Task&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;실행&amp;nbsp;단위&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&quot;지금&amp;nbsp;당장&amp;nbsp;무엇을&amp;nbsp;코딩하는가?&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 마지막 실행 단위는 트리 구조로 잘게 쪼개진다. 이렇게 쪼개는 이유는&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;하나의 Story가 AI 컨텍스트 한도 안에서 완결되도록&lt;/span&gt;&amp;nbsp;하기 위해서다. Story 한 개가 너무 크면 AI는 절반쯤 가다 길을 잃는다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;Epic (큰 기능 단위)
├── Story 1 (AI가 한 번에 구현 가능한 단위)
│   ├── Task
│   └── Task
└── Story 2
    └── Task
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 단계는 7명의 전담 에이전트가 맡는다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&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;Mary (Analyst)&lt;/td&gt;
&lt;td&gt;아이디어 구체화, 리서치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;John (PM)&lt;/td&gt;
&lt;td&gt;PRD 작성, 요구사항 정의&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sally (UX Designer)&lt;/td&gt;
&lt;td&gt;사용자 경험 설계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Winston (Architect)&lt;/td&gt;
&lt;td&gt;기술 아키텍처 설계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bob (Scrum Master)&lt;/td&gt;
&lt;td&gt;스프린트 계획, 스토리 준비&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Amelia (Developer)&lt;/td&gt;
&lt;td&gt;TDD 기반 코드 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quinn (QA)&lt;/td&gt;
&lt;td&gt;테스트 자동화&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. BMAD 표준 워크플로우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BMAD는 4단계 파이프라인으로 구성된다. 각 단계 끝에는&amp;nbsp;게이트(검증)가 있어서, 통과하지 못하면 다음 단계로 넘어갈 수 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 1. Analysis : 무엇을 만들지 정한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계의 결과물은&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;Product Brief&amp;nbsp;한 장&lt;/span&gt;이다. &quot;누가, 왜, 무엇을, 어떤 기준으로 성공한다고 볼 것인가&quot; 가 명확해야 다음 단계로 넘어간다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-brainstorming        # 아이디어를 다양한 기법으로 발산
/bmad-create-product-brief # 제품 비전, 사용자, 메트릭, 범위 정의
/bmad-domain-research      # 도메인 조사
/bmad-market-research      # 시장/사용자 조사
/bmad-technical-research   # 기술 조사
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 2. Planning : PRD를 만든다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; PRD는 BMAD에서 가장 중요한 문서&lt;/span&gt;다. 비전, 성공 기준, 사용자 여정, 기능 요구사항(FR), 비기능 요구사항(NFR)이 모두 들어간다.&amp;nbsp;validate-prd가 PRD에 모호한 표현이 있는지, 측정 가능한지, 구현 누설(어떻게 만들지를 미리 적어버린 부분)이 있는지를 까다롭게 검증한다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;/bmad-create-prd      # 12단계로 PRD 작성
/bmad-validate-prd    # 13단계로 PRD 검증 (포맷, 측정가능성, 추적성 등)
/bmad-create-ux-design
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 3. Solutioning : 어떻게 만들지 설계한다&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;핵심은 마지막 명령이다. PRD, UX, Architecture, Epics가&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;서로 정합한지&lt;/span&gt; 6단계로 검증한다. 여기서 결함이 발견되면 앞 단계로 돌아가야 한다.&amp;nbsp;&quot;기획이 완전하지 않으면 구현으로 넘어갈 수 없다&quot; &amp;mdash; 이것이 BMAD가 강제하는 규율이다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-create-architecture            # 시스템 아키텍처 설계
/bmad-create-epics-and-stories       # PRD를 에픽/스토리로 분해
/bmad-check-implementation-readiness # ⭐ 구현 준비도 검증
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 4. Implementation : 코드를 쓴다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;AI 개발자(Amelia)는 항상 스토리 파일 한 개만 본다.&lt;/span&gt;&amp;nbsp;PRD 전체를 매번 읽지 않는다. 그 스토리를 구현하기 위해 필요한 컨텍스트가 스토리 파일 안에 모두 들어 있어야 한다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-sprint-planning   # 스프린트 계획 생성
/bmad-create-story      # 스토리 파일 생성 (구현에 필요한 모든 컨텍스트 포함)
/bmad-dev-story         # 스토리 파일 기반 코드 구현
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실전 활용 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 처음부터 업무 관리 툴 하나를 만든다고 가정하고, BMAD 명령어를 순서대로 짚어보자.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;BMAD는 버전&amp;middot;환경에 따라 명령어 prefix가 다를 수 있다. 예를 들어 어떤 환경은 /bmad-create-story로, 다른 환경은 /create-story로 호출된다. 이 글은 /bmad- prefix 기준으로 작성했지만, 실제 실행 시 자동완성 목록에서 본인 환경의 정확한 명령어 이름을 확인하고 사용하면 된다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 0. 막막할 땐&amp;nbsp;/bmad-help&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 직후, 빈 폴더 앞에서 뭘 해야 할지 모르겠다면 가장 먼저 칠 명령어는 이거다. 현재 프로젝트 상태(설치된 모듈, 산출물 유무, 다음 추천 단계)를 분석해서 알려준다. 도중에 길을 잃었을 때마다 다시 부를 수 있어 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;가장 자주 쓰게 되는 명령어&lt;/span&gt;다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-help
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연어 질문도 받는다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-help 방금 PRD를 다 썼는데 다음에 뭘 해야 해?
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 1. 아이디어를 다듬는다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머릿속에 아이디어가 흐릿하다면 브레인스토밍을 먼저 한다. SCAMPER, Six Hats 같은 발상 기법으로 인터랙티브하게 아이디어를 확장해 준다. 이미 &quot;업무 관리 툴을 만든다&quot;가 명확하다면 건너뛰어도 된다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-brainstorming
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다양한 관점이 필요할 때는 파티 모드도 유용하다. PM, 아키텍트, UX, QA가 한 자리에 모여 토론하는 모드다. &quot;이 기획에 빠진 게 뭘까?&quot; 같은 질문에 빛을 발한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-party-mode
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 2. Product Brief : &quot;왜 만드는가&quot; 정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 작업의 시작점이다. 이 명령어를 치면 BMAD가 단계별로 묻는다:&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-create-product-brief
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;누구를 위한 도구인가?&lt;/li&gt;
&lt;li&gt;어떤 문제를 푸는가?&lt;/li&gt;
&lt;li&gt;성공의 기준은 무엇인가?&lt;/li&gt;
&lt;li&gt;범위(scope)는 어디까지인가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 관리 툴이라면 이런 답을 채워나가게 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자: 개인 또는 소규모 팀의 지식 노동자&lt;/li&gt;
&lt;li&gt;문제: 업무가 흩어져 진행률이 한눈에 안 보인다&lt;/li&gt;
&lt;li&gt;성공 기준: 업무 등록부터 대시보드 확인까지 5초 이내&lt;/li&gt;
&lt;li&gt;범위: 단일 사용자, 로컬 실행. 팀 협업/실시간 알림은 제외&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인이나 기술이 낯설다면 보조 명령어로 리서치를 돌린다. 세 가지를 모두 돌릴 필요는 없다. 막히는 곳에만 호출하자.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-domain-research      # 업무 관리 도메인 트렌드, 경쟁 도구 비교
/bmad-market-research      # 사용자 페인포인트, 기존 솔루션의 한계
/bmad-technical-research   # 기술 스택 옵션 (Electron vs 웹앱, 저장소 선택 등)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 3. PRD 작성과 검증&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;PRD/UX 같은 큰 단계는 새로운 컨텍스트 윈도우에서 시작하는 게 좋다. 토큰을 깨끗이 비운 상태에서 한 단계씩 진행해야 AI가 길을 잃지 않는다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기가 BMAD에서 시간을 가장 많이 쓰는 구간이다. 12단계 인터랙티브 인터뷰로 PRD를 만든다. 발견 &amp;rarr; 비전 &amp;rarr; 성공 지표 &amp;rarr; 사용자 여정 &amp;rarr; 기능 요구사항(FR) &amp;rarr; 비기능 요구사항(NFR) 순서다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-create-prd
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 관리 툴이라면 이런 식의 FR이 정리된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;FR-TM-01    카테고리에 업무를 등록할 수 있다
FR-TM-02    업무에 산정(예상 작업량)을 트리 구조로 입력할 수 있다
FR-TM-05    업무를 다른 카테고리로 드래그하여 이동할 수 있다
FR-TM-08    업무에 태그를 추가하고 태그로 필터링할 수 있다
FR-DB-01    대시보드에서 진행 중 업무 수와 평균 진행률을 요약 표시한다
NFR-PERF-01 데이터 변경 후 1초 이내 자동 저장된다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PRD 초안이 끝나면 곧바로 검증을 돌린다. 13단계 검증 체크리스트가 PRD를 훑는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;측정 가능성: &quot;빠르게 저장된다&quot; &amp;rarr; &quot;1초 이내 저장된다&quot;로 수정 요구&lt;/li&gt;
&lt;li&gt;추적성: 각 FR이 어떤 사용자 여정과 연결되는가?&lt;/li&gt;
&lt;li&gt;구현 누설: PRD에 &quot;React 컴포넌트로 만든다&quot; 같은 구현 디테일이 들어갔는가?&lt;/li&gt;
&lt;li&gt;SMART: 기준이 구체적&amp;middot;측정 가능&amp;middot;달성 가능&amp;middot;관련성 있고 시간 제한이 있는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-validate-prd
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증에서 지적이 나오면 곧바로 수정한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-edit-prd
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 화면 설계도 함께 정리한다. 대시보드 레이아웃, 업무 카드 구조, 드래그앤드롭 인터랙션 같은 화면 단위 설계가 여기서 정해진다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;/bmad-create-ux-design
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 4. Architecture : 어떻게 만들지 결정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PRD를 입력으로 받아 시스템 구조를 설계한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-create-architecture
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업무 관리 툴이라면 이런 결정이 문서로 남는다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트엔드 프레임워크 선택: 빌드 단계의 무게 vs 개발 속도&lt;/li&gt;
&lt;li&gt;데이터 저장 방식: SQLite, JSON 파일, IndexedDB 중 무엇?&lt;/li&gt;
&lt;li&gt;백엔드 필요성: 단일 사용자라면 백엔드 없이 가능한가?&lt;/li&gt;
&lt;li&gt;상태 관리 패턴: Context API, Redux, 단순 상태 끌어올리기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 결정 자체가 아니라&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;트레이드오프를 함께 기록&lt;/span&gt;하는 것이다. &quot;왜 SQLite 대신 JSON을 골랐는가?&quot;의 답이 6개월 뒤에도 남아 있어야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 5. Epic / Story 분해&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PRD의 FR들을 사용자 가치 단위로 묶고, AI가 한 번에 구현 가능한 크기로 쪼갠다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-create-epics-and-stories
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 이런 트리가 된다. 각 Story는 &quot;As a [사용자], I want [행동], so that [가치]&quot; 형식이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Epic 1: 업무 등록과 분류
├── Story 1.1: 카테고리에 업무 카드를 생성한다
├── Story 1.2: 업무에 마감일과 태그를 설정한다
└── Story 1.3: 업무를 다른 카테고리로 드래그한다

Epic 2: 업무 진행 추적
├── Story 2.1: 업무에 트리 구조 산정을 입력한다
├── Story 2.2: 산정 항목을 작업으로 복사한다
└── Story 2.3: 작업의 완료 상태를 전환한다

Epic 3: 대시보드
├── Story 3.1: 진행 중 업무 수와 평균 진행률을 요약한다
├── Story 3.2: 마감 임박 업무를 알림으로 표시한다
└── Story 3.3: 카테고리별 작업량을 비교한다
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 6. 게이트 : Implementation Readiness Check&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 단계가 BMAD의 마지노선이다. 6단계 검증을 통해 구현으로 진입할 준비가 됐는지 판정한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-check-implementation-readiness
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문서 탐색: 모든 산출물이 갖춰졌는가?&lt;/li&gt;
&lt;li&gt;PRD 분석: 요구사항이 명확한가?&lt;/li&gt;
&lt;li&gt;에픽 커버리지 검증: PRD의 모든 FR이 Story에 매핑되는가?&lt;/li&gt;
&lt;li&gt;UX 정합성 확인: UX 디자인과 Story가 일치하는가?&lt;/li&gt;
&lt;li&gt;에픽 품질 리뷰: Story가 충분히 잘게 쪼개졌는가?&lt;/li&gt;
&lt;li&gt;최종 판정: Pass / Fail&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fail이 나오면 앞 단계로 돌아간다.&amp;nbsp;이 게이트를 우회하지 말 것. 구현 중간에 &quot;어? 이 기능 어떻게 한다고 했지?&quot;가 터지는 걸 막아주는 마지막 안전망이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 7. 스프린트 계획과 구현 루프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기부터는 같은 패턴의 반복이다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-sprint-planning
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 1~2주에 처리할 Story를 골라 스프린트로 묶는다. 그리고 Story마다 다음 두 명령어를 반복한다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-create-story    # Story 한 개에 필요한 모든 컨텍스트를 담은 파일 생성
/bmad-dev-story       # 그 파일을 읽고 실제 코드 구현
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/bmad-create-story가 만드는 파일에는 다음이 모두 들어간다. 그래서&amp;nbsp;/bmad-dev-story의 Dev 에이전트(Amelia)는 PRD 전체를 다시 읽지 않고&amp;nbsp;그 Story 파일 하나만&amp;nbsp;보고도 구현을 끝낼 수 있다. 컨텍스트 윈도우를 절약하는 핵심 메커니즘이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Story의 사용자 가치 진술&lt;/li&gt;
&lt;li&gt;관련 FR과 NFR&lt;/li&gt;
&lt;li&gt;영향 받는 컴포넌트와 파일 경로&lt;/li&gt;
&lt;li&gt;테스트 시나리오&lt;/li&gt;
&lt;li&gt;완료 조건(Acceptance Criteria)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현이 끝나면 코드 리뷰를 돌린다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-code-review
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에픽 한 개가 끝나면 회고를 한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-retrospective
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 에픽으로 넘어가기 전에 무엇이 잘 됐고 무엇이 어긋났는지 정리한다. 다음 에픽의 Story 분해 품질이 올라간다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자주 쓰게 되는 명령어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 끝까지 따라가다 보면 결국 손에 익는 명령어는 다음 다섯이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;/bmad-help&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;/bmad-create-story&lt;/td&gt;
&lt;td&gt;새 Story 시작할 때마다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;/bmad-dev-story&lt;/td&gt;
&lt;td&gt;코드 짤 때마다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;/bmad-code-review&lt;/td&gt;
&lt;td&gt;Story 구현 직후&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;/bmad-quick-dev&lt;/td&gt;
&lt;td&gt;작은 기능 추가나 버그 수정 시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;작은 수정용 빠른 흐름&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 굴러가는 프로덕트에 간단한 기능을 추가하거나 버그를 잡을 때는 풀 파이프라인이 과하다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-quick-spec    # 가벼운 기술 명세 한 장
/bmad-quick-dev     # 그걸 읽고 바로 구현
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단, 이렇게 추가한 기능은 PRD/Story 문서에서 누락된다. 누적되면 문서와 코드가 어긋나기 시작한다. 정기적으로 다음 명령으로 동기화하자. 코드 변경사항을 PRD/에픽/스토리 문서에 역으로 반영해 준다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;/bmad-correct-course
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. BMAD를 잘 쓰는 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;큰 프로젝트와 작은 수정의 흐름을 분리하라&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BMAD는 신규 프로젝트나 큰 기능 단위에 강하지만, 버그 한 줄 수정에는 과하다. 작은 수정에는 별도 흐름이 있다. 단, 이렇게 만든 코드를 PRD/Story 문서에 다시 동기화해 두지 않으면 문서와 코드가 어긋난다.&amp;nbsp;/bmad-correct-course&amp;nbsp;가 이걸 맞춰주긴 하지만, 너무 자주 쓰면 BMAD를 쓰는 의미가 옅어진다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;/bmad-quick-spec   # 가벼운 기술 명세
/bmad-quick-dev    # 빠른 구현
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문서가 커지면 분할하고 연결하라&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PRD나 Architecture가 한 파일에 다 들어가면 AI가 매번 거대한 문서를 읽느라 토큰을 낭비한다. 기능 단위로 분할하자. /bmad-shard-doc(분할),&amp;nbsp;/bmad-distillator(압축) 같은 Skill이 이 작업을 도와준다.&lt;/p&gt;
&lt;pre class=&quot;dos&quot;&gt;&lt;code&gt;/docs
  /prd
    prd-task.md
    prd-dashboard.md
    prd-search.md
  /architecture
    arch-overview.md
    arch-storage.md
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;검증 단계를 생략하지 마라&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BMAD에는 다양한 검토 도구가 있다. 특히 Party Mode는 기획 초기에 빛을 발한다. 한 번에 PM, 아키텍트, QA의 시선을 받을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/bmad-review-adversarial-general: 비판적 시각으로 약점 찾기 (최소 10개 허점을 찾을 때까지 멈추지 않는다)&lt;/li&gt;
&lt;li&gt;/bmad-review-edge-case-hunter: 엣지 케이스 탐색&lt;/li&gt;
&lt;li&gt;/bmad-code-review: 코드 품질 검토&lt;/li&gt;
&lt;li&gt;/bmad-party-mode: 여러 에이전트가 동시에 토론하며 다각도 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;패턴이 보이면 Skill로 만들어라&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 작업 흐름이 반복된다면 자체 Skill로 만들어 두자. 다음 작업부터는 그 Skill을 호출하기만 하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. BMAD를 써본 후의 평가&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BMAD를 한 줄로 표현하면 이렇다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;기획이 완벽하지 않으면 코드를 쓸 수 없게 만드는 프로세스&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;AI가 코드를 잘 짜게 만드는 마법이 아니라, AI가 잘 짤 수 있도록&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;인간이 더 정확하게 요구사항을 정리하게 강제하는 프레임워크&lt;/span&gt;에 가깝다.&amp;nbsp;그래서 BMAD가 가장 빛나는 순간은&amp;nbsp;새 프로젝트를 시작하는 순간이다. 업무 관리 툴이든, 사이드 프로젝트든, 사내 도구든 빈 폴더 앞에서 막막할 때 /bmad-brainstorming 한 줄을 두드리면, AI가 단계별로 길을 깔아준다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반대로, 이미 굴러가는 프로덕트에 작은 버그를 잡거나 기능 한두 개를 꽂는 작업이라면, BMAD는 오히려 무거울 수 있다. quick-dev / quick-spec과의 균형을 잡는 감각이 필요하다. AI 코딩의 다음 단계는 &quot;더 똑똑한 AI&quot;가 아니라,&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&quot;AI가 똑똑하게 일하도록 만드는 우리의 방법론&quot;&lt;/span&gt;&amp;nbsp;일지도 모른다. BMAD는 그 가능성을 보여주는 흥미로운 시도다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기획의 허점이 빠르게 드러난다.&amp;nbsp;&quot;유저별로 구분한다&quot;는 기획에 로그인 기능이 빠져 있으면 PRD 단계에서 잡힌다.&lt;/li&gt;
&lt;li&gt;PRD가 촘촘해서 구현 결과물이 만족스럽다.&amp;nbsp;스토리 단위 구현이 흔들리지 않는다.&lt;/li&gt;
&lt;li&gt;AI가 길을 잃지 않는다.&amp;nbsp;컨텍스트가 비대해지는 걸 문서 분할이 막아준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PRD 만드는 데 시간이 꽤 든다.&amp;nbsp;간단한 프로그램에는 과한 투자다.&lt;/li&gt;
&lt;li&gt;수정 한 번 하려면 PRD &amp;rarr; Story &amp;rarr; Dev 사이클을 다시 돌아야 한다.&amp;nbsp;이걸 회피하려고 quick-dev를 쓰면 문서와 코드가 어긋난다.&lt;/li&gt;
&lt;li&gt;기존 프로젝트에 적용하려면 PRD를 거꾸로 만들어야 해서 부담이 크다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.bmad-method.org/&quot;&gt;https://docs.bmad-method.org/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776428281302&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Welcome to the BMad Method&quot; data-og-description=&quot;AI-driven development framework with specialized agents, guided workflows, and intelligent planning&quot; data-og-host=&quot;docs.bmad-method.org&quot; data-og-source-url=&quot;https://docs.bmad-method.org/&quot; data-og-url=&quot;https://docs.bmad-method.org/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.bmad-method.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.bmad-method.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Welcome to the BMad Method&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AI-driven development framework with specialized agents, guided workflows, and intelligent planning&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.bmad-method.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/bmad-code-org/BMAD-METHOD&quot;&gt;https://github.com/bmad-code-org/BMAD-METHOD&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776428286823&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - bmad-code-org/BMAD-METHOD: Breakthrough Method for Agile Ai Driven Development&quot; data-og-description=&quot;Breakthrough Method for Agile Ai Driven Development - bmad-code-org/BMAD-METHOD&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/bmad-code-org/BMAD-METHOD&quot; data-og-url=&quot;https://github.com/bmad-code-org/BMAD-METHOD&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dc28nC/dJMb8Rj3GVY/EZLRnPUClMiBkTUFQoaBwK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bIYmGU/dJMb8Rj3GVZ/yhwDR9mDmaoI9RcFEWgjp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/ZXh7m/dJMb83kuHim/DZNium39KlGaBmoDAS4rVk/img.png?width=1408&amp;amp;height=224&amp;amp;face=0_0_1408_224&quot;&gt;&lt;a href=&quot;https://github.com/bmad-code-org/BMAD-METHOD&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/bmad-code-org/BMAD-METHOD&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dc28nC/dJMb8Rj3GVY/EZLRnPUClMiBkTUFQoaBwK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/bIYmGU/dJMb8Rj3GVZ/yhwDR9mDmaoI9RcFEWgjp0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/ZXh7m/dJMb83kuHim/DZNium39KlGaBmoDAS4rVk/img.png?width=1408&amp;amp;height=224&amp;amp;face=0_0_1408_224');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - bmad-code-org/BMAD-METHOD: Breakthrough Method for Agile Ai Driven Development&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Breakthrough Method for Agile Ai Driven Development - bmad-code-org/BMAD-METHOD&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  AI/✏ AI Tools</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/323</guid>
      <comments>https://tech-interview.tistory.com/323#entry323comment</comments>
      <pubDate>Fri, 17 Apr 2026 20:59:58 +0900</pubDate>
    </item>
    <item>
      <title>[AI] Git Worktree를 활용한 개발 워크플로우 개선</title>
      <link>https://tech-interview.tistory.com/322</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;Git&amp;nbsp;Worktree를&amp;nbsp;활용한&amp;nbsp;개발&amp;nbsp;워크플로우&amp;nbsp;개선&lt;/span&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;stash 없이, 충돌 없이 &amp;mdash; 여러 작업을 동시에 진행하는 방법&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left; font-family: 'Nanum Gothic';&quot;&gt; 개발하다 보면 유독 타이밍이 나쁜 순간이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;신규 기능 한창 개발 중인데 라이브 버그가 터진다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;AI에게 리팩토링을 맡겼더니 생각보다 파일을 많이 건드려서 메인 브랜치가 불안해진다. 동료 PR을 리뷰해야 하는데 내 작업을 멈추기도 애매하다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;이럴 때 보통은 &lt;code&gt;git stash&lt;/code&gt;로 작업을 임시 저장하고 브랜치를 옮기고, 끝나면 다시 복귀하는 흐름을 반복한다. 번거롭기도 하고, 복귀 후에 &quot;어디까지 했더라&quot;를 다시 파악하는 컨텍스트 스위칭 비용도 크다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Git Worktree&lt;/b&gt;는 이 구조 자체를 바꿔준다. Git 2.5(2015)부터 있던 기능인데, AI 코딩 도구가 일상화되면서 다시 주목받고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;1. Git Worktree&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단순하게 말하면, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;같은 Git 저장소를 여러 폴더에서 동시에 열어두는 기능&lt;/span&gt;이다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기존 Git은 작업 디렉터리가 하나뿐이고 브랜치를 바꾸면 그 폴더 안의 파일이 통째로 교체된다. Worktree는 이 제약을 없애준다. 브랜치마다 별도의 폴더를 만들어서, 각각 독립적으로 작업할 수 있게 해준다.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;.git 데이터베이스는 하나만 존재하고, Worktree는 그걸 공유하면서 작업 공간만 따로 갖는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트를 통째로 clone하는 것과 달리, 코드 히스토리를 중복 저장하지 않아서 디스크도 훨씬 덜 쓴다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1776261901161&quot; class=&quot;jboss-cli&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;my-project/        &amp;larr; main 브랜치 (메인 작업 공간)
  └── .git/        &amp;larr; Git 데이터베이스 (히스토리, 커밋 전부 여기 있음)

../my-project-fix/ &amp;larr; hotfix 브랜치 (Worktree)
  └── .git         &amp;larr; 파일 하나 &amp;mdash; 위 .git 폴더를 가리키는 포인터&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 사용&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;기본 명령어&lt;/span&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 127px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명령어&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;add&amp;nbsp;&amp;lt;경로&amp;gt;&amp;nbsp;&amp;lt;브랜치&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Worktree&amp;nbsp;생성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;list&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;전체&amp;nbsp;목록&amp;nbsp;조회&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;remove&amp;nbsp;&amp;lt;경로&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;안전&amp;nbsp;삭제&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;prune&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;유령&amp;nbsp;Worktree&amp;nbsp;정리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;lock&amp;nbsp;&amp;lt;경로&amp;gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;prune&amp;nbsp;보호&amp;nbsp;(USB&amp;nbsp;등&amp;nbsp;외장&amp;nbsp;드라이브&amp;nbsp;사용&amp;nbsp;시)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;git&amp;nbsp;worktree&amp;nbsp;repair&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;폴더&amp;nbsp;이동&amp;nbsp;후&amp;nbsp;연결&amp;nbsp;복구&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;프로젝트 폴더와 동일한 위치에 만들기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;프로젝트 폴더 안에 Worktree를 만들면 Git이 그 폴더를 추적 안 된 파일로 인식해서 &lt;code&gt;git status&lt;/code&gt; 출력이 계속 오염된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776261687429&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이렇게 하면 git status가 지저분해짐
git worktree add ./my-worktree main

# 프로젝트 폴더 바깥, 나란한 위치에 만드는 게 맞음
git worktree add ../my-worktree main&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;같은 브랜치는 한 곳에서만 수정하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Git은 동일 브랜치를 두 폴더에서 동시에 수정하는 상황을 막아준다. 이미 &lt;code&gt;main&lt;/code&gt;을 열고 있는 상태에서 새 Worktree에도 &lt;code&gt;main&lt;/code&gt;을 체크아웃하려 하면 Fatal 에러가 난다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;읽기만 할 목적이라면 &lt;code&gt;--detach&lt;/code&gt; 옵션을 쓰면 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776261891352&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git worktree add ../just-looking --detach&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;의존성 폴더는 따로 설치하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;venv&lt;/code&gt; 같은 의존성 폴더는 자동으로 복사되지 않기 때문에 각 Worktree마다 따로 설치해야 한다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;pnpm을 쓰면 파일을 복사하지 않고 링크를 걸기 때문에 디스크 사용량과 설치 시간을 크게 줄일 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776261995426&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd ../my-worktree
npm install   # 빠뜨리면 실행이 안 됨&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;3. 활용&lt;/span&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;stash 없이&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;핫픽스 대응&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;stash pop 없이, IDE 재색인 없이, 컨텍스트도 그대로다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262178793&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기능 개발 중인 상태 그대로 두고
# 메인 기준으로 핫픽스 폴더만 따로 오픈

git worktree add ../hotfix main
cd ../hotfix

git checkout -b hotfix/critical-bug
# 수정 작업
git commit -m &quot;fix: 긴급 버그 수정&quot;
git push origin hotfix/critical-bug

# 원래 폴더로 돌아오면 작업 상태 그대로
cd ../my-project&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;동시 다발 작업&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;세 가지 일이 한꺼번에 주어진 상황을 가정해보자.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;세 서버가 동시에 뜬다. 포트는 각 프로젝트 설정에서 수동으로 지정해야 하지만, 작업 간 간섭은 전혀 없다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262203001&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;터미널 A: ~/projects/my-app/          &amp;rarr; 기능 개발 중 (3000 포트)
터미널 B: ~/projects/my-app-review/   &amp;rarr; 동료 PR 리뷰 (3001 포트)
터미널 C: ~/projects/my-app-hotfix/   &amp;rarr; 긴급 버그 수정 (3002 포트)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;PR 리뷰 전용 환경&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;동료 PR을 내 로컬에서 직접 돌려보고 싶을 때&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262218015&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git fetch origin pull/42/head:pr-42
git worktree add ../review-pr42 pr-42

cd ../review-pr42
npm install &amp;amp;&amp;amp; npm test
# 코드 이것저것 건드려봐도 내 작업엔 영향 없음

# 리뷰 끝나면 깔끔하게 정리
cd ../my-project
git worktree remove ../review-pr42
git branch -D pr-42&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;접근법 비교&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;같은 문제를 두 가지 방식으로 AI에게 시켜보고 결과를 나란히 비교할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262245032&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;claude --worktree approach-a -p &quot;이벤트 시스템을 옵저버 패턴으로 리팩토링해줘&quot;
claude --worktree approach-b -p &quot;이벤트 시스템을 메시지 버스 구조로 리팩토링해줘&quot;

# 두 결과를 diff로 비교
git diff worktree-approach-a..worktree-approach-b&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;4. Claude Code와 함께 쓰기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;Claude Code(v2.1.49+)에는 &lt;code&gt;--worktree&lt;/code&gt; 플래그가 내장되어 있다. Git 명령을 직접 치지 않아도 Claude가 Worktree를 알아서 만들고 작업한다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;line-height: 1.9;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;.claude/worktrees/&amp;lt;n&amp;gt;/&lt;/code&gt; 에 Worktree 자동 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;worktree-&amp;lt;n&amp;gt;&lt;/code&gt; 브랜치를 분기해서 그 안에서만 파일 수정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;세션 종료 시, 변경사항이 없으면 자동 삭제 / 있으면 선택&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1776262394724&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이름 지정
claude --worktree refactor-battle-system

# 이름 생략 (랜덤 이름 자동 생성)
claude --worktree&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1776262511338&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Claude Code Worktree 폴더가 Git에 추적되지 않도록
.claude/worktrees/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;에이전트 정의 파일에 &lt;code&gt;isolation: worktree&lt;/code&gt;를 넣으면 해당 에이전트는 항상 격리된 환경에서만 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262437661&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
name: safe-refactor
description: 격리된 환경에서 리팩토링을 수행하는 에이전트
isolation: worktree
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;여러 에이전트를 동시에 돌릴 때도 각자 다른 Worktree에서 작업하므로 서로 간섭이 없다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1776262468215&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;claude --worktree ai-auth  --dangerously-skip-permissions -p &quot;인증 모듈 개선&quot; &amp;amp;
claude --worktree ai-db    --dangerously-skip-permissions -p &quot;쿼리 최적화&quot; &amp;amp;
claude --worktree ai-api   --dangerously-skip-permissions -p &quot;API 타입 정리&quot; &amp;amp;
wait&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Claude Code 외에도 Cursor의 Parallel Agents(최대 8개), OpenAI Codex CLI 모두 같은 원리로 Worktree 기반 병렬 실행을 지원한다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;5. 게임 클라이언트에서 활용하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;게임 클라이언트는 전투, 인벤토리, 네트워크, 렌더링처럼 시스템 간 의존성이 복잡하게 얽혀 있다. 한 브랜치에서 여러 작업이 뒤섞이면 리뷰도 머지도 어려워진다. 위 패턴들을 그대로 적용할 수 있고, 특히 아래 상황에서 유용하다.&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;시스템별 AI 병렬 리팩토링&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;line-height: 1.9;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;전투, 퀘스트, 인벤토리처럼 독립성이 높은 시스템을 각각 다른 Worktree에서 AI에게 동시에 맡길 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;서로 다른 폴더에서 작동하므로 파일 충돌 없음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;결과는 시스템마다 개별 검토 후 선택적으로 머지&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;라이브 핫픽스 대응&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;line-height: 1.9;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;빌드 서버에서 크래시 리포트가 올라와도 진행 중인 피처 브랜치를 stash 없이 그대로 둘 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;핫픽스 Worktree를 별도로 열어 바로 대응 &amp;rarr; 완료 후 정리하고 원래 작업으로 복귀&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;로컬 환경 초기화 스크립트화&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;line-height: 1.9;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;코드 생성, 리소스 빌드, 프로토 업데이트 등 로컬 세팅이 복잡한 프로젝트일수록 효과적&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;Worktree를 새로 열 때마다 반복하게 되므로 초기화 스크립트를 미리 만들어두는 것을 권장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;주의!&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;에디터 실행이 필요한 작업은 주의가 필요하다.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;Worktree는 파일 시스템상 별도 폴더이기 때문에, 게임 엔진이 관리하는 캐시 폴더가 Worktree마다 새로 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; font-size: 14px; margin: 1.5em 0;&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;문제&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: left;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;내용&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;캐시 재생성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;에셋 데이터베이스, 임포트 캐시, 셰이더 캐시 등이 Worktree마다 새로 만들어짐&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;background: #fafafa;&quot;&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;재임포트 시간&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;에디터 첫 오픈 시 전체 에셋 재임포트 발생 &amp;mdash; 규모에 따라 수 분~수십 분 소요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;동시 오픈 충돌&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;같은 프로젝트를 두 Worktree에서 동시에 에디터로 열면 캐시&amp;middot;라이선스 충돌 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 style=&quot;color: #999999;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;참고&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://goddaehee.tistory.com/521&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://goddaehee.tistory.com/521&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776262809186&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Claude Code v2.1.49 신기능 리뷰 : --worktree로 멀티 에이전트 안전하게 쓰기, 병렬 작업 환경 구축 하기&quot; data-og-description=&quot;안녕하세요! 갓대희 입니다.오늘은 Git Worktree 지원 기능에 대해 알아보려고 한다.Claude Code로 여러 작업을 동시에 진행하다 보면 한 세션의 변경사항이 다른 세션과 충돌하거나, 실험적인 코드가 &quot; data-og-host=&quot;goddaehee.tistory.com&quot; data-og-source-url=&quot;https://goddaehee.tistory.com/521&quot; data-og-url=&quot;https://goddaehee.tistory.com/521&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buk9RG/dJMb8WMq7a0/6CSKw32Pw8WZknqNWG3kzK/img.png?width=800&amp;amp;height=532&amp;amp;face=0_0_800_532,https://scrap.kakaocdn.net/dn/buWBGt/dJMb8SXzh4p/DB5cXVABLoRyLD7KssTFc1/img.png?width=800&amp;amp;height=532&amp;amp;face=0_0_800_532,https://scrap.kakaocdn.net/dn/YMn47/dJMb8YXM3bx/noqghW62mIKvvqGgYWSz2k/img.png?width=2144&amp;amp;height=1428&amp;amp;face=0_0_2144_1428&quot;&gt;&lt;a href=&quot;https://goddaehee.tistory.com/521&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://goddaehee.tistory.com/521&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buk9RG/dJMb8WMq7a0/6CSKw32Pw8WZknqNWG3kzK/img.png?width=800&amp;amp;height=532&amp;amp;face=0_0_800_532,https://scrap.kakaocdn.net/dn/buWBGt/dJMb8SXzh4p/DB5cXVABLoRyLD7KssTFc1/img.png?width=800&amp;amp;height=532&amp;amp;face=0_0_800_532,https://scrap.kakaocdn.net/dn/YMn47/dJMb8YXM3bx/noqghW62mIKvvqGgYWSz2k/img.png?width=2144&amp;amp;height=1428&amp;amp;face=0_0_2144_1428');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Claude Code v2.1.49 신기능 리뷰 : --worktree로 멀티 에이전트 안전하게 쓰기, 병렬 작업 환경 구축 하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요! 갓대희 입니다.오늘은 Git Worktree 지원 기능에 대해 알아보려고 한다.Claude Code로 여러 작업을 동시에 진행하다 보면 한 세션의 변경사항이 다른 세션과 충돌하거나, 실험적인 코드가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;goddaehee.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@nova-kim/Git-Worktree%EB%A1%9C-AI-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-%ED%98%91%EC%97%85%EA%B3%BC-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B6%84%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@nova-kim/Git-Worktree%EB%A1%9C-AI-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-%ED%98%91%EC%97%85%EA%B3%BC-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B6%84%EB%A6%AC-%EC%A0%84%EB%9E%B5&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776262831394&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Git Worktree로 AI 워크플로 관리하기: 협업과 컨텍스트 분리 전략&quot; data-og-description=&quot;AI 기반 개발 흐름이 빠르게 자리 잡으면서,Git의 Worktree 기능은 협업과 자동화 워크플로를 구성할 때 유용한 무기가 되고 있습니다.특히 Claude, Gemini, Codex 등 AI 도구들을 연계해 작업을 구성하다 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@nova-kim/Git-Worktree%EB%A1%9C-AI-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-%ED%98%91%EC%97%85%EA%B3%BC-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B6%84%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; data-og-url=&quot;https://velog.io/@nova-kim/Git-Worktree로-AI-워크플로-관리하기-협업과-컨텍스트-분리-전략&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RMm6F/dJMb8YXM3bK/9WcMWHOdoBaRbVePpkmZTK/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/dzYCJX/dJMb9kT4uVP/cTM3I36otkCncF6P8R0Fmk/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/bRx3As/dJMb9gxmWLD/wkqN5h905EgYkyoQZP80F1/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot;&gt;&lt;a href=&quot;https://velog.io/@nova-kim/Git-Worktree%EB%A1%9C-AI-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-%ED%98%91%EC%97%85%EA%B3%BC-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B6%84%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@nova-kim/Git-Worktree%EB%A1%9C-AI-%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0-%ED%98%91%EC%97%85%EA%B3%BC-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B6%84%EB%A6%AC-%EC%A0%84%EB%9E%B5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RMm6F/dJMb8YXM3bK/9WcMWHOdoBaRbVePpkmZTK/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/dzYCJX/dJMb9kT4uVP/cTM3I36otkCncF6P8R0Fmk/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080,https://scrap.kakaocdn.net/dn/bRx3As/dJMb9gxmWLD/wkqN5h905EgYkyoQZP80F1/img.png?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Git Worktree로 AI 워크플로 관리하기: 협업과 컨텍스트 분리 전략&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;AI 기반 개발 흐름이 빠르게 자리 잡으면서,Git의 Worktree 기능은 협업과 자동화 워크플로를 구성할 때 유용한 무기가 되고 있습니다.특히 Claude, Gemini, Codex 등 AI 도구들을 연계해 작업을 구성하다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=JtA2JeqlTnI&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=JtA2JeqlTnI&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=JtA2JeqlTnI&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cmaUdI/dJMb89548u2/y1E2UkSVBqGAXCijfmgFuK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/PmVie/dJMb85vQwxo/W2H7NvVxrMapDn3iLdtjrK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;Git Worktree로 여러 피처 동시에 개발하기 | AI 코딩 시대의 필수 스킬&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/JtA2JeqlTnI&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;</description>
      <category>  AI/✏ AI Tools</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/322</guid>
      <comments>https://tech-interview.tistory.com/322#entry322comment</comments>
      <pubDate>Wed, 15 Apr 2026 22:53:50 +0900</pubDate>
    </item>
    <item>
      <title>[AI] MCP 설정 가이드</title>
      <link>https://tech-interview.tistory.com/321</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. MCP&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MCP&lt;/b&gt;는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;클라이언트(AI 도구)와 서버(도구 제공자) 사이를 잇는 JSON-RPC 기반 프로토콜&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;[AI 도구] - [MCP Server] - [파일 / API / DB]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버 하나가 &quot;파일 읽기&quot;, &quot;DB 조회&quot;, &quot;GitHub PR 생성&quot; 같은 툴(Tool)을 정의하면, AI가 작업 중에 그 툴을 자동으로 호출한다. 예를 들어 &quot;이 프로젝트의 DB 스키마를 보고 마이그레이션 코드 짜줘&quot;라고 하면 AI가 MCP를 통해 실제 DB에 접근한 뒤 코드를 작성한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;방식&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;주요 사용처&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;stdio&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;표준&amp;nbsp;입출력으로&amp;nbsp;통신.&amp;nbsp;로컬&amp;nbsp;프로세스를&amp;nbsp;직접&amp;nbsp;실행&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;npx,&amp;nbsp;node,&amp;nbsp;python&amp;nbsp;로컬&amp;nbsp;실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;HTTP&amp;nbsp;(SSE&amp;nbsp;/&amp;nbsp;Streamable)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;HTTP로&amp;nbsp;통신.&amp;nbsp;원격&amp;nbsp;서버&amp;nbsp;접속&amp;nbsp;가능&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;Docker&amp;nbsp;서버,&amp;nbsp;원격&amp;nbsp;배포&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. MCP 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP 서버는 각 도구의 설정 파일에 JSON 형식으로 등록한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도구별 전역 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역 설정이란 특정 프로젝트가 아닌 내 PC 전체에 적용되는 설정이다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;특정 프로젝트에만 적용하고 싶다면 프로젝트 루트에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;.mcp.json을 만들면 된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 106px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;도구&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 21px;&quot;&gt;전역 설정 파일 경로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;Claude&amp;nbsp;Code&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;~/.claude.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;Cursor&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;~/.cursor/mcp.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;Windsurf&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;~/.codeium/windsurf/mcp_config.json&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;Copilot&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;OS 마다 다르고 servers 값으로 설정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Windows에서 ~는 %HOMEPATH%(C:\Users\yourname)에 해당한다.&lt;/blockquote&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;서버이름&quot;: {
      &quot;command&quot;: &quot;실행명령어&quot;,
      &quot;args&quot;: [&quot;인자1&quot;, &quot;인자2&quot;],
      &quot;env&quot;: {
        &quot;API_KEY&quot;: &quot;your-key&quot;
      }
    },
    &quot;sse-서버이름&quot;: {
      &quot;url&quot;: &quot;http://localhost:3000/sse&quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3.&amp;nbsp;npx : 공식 서버를 즉시 붙이는 가장 빠른 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;npx&lt;/b&gt;는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;npm에 올라온 패키지를 설치 없이 즉시 실행해 주는 Node.js 도구&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 MCP 서버들이 대부분 npm에 배포되어 있어 가장 간편하게 시작할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# Node.js 18+ 설치 확인 (없으면 https://nodejs.org)
node -v&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하려는 서버를 찾은 뒤, 해당 서버의 공식 문서에서 제공하는 설정 예시를 복사해서 설정 파일에 붙여넣으면 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Windows 네이티브 환경(WSL 아님)에서는 npx를 직접 실행하면 &quot;Connection closed&quot; 오류가 발생할 수 있다.&lt;br /&gt;cmd /c 래퍼로 감싸주면 해결된다.&lt;/blockquote&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-server&quot;: {
      &quot;command&quot;: &quot;cmd&quot;,
      &quot;args&quot;: [&quot;/c&quot;, &quot;npx&quot;, &quot;-y&quot;, &quot;패키지명&quot;, &quot;추가인자...&quot;]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Node.js : JS/TS로 커스텀 서버를 만드는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사내 API 연동, 독자적인 비즈니스 로직과 같이 공식 서버에 없는 기능을 직접 만들 때 사용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트 초기화 및 서버 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;mkdir my-mcp-server &amp;amp;&amp;amp; cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// src/index.ts
import { McpServer } from &quot;@modelcontextprotocol/sdk/server/mcp.js&quot;;
import { StdioServerTransport } from &quot;@modelcontextprotocol/sdk/server/stdio.js&quot;;
import { z } from &quot;zod&quot;;

const server = new McpServer({ name: &quot;my-custom-server&quot;, version: &quot;1.0.0&quot; });

server.tool(
  &quot;get_deployment_status&quot;,
  &quot;서비스 배포 상태를 조회합니다&quot;,
  { service: z.string().describe(&quot;서비스 이름&quot;) },
  async ({ service }) =&amp;gt; {
    const res = await fetch(`https://api.example.com/api/status/${service}`);
    const data = await res.json();
    return { content: [{ type: &quot;text&quot;, text: JSON.stringify(data, null, 2) }] };
  }
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}
main().catch(console.error);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 후 설정 파일에 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;npx tsc&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-server&quot;: {
      &quot;command&quot;: &quot;node&quot;,
      &quot;args&quot;: [&quot;/absolute/path/to/my-mcp-server/dist/index.js&quot;],
      &quot;env&quot;: { &quot;DEPLOY_API_KEY&quot;: &quot;your-api-key&quot; }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;경로는 반드시 절대 경로를 사용한다. 상대 경로는 AI 도구 실행 위치에 따라 오동작할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Python/uvx : AI, 데이터 도구를 연동하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uv는 pip보다 빠른 Python 패키지 관리자이고, uvx는 Python 패키지를 설치 없이 즉시 실행해 주는 npx의 Python 버전이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크롤링, 데이터 분석, AI 라이브러리 기반 MCP 서버에 유용하다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# uv 설치 (macOS/Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows PowerShell (관리자 권한으로 실행)
# PowerShell: Windows에 내장된 명령줄 셸로, macOS Terminal(zsh/bash)에 해당한다.
powershell -ExecutionPolicy ByPass -c &quot;irm https://astral.sh/uv/install.ps1 | iex&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정 파일에 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;playwright&quot;: {
      &quot;command&quot;: &quot;uvx&quot;,
      &quot;args&quot;: [&quot;mcp-playwright&quot;]
    },
    &quot;data-analysis&quot;: {
      &quot;command&quot;: &quot;python&quot;,
      &quot;args&quot;: [&quot;/absolute/path/server.py&quot;]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Python으로 직접 서버 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;# server.py
from mcp.server.fastmcp import FastMCP
import pandas as pd

mcp = FastMCP(&quot;data-analysis-server&quot;)

@mcp.tool()
def analyze_csv(filepath: str) -&amp;gt; str:
    &quot;&quot;&quot;CSV 파일을 읽어 기본 통계를 반환합니다&quot;&quot;&quot;
    df = pd.read_csv(filepath)
    return df.describe().to_string()

if __name__ == &quot;__main__&quot;:
    mcp.run()&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;# uvx로 실행하는 경우: 별도 설치 불필요
# python server.py로 직접 실행하는 경우: 아래 패키지 설치 필요
pip install mcp pandas&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. HTTP 방식 (Docker, 원격 URL) : 원격으로 운영하는 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stdio 방식이 로컬 프로세스를 직접 실행하는 것이라면, HTTP 방식은 어딘가에 떠있는 서버에 연결하는 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 이미지를 실행해서 MCP 서버로 사용하는 경우&lt;/li&gt;
&lt;li&gt;이미 배포된 서버에 URL로 연결하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Docker로 MCP 서버 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Docker&lt;/b&gt;는 누군가 미리 만들어 배포한 프로그램(이미지)을 내 PC에서 그대로 실행할 수 있게 해주는 도구다. Docker 이미지는 Ubuntu, Debian, Alpine Linux 등 다양한 Linux 베이스를 사용한다. 누군가 Docker 이미지로 배포해둔 MCP 서버가 있다면 환경을 그대로 포장해서 어디서든 동일하게 실행할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;[내 맥북]   &amp;rarr;  [Docker 컨테이너 (Linux 내부)]
[팀원 PC]   &amp;rarr;  [동일한 컨테이너] &amp;larr; 항상 동일한 환경
[회사 서버] &amp;rarr;  [동일한 컨테이너]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 후 설정 파일에 아래처럼 등록하면 된다. command로 Docker를 직접 실행하는 stdio 방식이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;run: 이미지를 실행&lt;/li&gt;
&lt;li&gt;-i: stdio로 통신 (AI 도구와 입출력 연결)&lt;/li&gt;
&lt;li&gt;--rm: 종료 시 컨테이너 자동 삭제&lt;/li&gt;
&lt;li&gt;-e MY_API_KEY: 환경변수를 컨테이너 안으로 전달&lt;/li&gt;
&lt;li&gt;마지막 줄: 실행할 Docker 이미지 이름 (사용하는 MCP 서버에 따라 다름)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; style=&quot;color: #14181f;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-docker-mcp&quot;: {
      &quot;command&quot;: &quot;docker&quot;,
      &quot;args&quot;: [
        &quot;run&quot;, &quot;-i&quot;, &quot;--rm&quot;,
        &quot;-e&quot;, &quot;MY_API_KEY&quot;,
        &quot;some-org/some-mcp-server:latest&quot;
      ],
      &quot;env&quot;: {
        &quot;MY_API_KEY&quot;: &quot;${MY_API_KEY}&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Windows에서 WSL을 거치는 경우, Docker 명령어를 WSL을 통해 실행하는 패턴도 자주 쓰인다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;my-docker-mcp&quot;: {
      &quot;command&quot;: &quot;C:\\Windows\\System32\\wsl.exe&quot;,
      &quot;args&quot;: [
        &quot;-d&quot;, &quot;Ubuntu&quot;, &quot;--&quot;, &quot;bash&quot;, &quot;-lc&quot;,
        &quot;docker run -i --rm -e MY_API_KEY some-org/some-mcp-server:latest&quot;
      ],
      &quot;env&quot;: {
        &quot;MY_API_KEY&quot;: &quot;${MY_API_KEY}&quot;,
        &quot;WSLENV&quot;: &quot;MY_API_KEY/u&quot;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이미 있는 서버에 URL로 연결하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 없이 이미 배포된 외부 MCP 서버나 SaaS 형태의 서비스에 접속할 때는 &lt;code&gt;command&lt;/code&gt; 없이 &lt;code&gt;url&lt;/code&gt;만으로 등록할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증이 필요하면 &lt;code&gt;headers&lt;/code&gt;를 추가한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;remote-server&quot;: {
      &quot;url&quot;: &quot;https://example.com/mcp/sse&quot;,
      &quot;headers&quot;: { &quot;Authorization&quot;: &quot;Bearer YOUR_TOKEN&quot; }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 보안, 디버깅&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;API 키 노출 주의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;.mcp.json&lt;/code&gt;을 git에 커밋할 때 API 키를 직접 쓰면 키가 그대로 올라간다. 반드시 환경변수로 분리해야 한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 위험
&quot;env&quot;: { &quot;GITHUB_TOKEN&quot;: &quot;your_github_token&quot; }

// 안전
&quot;env&quot;: { &quot;GITHUB_TOKEN&quot;: &quot;${GITHUB_TOKEN}&quot; }

// 환경 변수 등록
# macOS/Linux (~/.zshrc 또는 ~/.bashrc)
export GITHUB_TOKEN=&quot;ghp_xxxx&quot;
# Windows PowerShell
[System.Environment]::SetEnvironmentVariable(&quot;GITHUB_TOKEN&quot;, &quot;ghp_xxxx&quot;, &quot;User&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀과 &lt;code&gt;.mcp.json&lt;/code&gt;을 공유하면서 키를 직접 써야 할 경우엔 &lt;code&gt;.gitignore&lt;/code&gt;에 추가한다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;.mcp.json
.env&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MCP Inspector 공식 디버깅 도구&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버가 AI 도구에서 인식이 안 될 때, Inspector로 서버 자체가 정상인지 먼저 확인한다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;브라우저에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;http://localhost:6274&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;접속 &amp;rarr; Transport / Command / Arguments 입력 &amp;rarr; Connect &amp;rarr; 툴 목록 확인 및 직접 호출 테스트가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;npx @modelcontextprotocol/inspector&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  AI/✏ AI Tools</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/321</guid>
      <comments>https://tech-interview.tistory.com/321#entry321comment</comments>
      <pubDate>Mon, 16 Mar 2026 20:39:04 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal] 최적화</title>
      <link>https://tech-interview.tistory.com/319</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 최적화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;높은 렌더링 부하와 CPU 병목 현상은 게임의 프레임 속도를 떨어뜨리고 게임 플레이에 영향을 줄 수 있다. 이를 해결하기 위해 &lt;b&gt;최적화&lt;/b&gt;는 필수이다. 특히 최적화는 한 번에 끝나는 작업이 아니기 때문에 &lt;u&gt;작업, 테스트, 개선의 반복&lt;/u&gt;이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 렌더링 최적화&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;렌더링(rendering)&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;컴퓨터 프로그램을 이용해 2D 또는 3D 모델에서 이미지를 생성하는 프로세스&lt;/span&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Culling&lt;/li&gt;
&lt;li&gt;LOD&lt;/li&gt;
&lt;li&gt;Nanite&lt;/li&gt;
&lt;li&gt;Shader Complexity View를 통해&amp;nbsp;머터리얼 복잡도 확인&lt;/li&gt;
&lt;li&gt;필요하지 않은 그림자 제거 및&amp;nbsp;실시간 그림자 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Culling&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 최적화 기법 중 가장 대표되는 Culling에 대해 알아보자.&amp;nbsp;&lt;b&gt;Culling&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;굳이 렌더링 하지 않아도 된다고 판단된 오브젝트들을 제외하는 것&lt;/span&gt;을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼에서의 Culling은 크게 4가지로 나눌 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Distance Culling
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액터와 플레이어 카메라 사이의 거리에 따라 오브젝트를 Culling 시키는 방식이다&lt;/li&gt;
&lt;li&gt;LOD와 Cull Distance Volume을 사용해서 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;View&amp;nbsp;Frustum&amp;nbsp;Culling
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카메라 절두체(View Frustum)에서 벗어난 영역에 있는 오브젝트를 Culling 시키는 방식이다.&lt;/li&gt;
&lt;li&gt;언리얼 엔진에서 기본 지원한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Precomputed&amp;nbsp;Visibility
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;움직이지 않는 액터들을 대상으로 Shadow Casting Surface 위에 Visibility State 정보를 저장해 놓는 방식이다.&lt;/li&gt;
&lt;li&gt;라이팅 빌드 도중에 visibility 정보를 오프라인에서 생성하며, 크지 않은 레벨과 저사양, 모바일 기기에 적합하다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dynamic&amp;nbsp;Occlusion
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간으로 물체를 가리는 오브젝트(Occluder)와 가려지는 오브젝트(Occludee)를 판단해서 Occludee를 Culling 시키는 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;939&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxCvlW/btsL1Y9OzR8/qmGxxmOcN7bfAAx3zfHie0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxCvlW/btsL1Y9OzR8/qmGxxmOcN7bfAAx3zfHie0/img.png&quot; data-alt=&quot;Culling&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxCvlW/btsL1Y9OzR8/qmGxxmOcN7bfAAx3zfHie0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxCvlW%2FbtsL1Y9OzR8%2FqmGxxmOcN7bfAAx3zfHie0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;440&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;939&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Culling&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;Occlusion&amp;nbsp;Culling&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Occlusion Culling&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;카메라에 보이지 않는 물체를 렌더링 하지 않도록 처리하는 방식&lt;/span&gt;이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hierarchical Z-Buffer Occlusion Culling 방식을 사용하여, 화면을 Z 버퍼로 나누고 각 픽셀에 가려진 물체를 감지 후 가려진 물체를 렌더링 파이브라인에서 제외한다.&lt;/li&gt;
&lt;li&gt;물체의 바운드 설정이 중요하다. 이 설정이 부정확하면 프리뷰에서 오브젝트가 보이지 않거나 성능이 나빠지는 등 문제가 될 수 있다.&lt;/li&gt;
&lt;li&gt;프로젝트 세팅에서 Occlusion Culling 활성화 설정을 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Occlusion Culling은 정적, 동적 환경에 따라 다음과 같이 나눌 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Static Occlusion
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적인 환경&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Precomputed Visibility Volumes&lt;/u&gt;를 활용해, 미리 계산된 데이터를 바탕으로 가림 처리를 수행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Dynamic Occlusion&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실시간으로 변하는 동적인 환경&lt;/li&gt;
&lt;li&gt;카메라와 오브젝트의 상대적인 위치와 움직임을 기준으로 매 프레임마다 Z-Buffer와 Occlusion Queries를 계산한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) LOD(Level of Detail)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LOD&lt;/b&gt;는&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;멀리 있는 오브젝트는 저해상도 모델을 사용하고, 가까이 있는 오브젝트는 고해상도 모델을 사용&lt;/span&gt;하도록 설정하는 기술이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 LOD 메시를 만들어도 되지만, 언리얼에서 제공하는 &lt;u&gt;자동 LOD 생성&lt;/u&gt;을 통해서도 꽤 괜찮게 적용이 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Nanite를&lt;/span&gt;&amp;nbsp;사용한다면, 이미 자동으로 LOD 설정한 것과 같아서 추가 LOD 설정은 필요하지 않다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt; Distance Culling&lt;/u&gt; 방식을 통해 아예 렌더링을 하지 않는 방법도 있다. Min/Max 값을 조절해서 카메라와의 거리에 따라 오브젝트를 보여줄지 말지를 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ur7QV/btsL12xAO71/RO2BUGO79FbmGejvstsN9k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ur7QV/btsL12xAO71/RO2BUGO79FbmGejvstsN9k/img.gif&quot; data-alt=&quot;LOD&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ur7QV/btsL12xAO71/RO2BUGO79FbmGejvstsN9k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ur7QV/btsL12xAO71/RO2BUGO79FbmGejvstsN9k/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;471&quot; data-origin-width=&quot;909&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;LOD&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) Nanite&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나나이트&lt;/b&gt;는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;언리얼 엔진 5의 가상화 지오메트리 시스템&lt;/span&gt;으로 새로운 내부 메시 포맷과 렌더링 기술을 사용하여 픽셀 스케일의 디테일과 방대한 양의 오브젝트를 렌더링한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하이폴 메시를 그대로 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;LOD, 노말맵이 필요 없다.&lt;/li&gt;
&lt;li&gt;클러스터 단위로 렌더링이 가능하기 때문에&amp;nbsp;Culling 성능이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나나이트가 만능인 것 같지만, 제약이 존재한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불투명한 머터리얼만 가능하다.&lt;/li&gt;
&lt;li&gt;Skeletal Mesh, WPO(월드 포지션) , Deformation 등 버텍스에 대한 연산이 들어가면 안된다.&lt;/li&gt;
&lt;li&gt;인스턴스의 버텍스 페인팅은 안된다.&lt;/li&gt;
&lt;li&gt;항상 더 나은 성능을 보장하는 것은 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 유튜브에서 자세히 확인이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=e-XFHcD7ibA&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=e-XFHcD7ibA&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=e-XFHcD7ibA&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bJMgWM/hyX4tKCZIj/HLUepnjgIOKmvMjSTJvWOK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/gsY0q/hyX72duL0y/jQronnkMPrvLB7YeckIBGK/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;LOD, 노말맵 왜 씀? 언리얼 나나이트 단숨에 정ㅋ벅ㅋ&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/e-XFHcD7ibA&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. CPU 최적화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 블루프린트에서 C++ 전환&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블루프린트는 간편하지만 C++에 비해 성능이 떨어진다. 만약 블루프린트를 사용하더라도 Tick 사용은 피하고 성능이 중요하지 않은 기능 구현만 하는 것을 추천한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) Tick 이벤트 최소화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매 프레임 호출되는 Tick 이벤트는 많으면 성능이 저하된다. 가능한 필요한 경우에만 Tick을 활성화하고 Timer나 이벤트로 대체하여 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) 오브젝트 풀링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복적으로 생성, 삭제되는 오브젝트는 풀링 기법을 통해 관리하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) AI&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 캐릭터의 Behavior Tree나 경로 탐색은 성능에 영향을 준다. Nav Mesh를 잘 설정하고, AI 캐릭터의 업데이트 빈도를 낮추는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 메모리 최적화&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) Garbage&amp;nbsp;Collection&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼은 주기적으로 가비지 컬렉션을 수행하는데, 메모리 관리를 잘못하면 성능 저하가 발생한다. 큰 데이터는 필요할 때만 로드하고, 사용하지 않는 데이터는 명시적으로 제거하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 텍스처 및 메시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하지 않는 텍스처는 제거하고, 가능한 압축된 포맷을 사용하여 메시의 폴리곤 수를 최적화하는 것이 좋다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Nanite를 사용하는 것도 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;5. 프로파일링&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;언리얼 엔진 내의 프로파일링 도구를 사용하여 어떤 부분이 가장 많은 자원을 사용하는지 분석하고, 최적화할 부분을 찾을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;가장 간단한 방법은 콘솔 명령을 통해 확인하는 방법이다. 아래 명령어를 콘솔에 입력하면 각 부분의 성능을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;stat fps&lt;br /&gt;stat unit&lt;br /&gt;stat gpu&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;다음으로 프로파일링 툴을 활용하여 무엇이 빠르고, 무엇이 느리고, 어느 부분인지 자세히 분석할 수 있다. 여러 가지 툴이 있지만 대표적으로 Insights가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1265&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRoTXN/btsL3QQkpFi/Zs9HKhawZNoifUfkUKgdK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRoTXN/btsL3QQkpFi/Zs9HKhawZNoifUfkUKgdK0/img.png&quot; data-alt=&quot;Insights&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRoTXN/btsL3QQkpFi/Zs9HKhawZNoifUfkUKgdK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRoTXN%2FbtsL3QQkpFi%2FZs9HKhawZNoifUfkUKgdK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;398&quot; data-origin-width=&quot;1265&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Insights&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로파일링 툴을 활용하면 병목 현상을 확인하고 최적화 방향을 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/ko/tech-blog/an-in-depth-look-at-unreal-engine-4-20-s-proxy-lod-tool&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.unrealengine.com/ko/tech-blog/an-in-depth-look-at-unreal-engine-4-20-s-proxy-lod-tool&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://delightlane.tistory.com/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://delightlane.tistory.com/21&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1738047203357&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE4] 컬링(Culling)&quot; data-og-description=&quot;개요 게임에는 수많은 오브젝트들이 배치됩니다. 하지만 그 배치된 오브젝트들이 늘 그려질 필요는 없을 것입니다. 전혀 노출되지 않는 오브젝트까지 매번 계산하여 그리는 건 낭비이기 때문입&quot; data-og-host=&quot;delightlane.tistory.com&quot; data-og-source-url=&quot;https://delightlane.tistory.com/21&quot; data-og-url=&quot;https://delightlane.tistory.com/21&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5OBya/hyX7RJO9DA/gBA2lAKF3SGl7abOKyiZpK/img.jpg?width=800&amp;amp;height=578&amp;amp;face=0_0_800_578,https://scrap.kakaocdn.net/dn/TmMj9/hyX4tKCOfR/lyEtZyAqyKT7Ik18K014CK/img.jpg?width=800&amp;amp;height=578&amp;amp;face=0_0_800_578,https://scrap.kakaocdn.net/dn/cpVlWK/hyX70teOkO/Fm7MPN9QaL4fQwKe99w5kK/img.jpg?width=986&amp;amp;height=713&amp;amp;face=0_0_986_713&quot;&gt;&lt;a href=&quot;https://delightlane.tistory.com/21&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://delightlane.tistory.com/21&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5OBya/hyX7RJO9DA/gBA2lAKF3SGl7abOKyiZpK/img.jpg?width=800&amp;amp;height=578&amp;amp;face=0_0_800_578,https://scrap.kakaocdn.net/dn/TmMj9/hyX4tKCOfR/lyEtZyAqyKT7Ik18K014CK/img.jpg?width=800&amp;amp;height=578&amp;amp;face=0_0_800_578,https://scrap.kakaocdn.net/dn/cpVlWK/hyX70teOkO/Fm7MPN9QaL4fQwKe99w5kK/img.jpg?width=986&amp;amp;height=713&amp;amp;face=0_0_986_713');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE4] 컬링(Culling)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요 게임에는 수많은 오브젝트들이 배치됩니다. 하지만 그 배치된 오브젝트들이 늘 그려질 필요는 없을 것입니다. 전혀 노출되지 않는 오브젝트까지 매번 계산하여 그리는 건 낭비이기 때문입&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;delightlane.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://choi-dan-di.github.io/unreal/optimization-profiling/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://choi-dan-di.github.io/unreal/optimization-profiling/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1738048272657&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Unreal Engine] 언리얼 엔진 최적화 - 1. 프로파일링&quot; data-og-description=&quot;언리얼 엔진의 최적화 방법에 대해 알아보기&quot; data-og-host=&quot;choi-dan-di.github.io&quot; data-og-source-url=&quot;https://choi-dan-di.github.io/unreal/optimization-profiling/&quot; data-og-url=&quot;https://choi-dan-di.github.io/unreal/optimization-profiling/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bU3vmw/hyX4kNIMbC/ywu4MOrBolz2FcKkWD6VJK/img.png?width=647&amp;amp;height=379&amp;amp;face=0_0_647_379,https://scrap.kakaocdn.net/dn/BkHIJ/hyX4wAwILN/UtaBtNZofoHqKko9MOQvF1/img.png?width=392&amp;amp;height=243&amp;amp;face=0_0_392_243&quot;&gt;&lt;a href=&quot;https://choi-dan-di.github.io/unreal/optimization-profiling/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://choi-dan-di.github.io/unreal/optimization-profiling/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bU3vmw/hyX4kNIMbC/ywu4MOrBolz2FcKkWD6VJK/img.png?width=647&amp;amp;height=379&amp;amp;face=0_0_647_379,https://scrap.kakaocdn.net/dn/BkHIJ/hyX4wAwILN/UtaBtNZofoHqKko9MOQvF1/img.png?width=392&amp;amp;height=243&amp;amp;face=0_0_392_243');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Unreal Engine] 언리얼 엔진 최적화 - 1. 프로파일링&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 엔진의 최적화 방법에 대해 알아보기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;choi-dan-di.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  Game/✏ Unreal</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/319</guid>
      <comments>https://tech-interview.tistory.com/319#entry319comment</comments>
      <pubDate>Tue, 28 Jan 2025 16:11:28 +0900</pubDate>
    </item>
    <item>
      <title>[C++] Palindrome</title>
      <link>https://tech-interview.tistory.com/318</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Palindrome&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Palindrome&lt;/b&gt;은 거꾸로 읽어도 제대로 읽는 것과 같은 문장을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;617&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EX5fD/btsJFJVDp5B/tLStHG0KWKCYjgTZLV4FUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EX5fD/btsJFJVDp5B/tLStHG0KWKCYjgTZLV4FUk/img.png&quot; data-alt=&quot;Palindrome&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EX5fD/btsJFJVDp5B/tLStHG0KWKCYjgTZLV4FUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEX5fD%2FbtsJFJVDp5B%2FtLStHG0KWKCYjgTZLV4FUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;368&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;617&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Palindrome&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/palindrome-partitioning/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/palindrome-partitioning/description/&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726822531610&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;vector&amp;gt;
#include &amp;lt;string&amp;gt;
using namespace std;

class Solution {
public:
    vector&amp;lt;vector&amp;lt;string&amp;gt;&amp;gt; answer;
    vector&amp;lt;string&amp;gt; sub;

    vector&amp;lt;vector&amp;lt;string&amp;gt;&amp;gt; partition(string s) {
        dfs(s, 0);
        return answer;
    }

    void dfs(string s, int index) {
        if (index == s.length()) {
            answer.push_back(sub);
            return;
        }

        for (int i = index; i &amp;lt; s.length(); i++) {
            string substr = s.substr(index, i - index + 1);
            if (!palindrome(substr))
                continue;
            sub.push_back(substr);
            dfs(s, i + 1);
            sub.pop_back();
        }
    }

    bool palindrome(string s) {
        int size = s.length();
        for (int i = 0; i &amp;lt; size / 2; i++)
            if (s[i] != s[size - i - 1])
                return false;
        return true;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/longest-palindromic-substring/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/longest-palindromic-substring/description/&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726822445531&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
using namespace std;

class Solution {
public:
	bool dp[1001][1001]{};

	string longestPalindrome(string s) {
		// 1글자
		string answer = s.substr(0, 1);
		for (int i = 0; i &amp;lt; s.size(); i++)
			dp[i][i] = true;

		// 2글자
		for (int i = 0; i &amp;lt; s.size() - 1; i++)
			if (s[i] == s[i + 1]) {
				dp[i][i + 1] = true;
				answer = s.substr(i, 2);
			}

		// 3글자 이상
		for (int i = 3; i &amp;lt;= s.size(); i++)
			for (int j = 0; j + i &amp;lt;= s.size(); j++)
				if (dp[j + 1][j + i - 2] &amp;amp;&amp;amp; s[j] == s[j + i - 1]) {
					dp[j][j + i - 1] = true;
					if (answer.size() &amp;lt; i)
						answer = s.substr(j, i);
				}

		return answer;
	}
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/shortest-palindrome/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/shortest-palindrome/description/&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1726822278979&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;string&amp;gt;
using namespace std;

class Solution {
public:
    string shortestPalindrome(string s) 
    {
        int i = 0, n = s.size();
        for (int j = n - 1; j &amp;gt;= 0; --j)
            if (s[i] == s[j]) 
                ++i;

        if (i == n) 
            return s;

        string add = s.substr(i); // 추가해야 할 최소 문자열
        reverse(add.begin(), add.end());
        return add + shortestPalindrome(s.substr(0, i)) + s.substr(i);
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>  Computer Science/✏ Algorithm</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/318</guid>
      <comments>https://tech-interview.tistory.com/318#entry318comment</comments>
      <pubDate>Fri, 20 Sep 2024 17:49:34 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal] 패키징</title>
      <link>https://tech-interview.tistory.com/317</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 패키징?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;패키징&lt;/b&gt;은 사용자에게 배포하기 위해 컨텐츠와 소스들을 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;빌드, 쿠킹, 패킹을 하는 일련의 과정&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 빌드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빌드&lt;/b&gt;는 선택한 플랫폼에서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;실행 가능한 실행 파일을 만들기 위한 컴파일 과정&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;전처리 UBT &amp;rarr; UHT (.h) &amp;rarr; 컴파일 (.cpp) &amp;rarr; 어셈블리 (.obj) &amp;rarr; Module &amp;rarr; 완료&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선 UBT와 UHT의 전처리 단계를 거친다. &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;일반적으로 UBT가 먼저 호출되며 필요에 따라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a style=&quot;color: #0070d1; text-align: left;&quot; href=&quot;https://tech-interview.tistory.com/266&quot;&gt;UHT&lt;/a&gt;가 호출된다.&lt;/li&gt;
&lt;li&gt;그 후 컴파일러가 컴파일을 수행한다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;UBT(Unreal Build Tool)&lt;/b&gt;는 프로젝트의 빌드 프로세스를 관리한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 소스 코드 파일들이 변경되었는지 확인하고, 그에 따라 어떤 부분을 새롭게 컴파일할 것인지 결정한다.&lt;/li&gt;
&lt;li&gt;프로젝트의 폴더 구조와 소스 파일을 기반으로 OS에 맞는 솔루션을 생성하여 멀티 플랫폼 개발이 가능하도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUMrex/btsJDw9D0q1/3yKFeB9fCFHNVse6jIiKek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUMrex/btsJDw9D0q1/3yKFeB9fCFHNVse6jIiKek/img.png&quot; data-alt=&quot;UBT&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUMrex/btsJDw9D0q1/3yKFeB9fCFHNVse6jIiKek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUMrex%2FbtsJDw9D0q1%2F3yKFeB9fCFHNVse6jIiKek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;226&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;UBT&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UBT의 동작 방식은 다음과 같다. 언리얼 C++ 프로젝트를 생성하면 3개의 빌드 정보 파일이 함께 생성된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(프로젝트명).build.cs: PCH, 외부 모듈 등 빌드 옵션을 관리한다.&lt;/li&gt;
&lt;li&gt;(프로젝트명).target.cs: 게임 빌드를 설정한다.&lt;/li&gt;
&lt;li&gt;(프로젝트명Editor).target.cs: 에디터 빌드를 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;빌드 시 UBT가 실행되면서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;C# 컴파일러에 의해 빌드 정보 파일도 함께 컴파일되는데, 이 파일에 작성된 사양대로 빌드 과정이 진행되게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) 쿠킹&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿠킹&lt;/b&gt;은 선택한 플랫폼에서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;사용할 수 있는 포맷으로 컨텐츠들을 변환하는 작업&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 패키징 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패키징을 위해서는 다음과 같은 설정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mGBTN/btsJDnLMYls/iDbO1GLCwxS3rqogbuQvx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mGBTN/btsJDnLMYls/iDbO1GLCwxS3rqogbuQvx1/img.png&quot; data-alt=&quot;패키징 설정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mGBTN/btsJDnLMYls/iDbO1GLCwxS3rqogbuQvx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmGBTN%2FbtsJDnLMYls%2FiDbO1GLCwxS3rqogbuQvx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;743&quot; height=&quot;192&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;192&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;패키징 설정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Build Connfiguration
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Debug
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;엔진과 게임 코드 모두 빌드한다.&lt;/li&gt;
&lt;li&gt;디버깅 심볼이 들어있는 빌드 환경으로 디버깅 시 사용하기 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DebugGame
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최적화 없이 게임 코드만 빌드한다.&lt;/li&gt;
&lt;li&gt;게임 모듈만 디버깅하는 경우에 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Development
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최적화 없이 엔진과 게임 코드 모두 빌드한다.&lt;/li&gt;
&lt;li&gt;컴파일 시 코드 변경 사항이 에디터에 반영된다.&lt;/li&gt;
&lt;li&gt;개발 시 실전 테스트용으로 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Test
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;Shipping과 동일하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;console commands, stats, profiling tools 유지한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Shipping
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퍼포먼스 최적화 및 게임 배포 시 사용한다.&lt;/li&gt;
&lt;li&gt;console commands, stats, profiling tools 삭제한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Full Rebuild: 모든 파일 빌드가 필요하다면 true, 수정된 파일만 빌드가 필요하다면 false로 설정한다.&lt;/li&gt;
&lt;li&gt;List of maps to include in a packaged build&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정이 끝났다면 플랫폼 버튼을 통해 플랫폼 별 패키징이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FVxa4/btsJD5KowjE/iV4dP68q96d5EwLdsh9SP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FVxa4/btsJD5KowjE/iV4dP68q96d5EwLdsh9SP0/img.png&quot; data-alt=&quot;플랫폼 패키징&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FVxa4/btsJD5KowjE/iV4dP68q96d5EwLdsh9SP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFVxa4%2FbtsJD5KowjE%2FiV4dP68q96d5EwLdsh9SP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;452&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;플랫폼 패키징&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726664370467&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Unreal] 컴파일 과정 (UBT, UHT 호출시점)&quot; data-og-description=&quot;언리얼에서 빌드를 시작하면 컴파일러가 컴파일을 수행하기 전에 언리얼 빌드 툴(UBT)과 언리얼 헤더 툴(UHT)이 콜 되어먼저 실행된다. 일반적으로 UBT가 먼저 호출되며, 필요에 따라 UHT가 호출된&quot; data-og-host=&quot;designerd.tistory.com&quot; data-og-source-url=&quot;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&quot; data-og-url=&quot;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byzQqh/hyW2XZVmub/BEjGKuuplXqDjM9ufie1q0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bXCEmp/hyW21Vv8lp/YyAalFhz5SGiUwtuMnI4G0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450&quot;&gt;&lt;a href=&quot;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://designerd.tistory.com/entry/Unreal-%EC%BB%B4%ED%8C%8C%EC%9D%BC-%EA%B3%BC%EC%A0%95&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byzQqh/hyW2XZVmub/BEjGKuuplXqDjM9ufie1q0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bXCEmp/hyW21Vv8lp/YyAalFhz5SGiUwtuMnI4G0/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Unreal] 컴파일 과정 (UBT, UHT 호출시점)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;언리얼에서 빌드를 시작하면 컴파일러가 컴파일을 수행하기 전에 언리얼 빌드 툴(UBT)과 언리얼 헤더 툴(UHT)이 콜 되어먼저 실행된다. 일반적으로 UBT가 먼저 호출되며, 필요에 따라 UHT가 호출된&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;designerd.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726659827805&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[UE] 빌드 환경설정(Build Mode): Debug, DebugGame, Development, Shipping&quot; data-og-description=&quot;UnrealBuildTool은 *.build.cs 및 *.target.cs 파일을 사용하여 게임 프로젝트를 빌드한다. 목차 빌드 환경설정 UnrealBuildTool(UBT)은 *.build.cs 및 *.target.cs 파일을 사용하여 게임 프로젝트를 빌드한다. 빌드 환&quot; data-og-host=&quot;designerd.tistory.com&quot; data-og-source-url=&quot;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&quot; data-og-url=&quot;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CD50d/hyW6JeAT0O/iCJ8LKcPWWTAidGjQKGjEK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cMlP0R/hyW6DZKHAp/gIQlb8zPAzswAafJ1HJAc1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/el2LQE/hyW6yKUbuC/Y2EiAPPVPzeKkT34ycOibK/img.png?width=1400&amp;amp;height=788&amp;amp;face=0_0_1400_788&quot;&gt;&lt;a href=&quot;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CD50d/hyW6JeAT0O/iCJ8LKcPWWTAidGjQKGjEK/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cMlP0R/hyW6DZKHAp/gIQlb8zPAzswAafJ1HJAc1/img.png?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/el2LQE/hyW6yKUbuC/Y2EiAPPVPzeKkT34ycOibK/img.png?width=1400&amp;amp;height=788&amp;amp;face=0_0_1400_788');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[UE] 빌드 환경설정(Build Mode): Debug, DebugGame, Development, Shipping&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UnrealBuildTool은 *.build.cs 및 *.target.cs 파일을 사용하여 게임 프로젝트를 빌드한다. 목차 빌드 환경설정 UnrealBuildTool(UBT)은 *.build.cs 및 *.target.cs 파일을 사용하여 게임 프로젝트를 빌드한다. 빌드 환&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;designerd.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://makerejoicegames.tistory.com/507&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://makerejoicegames.tistory.com/507&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1726667605774&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;언리얼엔진5 Project Packaging&quot; data-og-description=&quot;▣ 먼저 프로젝트를 패키징 하기 전에 패키징 세팅을 진행합니다.&amp;nbsp;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/project-section-of-the-unreal-engine-project-settings?application_version=5.3&amp;nbsp;언리얼 엔진 프로젝&quot; data-og-host=&quot;makerejoicegames.tistory.com&quot; data-og-source-url=&quot;https://makerejoicegames.tistory.com/507&quot; data-og-url=&quot;https://makerejoicegames.tistory.com/507&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyrcFw/hyW6E5rsNA/yDf110UtC1p8W31GRwUWy1/img.jpg?width=800&amp;amp;height=483&amp;amp;face=0_0_800_483,https://scrap.kakaocdn.net/dn/cziava/hyW6DZLH3e/K9pqfYejtoWG3Skkk7HTYk/img.jpg?width=800&amp;amp;height=483&amp;amp;face=0_0_800_483,https://scrap.kakaocdn.net/dn/eZu32/hyW6ImsZU0/l5j75YzRkxckeJiCQxDDVk/img.jpg?width=2538&amp;amp;height=1538&amp;amp;face=0_0_2538_1538&quot;&gt;&lt;a href=&quot;https://makerejoicegames.tistory.com/507&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://makerejoicegames.tistory.com/507&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyrcFw/hyW6E5rsNA/yDf110UtC1p8W31GRwUWy1/img.jpg?width=800&amp;amp;height=483&amp;amp;face=0_0_800_483,https://scrap.kakaocdn.net/dn/cziava/hyW6DZLH3e/K9pqfYejtoWG3Skkk7HTYk/img.jpg?width=800&amp;amp;height=483&amp;amp;face=0_0_800_483,https://scrap.kakaocdn.net/dn/eZu32/hyW6ImsZU0/l5j75YzRkxckeJiCQxDDVk/img.jpg?width=2538&amp;amp;height=1538&amp;amp;face=0_0_2538_1538');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;언리얼엔진5 Project Packaging&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;▣ 먼저 프로젝트를 패키징 하기 전에 패키징 세팅을 진행합니다.&amp;nbsp;https://dev.epicgames.com/documentation/ko-kr/unreal-engine/project-section-of-the-unreal-engine-project-settings?application_version=5.3&amp;nbsp;언리얼 엔진 프로젝&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;makerejoicegames.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  Game/✏ Unreal</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/317</guid>
      <comments>https://tech-interview.tistory.com/317#entry317comment</comments>
      <pubDate>Wed, 18 Sep 2024 22:36:41 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal] 캐릭터 애니메이션 개선</title>
      <link>https://tech-interview.tistory.com/316</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 블렌드 스페이스(Blend&amp;nbsp;Space)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;걷기, 뛰기 등 기존 애니메이션의 구현 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;방식은 &lt;/span&gt;&lt;u style=&quot;letter-spacing: 0px;&quot;&gt;FSM 구조로 특정 조건에 맞는 애니메이션이 즉시 실행&lt;/u&gt;되도록 구현되어 있었&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;다. 그래서 이 방식은 애니메이션 전환이 일어날 때 딱딱 끊기는 느낌이 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;개선 전 1.gif&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Rnjt/btsIk1cbf2R/kDy2P8hWr3LFdNAvYO5X6k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Rnjt/btsIk1cbf2R/kDy2P8hWr3LFdNAvYO5X6k/img.gif&quot; data-alt=&quot;FSM&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Rnjt/btsIk1cbf2R/kDy2P8hWr3LFdNAvYO5X6k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/4Rnjt/btsIk1cbf2R/kDy2P8hWr3LFdNAvYO5X6k/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;322&quot; height=&quot;358&quot; data-filename=&quot;개선 전 1.gif&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;FSM&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애니메이션이 전환할 때 부드럽게 바뀌도록 블렌드 스페이스를 사용할 것이다.&amp;nbsp;&lt;b&gt;블렌드 스페이스&lt;/b&gt;는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;두 입력값에 따라 애니메이션을 블렌딩 시켜&lt;/span&gt; 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BaTca/btsI5u4kA0N/cKPDMbF28sudmZilCoyHf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BaTca/btsI5u4kA0N/cKPDMbF28sudmZilCoyHf1/img.png&quot; data-alt=&quot;블렌드 스페이스 생성&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BaTca/btsI5u4kA0N/cKPDMbF28sudmZilCoyHf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBaTca%2FbtsI5u4kA0N%2FcKPDMbF28sudmZilCoyHf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;608&quot; height=&quot;277&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;블렌드 스페이스 생성&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블렌드 스페이스를 생성한 후, 먼저 축 세팅이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH8wCD/btsI3QnxMPZ/k7Ss6ZOj5cFin6aEnAKmIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH8wCD/btsI3QnxMPZ/k7Ss6ZOj5cFin6aEnAKmIk/img.png&quot; data-alt=&quot;블렌드 스페이스 수정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH8wCD/btsI3QnxMPZ/k7Ss6ZOj5cFin6aEnAKmIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH8wCD%2FbtsI3QnxMPZ%2Fk7Ss6ZOj5cFin6aEnAKmIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;351&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;블렌드 스페이스 수정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Vertical&amp;nbsp;Axis
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Name: Speed&lt;/li&gt;
&lt;li&gt;Minimum Axis Value: 0&lt;/li&gt;
&lt;li&gt;Maximum Axis Value: 700&lt;/li&gt;
&lt;li&gt;Smoothing Time: 0.1. 값이 클수록 부드럽게 전환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 캐릭터의 걷기 속도는 500, 뛰기 속도는 700으로 설정되어 있어 이 값에 맞게 애니메이션을 배치해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;415&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T64Pu/btsI5f0GRYu/YvOwi1zWoIVlI6CGD2rMCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T64Pu/btsI5f0GRYu/YvOwi1zWoIVlI6CGD2rMCk/img.png&quot; data-alt=&quot;에디터 그리드 수정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T64Pu/btsI5f0GRYu/YvOwi1zWoIVlI6CGD2rMCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT64Pu%2FbtsI5f0GRYu%2FYvOwi1zWoIVlI6CGD2rMCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;361&quot; data-origin-width=&quot;919&quot; data-origin-height=&quot;415&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에디터 그리드 수정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Idle 애니메이션: Speed 0&lt;/li&gt;
&lt;li&gt;Walk 애니메이션: Speed 500&lt;/li&gt;
&lt;li&gt;Run 애니메이션: Speed 700&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블렌드 스페이스의 Speed 변수를 설정하기 위해 캐릭터 AnimInstance 클래스에 Speed 값 추가가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723706805583&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPROPERTY(BlueprintReadOnly)
float CharacterSpeed;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723706829130&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void USurvivorCharacterAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeUpdateAnimation(DeltaSeconds);

	if (IsValid(Character) == false)
	{
		auto Pawn = TryGetPawnOwner();
		Character = Cast&amp;lt;ASurvivorCharacter&amp;gt;(Pawn);
	}

	if (IsValid(Character))
	{
		CharacterSpeed = Character-&amp;gt;GetCharacterMovement()-&amp;gt;Velocity.Length();
		...
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 애님 그래프에서 블렌드 스페이스를 적용한 후 플레이하면, 결과는 다음과 같다. 이전보다 부드럽게 애니메이션이 전환되고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;898&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvZChp/btsI5B3tGNn/68ShIm28t7WU0APkKbWuZk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvZChp/btsI5B3tGNn/68ShIm28t7WU0APkKbWuZk/img.gif&quot; data-alt=&quot;블렌드 스페이스&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvZChp/btsI5B3tGNn/68ShIm28t7WU0APkKbWuZk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bvZChp/btsI5B3tGNn/68ShIm28t7WU0APkKbWuZk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;898&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;898&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;블렌드 스페이스&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 모션 워핑(Motion Warping)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기계 수리 등 특정 액터와 상호작용하는 애니메이션이 필요한 경우 다음과 같은 문제가 있었다. 물론 수리 애니메이션이 실행될 때 기계를 바라보도록 회전을 하는 등의 작업을 할 수도 있지만, 하나의 코드로 모든 상황에 적절한 회전을 하기 어렵다는 점과 더 자연스러운 애니메이션을 위해 모션 워핑을 사용하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;motion.gif&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUOOpB/btsIJx9n9YT/x1M9scmr60YfVp5Q9em5Kk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUOOpB/btsIJx9n9YT/x1M9scmr60YfVp5Q9em5Kk/img.gif&quot; data-alt=&quot;기계 수리 애니메이션&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUOOpB/btsIJx9n9YT/x1M9scmr60YfVp5Q9em5Kk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cUOOpB/btsIJx9n9YT/x1M9scmr60YfVp5Q9em5Kk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;736&quot; height=&quot;446&quot; data-filename=&quot;motion.gif&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;446&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기계 수리 애니메이션&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모션 워핑&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;캐릭터의 루트 모션이 타깃과 일치하도록 동적으로 정렬하는 기능&lt;/span&gt;이다. 캐릭터의 루트를 직접 이동시키는 방법이 아니며 루트 모션 애니메이션을 보간하여 캐릭터를 이동시키는 방식이다. 파쿠르나 암살 등의 다양한 곳에서 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모션 워핑을 사용하기 위해서는 플러그인 설정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2HNd3/btsI8frZ5aB/iD3ClUVCCH0OykLIpMQi3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2HNd3/btsI8frZ5aB/iD3ClUVCCH0OykLIpMQi3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2HNd3/btsI8frZ5aB/iD3ClUVCCH0OykLIpMQi3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2HNd3%2FbtsI8frZ5aB%2FiD3ClUVCCH0OykLIpMQi3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;92&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1723958592604&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PublicDependencyModuleNames.AddRange(
	new string[] {
		...
		&quot;MotionWarping&quot;
    }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모션 워핑을 사용할 몽타주에서 애니메이션과 모션 워핑을 추가하고 Warp Target Name을 설정한다. Warp Target Name을 통해 워프 타깃을 찾게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvy54/btsI8iPNBpa/hVR2SRt7kqsXq8Veim3wS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvy54/btsI8iPNBpa/hVR2SRt7kqsXq8Veim3wS1/img.png&quot; data-alt=&quot;애니메이션 몽타주 수정&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvy54/btsI8iPNBpa/hVR2SRt7kqsXq8Veim3wS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpvy54%2FbtsI8iPNBpa%2FhVR2SRt7kqsXq8Veim3wS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;800&quot; height=&quot;413&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;애니메이션 몽타주 수정&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 추가한 애니메이션들은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;루트 모션의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;EnableRootMotion를 활성화해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/edXpXv/btsI6ijQYup/Aq8FMBKJs7brKqnNleMAe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/edXpXv/btsI6ijQYup/Aq8FMBKJs7brKqnNleMAe0/img.png&quot; data-alt=&quot;애니메이션 EnableRootMotion 활성화&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/edXpXv/btsI6ijQYup/Aq8FMBKJs7brKqnNleMAe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FedXpXv%2FbtsI6ijQYup%2FAq8FMBKJs7brKqnNleMAe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;71&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;애니메이션 EnableRootMotion 활성화&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 캐릭터에 모션 워핑 컴포넌트를 추가하고, 몽타주가 재생되기 전에 타깃의 위치와 회전을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723959124789&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPROPERTY()
UMotionWarpingComponent* MotionWarpingComponent;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1723959141559&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ASurvivorCharacter::ASurvivorCharacter()
{
	...
	MotionWarpingComponent = CreateDefaultSubobject&amp;lt;UMotionWarpingComponent&amp;gt;(TEXT(&quot;MotionWarping&quot;));
}

MachineInstall()
{
	FMotionWarpingTarget Target = {};
	Target.Name = FName(&quot;Machine&quot;);
	Target.Location = GetActorLocation();
	Target.Rotation = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), InstallMachine-&amp;gt;GetActorLocation());
	
	MotionWarpingComponent-&amp;gt;AddOrUpdateWarpTarget(Target);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AddOrUpdateWarpTarget: 몽타주 에셋에서 정의된 워프 타깃 이름을 위치로 링크하는 데 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 플레이해 보면 결과는 다음과 같다. 설정 값을 수정하면 좀 더 정확하게 동작할 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwhNl7/btsI7lNfLfh/SoRL5EQizqHwb0XywNCz41/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwhNl7/btsI7lNfLfh/SoRL5EQizqHwb0XywNCz41/img.gif&quot; data-alt=&quot;모션 워핑&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwhNl7/btsI7lNfLfh/SoRL5EQizqHwb0XywNCz41/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cwhNl7/btsI7lNfLfh/SoRL5EQizqHwb0XywNCz41/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;506&quot; height=&quot;318&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;모션 워핑&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>  Game/✏ Unreal</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/316</guid>
      <comments>https://tech-interview.tistory.com/316#entry316comment</comments>
      <pubDate>Sun, 18 Aug 2024 16:03:56 +0900</pubDate>
    </item>
    <item>
      <title>[Unreal] 프로퍼티(리플렉션), 매크로, 가비지 컬렉션</title>
      <link>https://tech-interview.tistory.com/283</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 리플렉션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리플렉션(Reflection)&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;프로그램이 실행 시간에 자기 자신을 조사하는 기능&lt;/span&gt;이다. 여기서 자기 자신이란 클래스, 구조체, 함수, 멤버 변수, 열거형 등을 의미한다. 즉, 런타임에 객체의 타입을 보는 것을 포함해 구조와 행동까지 수정하는 것이 리플렉션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프로퍼티&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바나 C#에서는 리플렉션을 지원하지만, 언리얼 C++에서는 지원하지 않고 있다. 그래서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;언리얼 자체 시스템으로 리플렉션을 제공&lt;/span&gt;하고 있으며 그 시스템을 언리얼의 리플렉션인 &lt;b&gt;프로퍼티&lt;/b&gt;라 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼 내의&lt;span&gt;&amp;nbsp;&lt;/span&gt;여러 가지&lt;span&gt;&amp;nbsp;&lt;/span&gt;시스템들이 이 리플렉션 객체에 의존한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 리플리케이션&lt;/li&gt;
&lt;li&gt;블루프린트와 C++ 연동&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 매크로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스, 변수, 함수 등 상황에 맞게 &lt;b&gt;매크로&lt;/b&gt;를 달아두면, UHT(Unreal Header Tool)가 빌드 전처리 시 필요한 정보를 수집하여 프로퍼티 시스템에 등록하게 된다.&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;매크로를 잘 조작함으로서 C++와 블루프린트 연동을 잘할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;UENUM(), UCLASS(), USTURCT(), UFUNCTIONI(), UPROPERTY() 등&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1695887138588&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 리플렉션이 있는 타입은 이 헤더파일을 인클루드해서 UHT에 알린다.
#include &quot;MyObject.generated.h&quot;

// MyObject는 리플렉션 되는 클래스임을 나타낸다.
UCLASS()
class UMyObject : public UObject
{
    // 자동 생성된 코드가 여기에 삽입된다는 마커.
    GENERATED_BODY()
    
    // MyFunc는 리플렉션 되는 멤버 함수임을 나타낸다.
    UFUNCTION()
    void MyFunc(int, double) {}
    
    // MyData는 리플렉션 되는 멤버 변수임을 나타낸다.
    UPROPERTY()
    int32 MyData;
    
    // 리플렉션이 되지 않는 것을 섞어도 된다.
    // 하지만 리플렉션 시스템에 보이지 않으므로 주의해야한다.
    uint8 MyNum;
    // 예를 들면 리플렉션 되지 않는 UObject 포인터를 저장하는 것은 
    // 가비지 컬렉터가 레퍼런스를 확인할 수 없기 때문에 위험하다.
    UObject* MyObjectRef;
}

// MyEnum은 리플렉션 되는 열거형임을 나타낸다.
UENUM()
enum class EMyEnum
{
    ....
};

// MyStruct는 리플렉션 되는 구조체임을 나타낸다.
USTRUCT()
struct FMyStruct
{
    GENERATED_BODY()
    
    UPROPERTY()
    int32 MyData;
    
    // 구조체의 멤버함수는 UFUNCTION으로 지정할 수 없다!
    // UFUNCTION()
    void MyFunc(double) {}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1) UPROPERTY()&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;변수에 붙는 매크로&lt;/span&gt;이며 인자 값을 넣어서 용도에 맞게 활용할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719729220143&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
float AttackRange;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1) 변수 공개와 수정 권한&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VisibleDefaultsOnly: 블루프린트 에디터 창의 디테일 패널에서 값 보기 가능&lt;/li&gt;
&lt;li&gt;VisibleInstanceOnly: 월드 상에 배치된 오브젝트의 디테일 패널에서 값 보기 가능&lt;/li&gt;
&lt;li&gt;VisibleAnywhere: 둘 다 보기 가능&amp;nbsp;&lt;/li&gt;
&lt;li&gt;EditDefulatOnly: 블루프린트 에디터 창의 디테일 패널에서 값 수정 가능&lt;/li&gt;
&lt;li&gt;EditInstanceOnly: 월드 상에 배치된 오브젝트의 디테일 패널에서 값 수정 가능&lt;/li&gt;
&lt;li&gt;EditAnywhere: 둘 다 수정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2) 블루프린트 공개와 수정 권한&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BlueprintReadOnly: 블루프린트에서 읽기 가능&lt;/li&gt;
&lt;li&gt;BlueprintReadWrite: 블루프린트에서 읽기와 쓰기 가능&lt;/li&gt;
&lt;li&gt;BlueprintGetter: 해당 함수를 통해 블루프린트에서 접근 가능&lt;/li&gt;
&lt;li&gt;BlueprintSetter: 해당 함수를 통해 블루프린트에서 수정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2) UFUNCTION()&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;함수에 붙는 매크로&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1719729220144&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;// header 파일
UFUNCTION(BlueprintCallable, Category = &quot;value&quot;)
void Function();

// cpp 파일
void AMyActor::Function()
{
	// 동작
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BlueprintCallable: 블루프린트 내에서 사용 가능&lt;/li&gt;
&lt;li&gt;BlueprintPure: 블루프린트 내에서 값 하나 반환하는 형태에 사용&lt;/li&gt;
&lt;li&gt;BlueprintImplementableEvent, BlueprintNativeEvent&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3) UEnum()&lt;/h3&gt;
&lt;pre id=&quot;code_1719729220144&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;UENUM(BlueprintType)
enum class ETestEnum : uint8
{
    TE_OptionA UMETA(DisplayName = &quot;Option A&quot;),
    TE_OptionB UMETA(DisplayName = &quot;Option B&quot;),
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BlueprintType: 구조체가 블루프린트에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4) USTRUCT()&lt;/h3&gt;
&lt;pre id=&quot;code_1719729220145&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;USTRUCT(Atomic, BlueprintType)
struct FCustomStruct
{
    GENERATED_BODY()
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    AActor* actor;
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    int32 i;
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Atomic: 구조체가 항상 하나의 단위로 직렬화(Serialize) 됨&lt;/li&gt;
&lt;li&gt;BlueprintType: 구조체가 블루프린트에서 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 가비지 컬렉션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가비지 컬렉션&lt;/b&gt;은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;더 이상 필요하지 않은 객체를 가비지 컬렉터가 메모리에서 할당 해제해 주는 방법&lt;/span&gt;이다. 프로그램의 규모가 커질수록 아래와 같은 상황들을 신경 쓰기가 어렵기 때문에 등장한 개념이라고 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 누수: 더 이상 사용되지 않는 객체인데 delete를 하지 않음&lt;/li&gt;
&lt;li&gt;Dangling pointer:&amp;nbsp;아직 사용 중인 객체인데 delete 해버림&lt;/li&gt;
&lt;li&gt;undefined behaviour: 할당되지 않은 영역에 대해 delete 해버림&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언리얼에서는 참조 그래프를 만들어 어느 오브젝트가 사용 중이고 어느 것이 사용 중이지 않은지 확인한다. 루트에는 Root set이 있으며 UObject가 아래에 추가된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tw1fX/btsv5l7Kw5D/w6TGs5XxAk6sOdk64VPMyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tw1fX/btsv5l7Kw5D/w6TGs5XxAk6sOdk64VPMyK/img.png&quot; data-alt=&quot;참조 그래프&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tw1fX/btsv5l7Kw5D/w6TGs5XxAk6sOdk64VPMyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftw1fX%2Fbtsv5l7Kw5D%2Fw6TGs5XxAk6sOdk64VPMyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;311&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;참조 그래프&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가비지 컬렉션이 발생하면 Root set부터 시작해서 트리를 검색한다. 여기서 찾지 못한 오브젝트는 참조되지 않은 오브젝트이므로 해제하고 제거한다. 이러한 방식은 Mark &amp;amp; Sweep 방식이라 부르며 Root set부터 Mark 되고 Mark 되지 않은 오브젝트들은 Sweep 된다고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Root set부터 아래 UObject를 따라 내려가기 위해서는 프로퍼티가 필요하다. &lt;u&gt;프로퍼티가 객체 내의 UObject 포인터 위치를 가비지 컬렉터에게 알려주기 때문&lt;/u&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://upbo.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://upbo.tistory.com/79&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1695886633778&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Unreal Engine] 리플렉션(프로퍼티)과 가비지 컬렉션&quot; data-og-description=&quot;리플렉션 위키피디아에서는 다음과 같이 설명하고 있다. Reflection is the ability of a process to examine, introspect, and modify its own structure and behavior. 런타임에 객체의 타입을 보는 Type Introspection을 포함해 &quot; data-og-host=&quot;upbo.tistory.com&quot; data-og-source-url=&quot;https://upbo.tistory.com/79&quot; data-og-url=&quot;https://upbo.tistory.com/79&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ZzEbo/hyT2yH6ZqQ/QmXanUI6BkxswuS3TCPKrK/img.png?width=563&amp;amp;height=374&amp;amp;face=0_0_563_374,https://scrap.kakaocdn.net/dn/VCgYo/hyT2xoS3aH/DtkPp8WvAUoXSK5oaKNJzk/img.png?width=563&amp;amp;height=374&amp;amp;face=0_0_563_374,https://scrap.kakaocdn.net/dn/Colej/hyT2BY6XTc/ANB4s6EJbzRfqwRKGG5RWK/img.png?width=657&amp;amp;height=340&amp;amp;face=0_0_657_340&quot;&gt;&lt;a href=&quot;https://upbo.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://upbo.tistory.com/79&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ZzEbo/hyT2yH6ZqQ/QmXanUI6BkxswuS3TCPKrK/img.png?width=563&amp;amp;height=374&amp;amp;face=0_0_563_374,https://scrap.kakaocdn.net/dn/VCgYo/hyT2xoS3aH/DtkPp8WvAUoXSK5oaKNJzk/img.png?width=563&amp;amp;height=374&amp;amp;face=0_0_563_374,https://scrap.kakaocdn.net/dn/Colej/hyT2BY6XTc/ANB4s6EJbzRfqwRKGG5RWK/img.png?width=657&amp;amp;height=340&amp;amp;face=0_0_657_340');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Unreal Engine] 리플렉션(프로퍼티)과 가비지 컬렉션&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;리플렉션 위키피디아에서는 다음과 같이 설명하고 있다. Reflection is the ability of a process to examine, introspect, and modify its own structure and behavior. 런타임에 객체의 타입을 보는 Type Introspection을 포함해&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;upbo.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1695886675881&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;언리얼 프로퍼티 시스템 (리플렉션)&quot; data-og-description=&quot;리플렉션(Reflection)은 프로그램이 실행시간에 자기 자신을 조사하는 기능입니다. 이는 엄청나게 유용한 데다 언리얼 엔진 테크놀로지의 근간을 이루는 것으로, 에디터의 디테일 패널, 시리얼라&quot; data-og-host=&quot;www.unrealengine.com&quot; data-og-source-url=&quot;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&quot; data-og-url=&quot;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cfbApz/hyT2uZ1DML/WkD5bE7Tes13u33Zmd9sV1/img.jpg?width=770&amp;amp;height=250&amp;amp;face=0_0_770_250,https://scrap.kakaocdn.net/dn/bEAxbk/hyT2qXCub1/uk9IpQbKa5pns5DHkda0Wk/img.jpg?width=770&amp;amp;height=250&amp;amp;face=0_0_770_250&quot;&gt;&lt;a href=&quot;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.unrealengine.com/ko/blog/unreal-property-system-reflection&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cfbApz/hyT2uZ1DML/WkD5bE7Tes13u33Zmd9sV1/img.jpg?width=770&amp;amp;height=250&amp;amp;face=0_0_770_250,https://scrap.kakaocdn.net/dn/bEAxbk/hyT2qXCub1/uk9IpQbKa5pns5DHkda0Wk/img.jpg?width=770&amp;amp;height=250&amp;amp;face=0_0_770_250');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;언리얼 프로퍼티 시스템 (리플렉션)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;리플렉션(Reflection)은 프로그램이 실행시간에 자기 자신을 조사하는 기능입니다. 이는 엄청나게 유용한 데다 언리얼 엔진 테크놀로지의 근간을 이루는 것으로, 에디터의 디테일 패널, 시리얼라&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.unrealengine.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyo-ue4study.tistory.com/182&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hyo-ue4study.tistory.com/182&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1695887953051&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[언리얼엔진] 리플렉션 (aka. 프로퍼티 시스템)&quot; data-og-description=&quot;언리얼엔진하면은 다룬다고 하면 알아야할 몇가지들이 있다. 그 중에서 언리얼엔진에서 베이스가 되는 프로퍼티 시스템인 리플렉션 이 있다. 리플렉션이라는 것은 자바나 C#등에선 지원하지만,&quot; data-og-host=&quot;hyo-ue4study.tistory.com&quot; data-og-source-url=&quot;https://hyo-ue4study.tistory.com/182&quot; data-og-url=&quot;https://hyo-ue4study.tistory.com/182&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cglbQn/hyT2r3iRIx/ucImWGPN2arReuJFONU8Kk/img.png?width=498&amp;amp;height=160&amp;amp;face=0_0_498_160,https://scrap.kakaocdn.net/dn/bodF9b/hyT2u6MRRx/mcMVT9jkGQ08MCHL22FWK0/img.png?width=498&amp;amp;height=160&amp;amp;face=0_0_498_160,https://scrap.kakaocdn.net/dn/cJMb3O/hyT2yVEit1/BzacFVBgBbmxxMtjiduyBk/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000&quot;&gt;&lt;a href=&quot;https://hyo-ue4study.tistory.com/182&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hyo-ue4study.tistory.com/182&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cglbQn/hyT2r3iRIx/ucImWGPN2arReuJFONU8Kk/img.png?width=498&amp;amp;height=160&amp;amp;face=0_0_498_160,https://scrap.kakaocdn.net/dn/bodF9b/hyT2u6MRRx/mcMVT9jkGQ08MCHL22FWK0/img.png?width=498&amp;amp;height=160&amp;amp;face=0_0_498_160,https://scrap.kakaocdn.net/dn/cJMb3O/hyT2yVEit1/BzacFVBgBbmxxMtjiduyBk/img.jpg?width=2000&amp;amp;height=2000&amp;amp;face=0_0_2000_2000');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[언리얼엔진] 리플렉션 (aka. 프로퍼티 시스템)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;언리얼엔진하면은 다룬다고 하면 알아야할 몇가지들이 있다. 그 중에서 언리얼엔진에서 베이스가 되는 프로퍼티 시스템인 리플렉션 이 있다. 리플렉션이라는 것은 자바나 C#등에선 지원하지만,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hyo-ue4study.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>  Game/✏ Unreal</category>
      <author>Blxxming</author>
      <guid isPermaLink="true">https://tech-interview.tistory.com/283</guid>
      <comments>https://tech-interview.tistory.com/283#entry283comment</comments>
      <pubDate>Sun, 30 Jun 2024 15:39:25 +0900</pubDate>
    </item>
  </channel>
</rss>