<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>나의 발자취</title>
    <link>https://wildguess.tistory.com/</link>
    <description>Good artists copy. Great artists steal.
But I don't steal. 
I do Cmd + C.</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 17:51:04 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>달모드</managingEditor>
    <image>
      <title>나의 발자취</title>
      <url>https://tistory1.daumcdn.net/tistory/3484286/attach/4231ce5e64d94b839023b0fdc6a072d2</url>
      <link>https://wildguess.tistory.com</link>
    </image>
    <item>
      <title>브라우저 작동 원리에 따른 앱 성능 최적화 (Web Browser Engineering)</title>
      <link>https://wildguess.tistory.com/553</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;일단 기본적으로 브라우저 작동 원리를 생각해보면,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;일단 브라우저는 HTML 문서를 받으면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;파싱&lt;/b&gt;&lt;/span&gt; 처리를 진행한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;파서는 받은 문서를 읽어서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;DOM(Document Object Model) 트리&lt;/b&gt;&lt;/span&gt;를 생성한다. (DOM은 문서의 &lt;b&gt;구조&lt;/b&gt;를 나타낸다.) 이 때 CSS를 처리해 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;CSSOM&lt;/b&gt;&lt;/span&gt;(CSS Object Model)을 만든다.&lt;/li&gt;
&lt;li&gt;브라우저는 이 DOM 트리를 사용해 콘텐츠를 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;렌더링&lt;/b&gt;&lt;/span&gt;한다. (렌더링의 두 가지 주요 단계는 layout, paint이다.)&lt;/li&gt;
&lt;li&gt;렌더링 1) &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;레이아웃&lt;/b&gt;&lt;/span&gt;: 브라우저는 CSS에 정의된 스타일과 레이아웃 규칙을 기반으로 각 요소의 크기와 위치를 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;계산&lt;/b&gt;&lt;/span&gt;한다.&lt;/li&gt;
&lt;li&gt;렌더링 2) &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;페인트&lt;/b&gt;&lt;/span&gt;: 브라우저가 각 요소를 화면에 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;그린다&lt;/span&gt;.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;gt; 페이지의 요소 수를 최소화하거나, CSS grid를 사용하거나, Flexbox를 사용해서 레이아웃을 단순화시키는 것이 성능을 개선하는 방법이 된다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자, 이제까지는 &lt;u&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;렌더링&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;에 관한 성능 개선 방법이었는데 이번에는 '&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;로딩&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;'에 초점을 맞춰서 생각해보면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 위의 순서로 돌아가서, 브라우저가 HTML 문서를 받게 되는 1번 순서를 보자. 여기서, HTML문서를 받는다는 것은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;문서에 참조된 리소스도 로딩한다&lt;/b&gt;&lt;/span&gt;는 것이다. 여기서 로딩할 게 많으면( 이미지, 스타일시트, 스크립트 등의 리소스) 여기가 병목이 된다. =&amp;gt; lazy loading, &amp;nbsp;prefetching, preloading 같은 resource hint를 사용. &lt;span style=&quot;color: #009a87;&quot;&gt;Chrome DevTools Performance tab - summary&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;Chrome 개발 블로그를 참고하면 매우 많은 도움이 된다.&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;/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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.chrome.com/blog/inside-browser-part1&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.chrome.com/blog/inside-browser-part1&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1772537406380&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;최신 웹브라우저 들여다보기 (1부) &amp;nbsp;|&amp;nbsp; Blog &amp;nbsp;|&amp;nbsp; Chrome for Developers&quot; data-og-description=&quot;브라우저가 코드를 개략적인 아키텍처에서 구체적인 렌더링 파이프라인에 이르기까지 제대로 작동하는 웹사이트로 변환하는 방법을 알아보세요.&quot; data-og-host=&quot;developer.chrome.com&quot; data-og-source-url=&quot;https://developer.chrome.com/blog/inside-browser-part1&quot; data-og-url=&quot;https://developer.chrome.com/blog/inside-browser-part1?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Oah9e/dJMb81GUO5k/OA3KSdLoWUW48SpfSm7uG1/img.png?width=856&amp;amp;height=546&amp;amp;face=0_0_856_546,https://scrap.kakaocdn.net/dn/WP7BJ/dJMb8Wexe7P/3knqE7CKeAVfPSDCAJ3tVK/img.png?width=856&amp;amp;height=491&amp;amp;face=0_0_856_491,https://scrap.kakaocdn.net/dn/hD606/dJMb86nU9em/apXUFGkM1LZHM7GLVC6b30/img.png?width=856&amp;amp;height=491&amp;amp;face=0_0_856_491&quot;&gt;&lt;a href=&quot;https://developer.chrome.com/blog/inside-browser-part1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.chrome.com/blog/inside-browser-part1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Oah9e/dJMb81GUO5k/OA3KSdLoWUW48SpfSm7uG1/img.png?width=856&amp;amp;height=546&amp;amp;face=0_0_856_546,https://scrap.kakaocdn.net/dn/WP7BJ/dJMb8Wexe7P/3knqE7CKeAVfPSDCAJ3tVK/img.png?width=856&amp;amp;height=491&amp;amp;face=0_0_856_491,https://scrap.kakaocdn.net/dn/hD606/dJMb86nU9em/apXUFGkM1LZHM7GLVC6b30/img.png?width=856&amp;amp;height=491&amp;amp;face=0_0_856_491');&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;최신 웹브라우저 들여다보기 (1부) &amp;nbsp;|&amp;nbsp; Blog &amp;nbsp;|&amp;nbsp; Chrome for Developers&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;developer.chrome.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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://web.dev/articles/critical-rendering-path/constructing-the-object-model&quot;&gt;https://web.dev/articles/critical-rendering-path/constructing-the-object-model&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1772537412017&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;객체 모델 구성 &amp;nbsp;|&amp;nbsp; Articles &amp;nbsp;|&amp;nbsp; web.dev&quot; data-og-description=&quot;브라우저가 DOM 및 CSSOM 트리를 구성하는 방법을 알아봅니다.&quot; data-og-host=&quot;web.dev&quot; data-og-source-url=&quot;https://web.dev/articles/critical-rendering-path/constructing-the-object-model&quot; data-og-url=&quot;https://web.dev/articles/critical-rendering-path/constructing-the-object-model?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bRjd3X/dJMb8RRPvAx/iy2KvKr2UmgHwa64Wh40M0/img.png?width=1123&amp;amp;height=622&amp;amp;face=0_0_1123_622,https://scrap.kakaocdn.net/dn/jEV4B/dJMb83Sgrqq/XYDweQ1TpSXFHyskUycH70/img.png?width=582&amp;amp;height=299&amp;amp;face=0_0_582_299,https://scrap.kakaocdn.net/dn/b5rhs3/dJMb8SXvnZZ/jV5nKU2mxvjTmFxz66iJ2K/img.png?width=582&amp;amp;height=299&amp;amp;face=0_0_582_299&quot;&gt;&lt;a href=&quot;https://web.dev/articles/critical-rendering-path/constructing-the-object-model&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://web.dev/articles/critical-rendering-path/constructing-the-object-model&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bRjd3X/dJMb8RRPvAx/iy2KvKr2UmgHwa64Wh40M0/img.png?width=1123&amp;amp;height=622&amp;amp;face=0_0_1123_622,https://scrap.kakaocdn.net/dn/jEV4B/dJMb83Sgrqq/XYDweQ1TpSXFHyskUycH70/img.png?width=582&amp;amp;height=299&amp;amp;face=0_0_582_299,https://scrap.kakaocdn.net/dn/b5rhs3/dJMb8SXvnZZ/jV5nKU2mxvjTmFxz66iJ2K/img.png?width=582&amp;amp;height=299&amp;amp;face=0_0_582_299');&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;객체 모델 구성 &amp;nbsp;|&amp;nbsp; Articles &amp;nbsp;|&amp;nbsp; web.dev&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;브라우저가 DOM 및 CSSOM 트리를 구성하는 방법을 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;web.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;/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;/p&gt;</description>
      <category>Frontend</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/553</guid>
      <comments>https://wildguess.tistory.com/553#entry553comment</comments>
      <pubDate>Tue, 3 Mar 2026 20:43:18 +0900</pubDate>
    </item>
    <item>
      <title>React App 확장성을 위해 점검해 볼것</title>
      <link>https://wildguess.tistory.com/552</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;GA4 필요한 어트리뷰션, 메트릭만 가지고 오기 위해 GraphQL 적용할 수 있는지? (REST API 대신)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GA4 데이터 받을 때, streaming방식 (덩어리 혹은 조각으로)으로 받을 수 있는지?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GA4에서 flushing을 응용해서 사용할 수 있는지 (전체 응답이 생성되기 전에 데이터를 브라우저에게 보낼 수 있는 능력)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chrome lighthouse에서 참고해볼 것들이 있는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lazy(), Suspense()를 사용해서 로딩시간을 최적화할 수 있는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;on-demand code splitting을 적용할 부분이 있는지 -- (Intersection Observer API 사용해서)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Code Splitting -- critical path를 먼저 식별하고!! entry point / vendor / dynamic splitting 중에 어떤것이 제일 적합할지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BE - 거대한 인라인 스크립트를 피해야한다 (스크립트 크기가 1KB가 넘으면 인라인으로 작성하지 말것)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BE - 긴 태스크를 피해야하는데 메인 스레드를 점유하고 있는지 (작은 작업으로 분할했다고 하더라도!)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 식별 (3rd party) -- Chrorme DevTools/Lighthouse/WebPageTest 같은 도구로 가장 느리게 로딩되는 서드파티 의존성을 식별, 로딩 최적화(lazy loading, code splitting, tree shaking(은 보통 번들러와 빌드 도구들이 많이 사용하곤 함))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번들 분석 - Webpack Bundle Analyzer, Lighthouse Treemap 등 번들 분석하고 가장 많은 공간을 차지하는 의존성을 식별&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3rd party 의존성 configuration을 최적화&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 패턴(SPA, MPA, server-side, static, partial hydration, progressive hydration, islands architecture, incremental static generation, streaming SSR, resumability, edge rendering 등) 맞는것 찾기&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;/p&gt;</description>
      <category>코드 아키텍처, 모델링</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/552</guid>
      <comments>https://wildguess.tistory.com/552#entry552comment</comments>
      <pubDate>Tue, 3 Mar 2026 20:17:53 +0900</pubDate>
    </item>
    <item>
      <title>Food Delivery Service (WooWa Bros) system architecture</title>
      <link>https://wildguess.tistory.com/551</link>
      <description>&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;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;These sources detail the sophisticated technical strategies employed by Woowa Brothers to maintain the stability and performance of the Baedal Minjok ecosystem (ref: &lt;a href=&quot;https://techblog.woowahan.com/2667/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://techblog.woowahan.com/2667/&lt;/a&gt;). The documentation highlights the &quot;Shop Exposure System,&quot; which utilizes Spring WebFlux, Redis, and DynamoDB to manage massive traffic through reactive programming and asynchronous non-blocking I/O. Another key focus is the &quot;Ad Listing System,&quot; where Kotlin DSLs and Coroutines are used to simplify complex query logic and improve developer productivity. To ensure system resilience, the engineering teams implement circuit breakers, vendor redundancy, and fault isolation to prevent external service outages from degrading the user experience. By conducting regular dependency audits and adopting a CQRS pattern, the company manages the inherent risks of a large-scale microservices architecture. Ultimately, these texts illustrate a continuous commitment to infrastructure optimization and proactive monitoring to handle the volatile demands of real-time delivery services.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;Preface:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;This is a reflection from a study group I participate in biweekly, in person.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;In Week 1 (Session 1), we examined the live shopping event on Toss &amp;mdash; a Korean fintech app that leverages open banking (My Data) and also offers stock trading, an expense tracker, and various credit card promotions. I had done this session on paper and hadn't transferred my notes to a computer, so afterward I redrew the architecture digitally to get AI feedback and continue the discussion.&lt;/i&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #141413; text-align: start;&quot;&gt;This session was centered around designing a high-traffic store listing system &amp;mdash; loosely modeled after real-world platforms like Baedal Minjok. As the moderator, I guided the group through &lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;1) Functional Requirements&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2) Non-Functional Requirements&lt;/b&gt;&lt;/span&gt;, and &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;3) System Architecture.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;1) Functional Requirements&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;were split into frontend and backend:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Frontend&lt;/i&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Store list&lt;/li&gt;
&lt;li&gt;DSL store info (thumbnails, etc.)&lt;/li&gt;
&lt;li&gt;Delivery zone detection and delivery fee filtering logic&lt;/li&gt;
&lt;li&gt;Ad banners (curation)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;Backend&lt;/i&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Policy service&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;2) Non-Functional Requirements&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;were broken into three areas: Performance, Availability, and Scalability.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Performance &amp;mdash; Scale Estimation&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DAU: 10 million&lt;/li&gt;
&lt;li&gt;QPU: 579&lt;/li&gt;
&lt;li&gt;Peak QPS: 100,000&lt;/li&gt;
&lt;li&gt;Registered stores: 1 million&lt;/li&gt;
&lt;li&gt;Response time: ~200ms&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Availability:&lt;span&gt;&amp;nbsp;&lt;/span&gt;99.999%&lt;span&gt;&amp;nbsp;&lt;/span&gt;Scalability target:&lt;span&gt;&amp;nbsp;&lt;/span&gt;30 million DAU&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The most interesting part was designing the&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 3) &lt;/b&gt;&lt;b&gt;System Architecture&lt;/b&gt;&lt;/span&gt;. The key discussion questions we wrestled with were:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Which DB type should we use as the primary DB &amp;mdash; synchronous or asynchronous?&lt;/li&gt;
&lt;li&gt;What replication architecture should we apply to the RDB?&lt;/li&gt;
&lt;li&gt;If we go with Load Balancer &amp;rarr; Cache &amp;rarr; Server &amp;rarr; RDB, and then separate reads via CQRS, should Elasticsearch be treated as an independent search layer or appended to the read DB?&lt;span&gt;&amp;nbsp;&lt;/span&gt;(This question surfaced the fact that most of us had only used ES for search functionality, not as a primary data store.)&lt;/li&gt;
&lt;li&gt;Should we split the RDB into Master/Slave, or is there a better alternative?&lt;/li&gt;
&lt;li&gt;How does the cost of filtering in RDB compare to Elasticsearch, and why?&lt;/li&gt;
&lt;li&gt;When choosing between Elasticsearch and DynamoDB as the primary DB, what are the tradeoffs?&lt;/li&gt;
&lt;li&gt;What are the tradeoffs of using Elasticsearch as the primary DB rather than an RDB?&lt;/li&gt;
&lt;li&gt;Instead of using store ID as the PK, what if we used geospatial data (like a QuadTree, similar to Google Maps) as the cache key &amp;mdash; wouldn't that improve accuracy? And rather than putting everything in a single cache, what if we split it into four layers: top-ranked locations, detailed filtering, personalization, and real-time state changes?&lt;/li&gt;
&lt;li&gt;If ES is used for caching and synced periodically with the RDB, what is the data retention span in ES? TTL? But it doesn't make sense to delete data after a fixed interval &amp;mdash; searches would break.&lt;/li&gt;
&lt;li&gt;If we split caching into popular areas (LFU), detailed filtering, personalization, and real-time state changes &amp;mdash; how many cache instances do we need, and what does that structure look like?&lt;/li&gt;
&lt;li&gt;If we set the PK to lat/lng coordinates by region &amp;mdash; users within the same zone should see the same results, and this approach seems more semantically correct.&lt;/li&gt;
&lt;li&gt;How exactly does distributed processing work using Elasticsearch nodes and shards?&lt;/li&gt;
&lt;li&gt;Where should the cache sit, and what spec should it use?&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;This architecture diagram is the final output of our discussion.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBq1bD/dJMcaiI3HAJ/bIDiiI4kwy859AyM2kB9c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBq1bD/dJMcaiI3HAJ/bIDiiI4kwy859AyM2kB9c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBq1bD/dJMcaiI3HAJ/bIDiiI4kwy859AyM2kB9c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBq1bD%2FdJMcaiI3HAJ%2FbIDiiI4kwy859AyM2kB9c0%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;2024&quot; height=&quot;1464&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1464&quot;/&gt;&lt;/span&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;After the session, I asked a generative AI to identify and correct any missing or incorrect parts of the architecture.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;High Performance Architecture Design.png&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1350&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bl00P/dJMcaaRRb0t/1k0417k9jPaPDBeLbK8DF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bl00P/dJMcaaRRb0t/1k0417k9jPaPDBeLbK8DF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bl00P/dJMcaaRRb0t/1k0417k9jPaPDBeLbK8DF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBl00P%2FdJMcaaRRb0t%2F1k0417k9jPaPDBeLbK8DF0%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;1400&quot; height=&quot;1350&quot; data-filename=&quot;High Performance Architecture Design.png&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1350&quot;/&gt;&lt;/span&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;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1 style=&quot;color: #141413; text-align: start;&quot;&gt;Self-Reflection: CQRS + CDC Architecture Study Session&lt;/h1&gt;
&lt;h2 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;What I Think Went Well&lt;/h2&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The decision to adopt&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CQRS with a CDC pipeline&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;was the right call. At a peak QPS of 100,000, a single RDB handling both reads and writes would inevitably become the bottleneck. Separating the write path (server &amp;rarr; Relational DB) from the read path (Worker &amp;rarr; Redis / Elasticsearch &amp;rarr; Local Cache) is a pattern that production systems at this scale actually use, and I'm glad the group landed on it organically rather than being told the answer.&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The idea of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;splitting the cache into four distinct buckets&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; Popular Areas (LFU-based), Detailed Filtering, Personalization, and Real-time State Changes &amp;mdash; also felt like a meaningful insight. Rather than dumping everything into one cache layer and hoping for the best, this approach respects the fact that different data has different access patterns, different TTL requirements, and different tolerance for staleness. Separating Real-time State Changes into its own Pub/Sub-driven bucket in particular shows an understanding that open/close status updates cannot be treated the same way as relatively stable store metadata.&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Choosing&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Debezium &amp;rarr; Kafka &amp;rarr; Worker&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;as the synchronization backbone was also well-reasoned. Polling the database for changes is fragile and expensive. CDC via binlog capture is how this problem is actually solved at scale, and the group arrived at this without it being handed to them.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Where I Was Wrong or Shallow&lt;/h2&gt;
&lt;h3 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. The Numbers Lack a Derivation&lt;/h3&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;We stated DAU of 10 million, peak QPS of 100,000, and QPU of 579 &amp;mdash; but I cannot clearly explain where QPU 579 came from. In any serious design review or technical interview, the derivation matters more than the number itself. The expected reasoning looks something like:&lt;/p&gt;
&lt;div style=&quot;background-color: #000000; color: #141413; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;10,000,000 DAU
&amp;times; avg. requests per session (e.g., 5)
/ 86,400 seconds
&amp;asymp; ~578 avg QPS

Peak QPS = avg QPS &amp;times; spike multiplier (e.g., &amp;times;150 during lunch rush)
&amp;asymp; 86,700 &amp;rarr; rounded to 100,000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Without walking through this explicitly, the numbers are just decoration. I need to be able to justify every figure I put on a design document.&lt;/p&gt;
&lt;h3 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. I Was Confused About What Elasticsearch Actually Is&lt;/h3&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The question &quot;what if we use ES as the primary DB?&quot; came up in our session, and I didn't shut it down cleanly enough. The answer is: you can't, and you shouldn't. Elasticsearch does not support ACID transactions. It doesn't guarantee durability the way a relational database does. A partial update internally triggers a delete and reindex. It is a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;search index built on top of a document store&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; it is a derived view of your data, not the source of truth.&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The correct mental model is: the Relational DB owns the truth, and ES reflects it. Elasticsearch answers questions like &quot;which stores match this filter set sorted by distance?&quot; It does not replace the system that answers &quot;what is the canonical state of store #4821?&quot;&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Going forward, I need to be precise about this distinction every time ES comes up in a discussion.&lt;/p&gt;
&lt;h3 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. The QuadTree / Geospatial PK Idea Was Undercooked&lt;/h3&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The suggestion to use geospatial data &amp;mdash; specifically QuadTree-based region classification &amp;mdash; as a cache key had the right instinct behind it: users in the same geographic zone should see the same results, so keying the cache by region rather than by individual user makes sense. However, the way I phrased it (&quot;use lat/lng as the PK&quot;) is technically incorrect and would be a red flag in a design review.&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Raw latitude/longitude coordinates are floating-point numbers. They're noisy. Two users standing ten meters apart will generate different coordinates, and floating-point precision differences mean you cannot reliably use them as cache keys. The correct approach is to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;discretize the space first&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; hash the coordinates into a fixed-size cell using a scheme like&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Geohash&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Google S2&lt;/b&gt;, or&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Uber's H3&lt;/b&gt;. Then that cell ID becomes the cache key.&lt;/p&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The distinction is: QuadTree is a data structure for spatial indexing and range queries. Geohash / H3 is a way to assign a stable string identifier to a geographic region. They solve adjacent but different problems. I was conflating the two, and I need to be clearer about which tool does what.&lt;/p&gt;
&lt;h3 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. The Worker's Sequential Update Logic Has a Gap&lt;/h3&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;We defined the update order as: ① Redis 1st &amp;rarr; ② Redis 2nd &amp;rarr; ③ Elasticsearch. But I never addressed the failure case:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;what happens if Redis update succeeds but ES indexing fails?&lt;/b&gt;In a distributed system, partial failures are not edge cases &amp;mdash; they are normal operating conditions. At minimum, the design needs a retry mechanism: failed ES updates should be sent to a dead-letter queue or retry topic so they can be replayed without data loss. Without this, the system silently drifts into inconsistency and there's no way to detect it.&lt;/p&gt;
&lt;h3 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;5. 99.999% Availability Was Written Without Infrastructure to Back It Up&lt;/h3&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Five nines means&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;5 minutes and 15 seconds of downtime per year&lt;/b&gt;. I wrote this number on the diagram without specifying what it actually requires: multi-AZ deployment, active-active configuration, automated failover under 30 seconds, and careful handling of network partitions. None of that was reflected in the architecture. If I'm going to claim 99.999%, the diagram needs to show how the system survives the loss of an availability zone. Otherwise it's a wish, not a design target.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;What I'm Taking Away&lt;/h2&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The most valuable part of this session wasn't the final diagram &amp;mdash; it was the questions the group asked that I couldn't fully answer in the moment. Those gaps are the actual learning agenda:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #141413; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I need to internalize how to derive capacity numbers from first principles, not just state them.&lt;/li&gt;
&lt;li&gt;I need a much cleaner mental model of ES: what it's good at, what it can't do, and where it fits in the data flow.&lt;/li&gt;
&lt;li&gt;I need to understand spatial indexing properly &amp;mdash; Geohash, S2, H3 &amp;mdash; before I use geospatial data in any future design.&lt;/li&gt;
&lt;li&gt;I need to design for failure, not just for the happy path. Every asynchronous update step needs a defined behavior on failure.&lt;/li&gt;
&lt;li&gt;I need to treat availability targets as engineering commitments, not aspirational numbers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;The architecture we drew is directionally correct. The CQRS pattern, the CDC pipeline, the layered cache strategy &amp;mdash; these are real solutions to real problems. But a correct direction with unexamined gaps is only halfway to a real design. The next session should revisit the failure modes, the capacity math, and the geospatial keying strategy with more rigor.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #141413; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Resources I'm Going to Read&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #141413; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Designing Data-Intensive Applications&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; Martin Kleppmann. Covers CQRS, CDC, replication, and consistency models in depth. Most of the questions raised in this session are answered in this book. (need to buy this)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Elasticsearch: The Definitive Guide&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;a href=&quot;https://www.elastic.co/docs/get-started&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.elastic.co/docs/get-started&lt;/a&gt;). Will clear up my confusion about what ES is and isn't.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Uber Engineering Blog &amp;mdash; H3: Hexagonal Hierarchical Spatial Index&lt;/b&gt;. The practical reference for geospatial discretization.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Martin Fowler &amp;mdash; CQRS&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(martinfowler.com/bliki/CQRS.html). Short, authoritative, worth reading before the next session &lt;a href=&quot;https://martinfowler.com/bliki/CQRS.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://martinfowler.com/bliki/CQRS.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Confluent Blog &amp;mdash; Change Data Capture with Debezium&lt;/b&gt;. Will deepen my understanding of the CDC layer we designed.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Woowa Brothers Tech Blog&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(techblog.woowahan.com) &amp;mdash; specifically the Store Exposure System series, again. Reading it after having designed our own version will make the differences much more instructive.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;System Design Interview Vol. 2&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;mdash; Alex Xu. The cache design chapters map directly onto what we discussed. (I have this book)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>시스템 디자인</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/551</guid>
      <comments>https://wildguess.tistory.com/551#entry551comment</comments>
      <pubDate>Sat, 21 Feb 2026 01:50:03 +0900</pubDate>
    </item>
    <item>
      <title>Azure 환경변수 가져오는 법</title>
      <link>https://wildguess.tistory.com/550</link>
      <description>&lt;pre id=&quot;code_1771472164678&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;az webapp config appsettings list --name [App Name] --resource-group [RG name] --output table&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Backend</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/550</guid>
      <comments>https://wildguess.tistory.com/550#entry550comment</comments>
      <pubDate>Thu, 19 Feb 2026 12:36:07 +0900</pubDate>
    </item>
    <item>
      <title>Azure Docker 배포 시 Web App Crash issue RCA</title>
      <link>https://wildguess.tistory.com/549</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;FE/BE 따로 배포하다가 하나의 앱으로 합치고 FE앱에 .env 를 설정하는 구조로 변경함.&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;일단 앱은 이와 같은 구조로 되어있다. NginX reverse proxy로 포트 호스팅을 해주니 정상적으로 배포를 하는듯 보였음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;1224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4JCEm/btsO3BYrReq/qg4TgZk4I6ohQjNk9ab260/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4JCEm/btsO3BYrReq/qg4TgZk4I6ohQjNk9ab260/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4JCEm/btsO3BYrReq/qg4TgZk4I6ohQjNk9ab260/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4JCEm%2FbtsO3BYrReq%2Fqg4TgZk4I6ohQjNk9ab260%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;1934&quot; height=&quot;1224&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;1224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2962&quot; data-origin-height=&quot;1316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sotcO/btsO3BRC8VX/1CCwHEPPousyqkzhAwwCRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sotcO/btsO3BRC8VX/1CCwHEPPousyqkzhAwwCRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sotcO/btsO3BRC8VX/1CCwHEPPousyqkzhAwwCRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsotcO%2FbtsO3BRC8VX%2F1CCwHEPPousyqkzhAwwCRk%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;2962&quot; height=&quot;1316&quot; data-origin-width=&quot;2962&quot; data-origin-height=&quot;1316&quot;/&gt;&lt;/span&gt;&lt;/figure&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;1440&quot; data-origin-height=&quot;1664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pcfzO/btsO4P8914Q/8ZDG3hvURnl3HMOGYQivc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pcfzO/btsO4P8914Q/8ZDG3hvURnl3HMOGYQivc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pcfzO/btsO4P8914Q/8ZDG3hvURnl3HMOGYQivc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpcfzO%2FbtsO4P8914Q%2F8ZDG3hvURnl3HMOGYQivc0%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;1440&quot; height=&quot;1664&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o6ucG/btsO2C4KAuI/MK60jGpeiL0WuYYfxjpTK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o6ucG/btsO2C4KAuI/MK60jGpeiL0WuYYfxjpTK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o6ucG/btsO2C4KAuI/MK60jGpeiL0WuYYfxjpTK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo6ucG%2FbtsO2C4KAuI%2FMK60jGpeiL0WuYYfxjpTK1%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;503&quot; height=&quot;281&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2888&quot; data-origin-height=&quot;1258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMBRbC/btsO3cdPOzc/6BWZJwgoqgysHrdLc6qAA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMBRbC/btsO3cdPOzc/6BWZJwgoqgysHrdLc6qAA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMBRbC/btsO3cdPOzc/6BWZJwgoqgysHrdLc6qAA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMBRbC%2FbtsO3cdPOzc%2F6BWZJwgoqgysHrdLc6qAA1%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;2888&quot; height=&quot;1258&quot; data-origin-width=&quot;2888&quot; data-origin-height=&quot;1258&quot;/&gt;&lt;/span&gt;&lt;/figure&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;1298&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m6Xgm/btsO29OPrdo/oGKUphC2vKQCInC6KMv070/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m6Xgm/btsO29OPrdo/oGKUphC2vKQCInC6KMv070/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m6Xgm/btsO29OPrdo/oGKUphC2vKQCInC6KMv070/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm6Xgm%2FbtsO29OPrdo%2FoGKUphC2vKQCInC6KMv070%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;1298&quot; height=&quot;408&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&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;Issue 4: Frontend image fails to load with its proper layouts&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;This issue occurred because I selected the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;amd64&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;architecture on deployment, which is compatible with Azure but not with Mac M3 (arm64). As a result, the app initially worked perfectly only on Chrome. However, when I checked again a couple of days later, it started working on Safari as well.&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;그리고, 배포 후 새로운 subroute를 추가했을 경우 배포 전 체크할 부분&lt;/b&gt;&lt;br /&gt;1) .env에 새로운 route 추가했는지 (react route)와 해당 스크립트에서 이 변수를 사용하게끔(하드코딩 no) - 안그럼 axios error 남&lt;br /&gt;2) 애져 환경 변수에 해당 변수 등록&lt;br /&gt;3) FE app build 다시&lt;br /&gt;4) 그 후 도커 이미지 만들고 다시 배포&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;Issue 5: &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Resolving nginx Default Page Instead of React App Issue&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;Problem&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;nginx welcome page shown instead of React app&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;Static resources (images, CSS, JS) not loading&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;404 errors in browser console&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Root Cause Analysis:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;nginx Cannot Find React Build Files&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;3&quot;&gt;&lt;span&gt;Build files missing or incorrectly placed in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;/usr/share/nginx/html&lt;/b&gt;&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;3&quot;&gt;&lt;span&gt;Issues with build file copying process in Dockerfile&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;Incorrect nginx Configuration for React App&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;3&quot;&gt;&lt;span&gt;Missing MIME type configurations for static files&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;3&quot;&gt;&lt;span&gt;No SPA (Single Page Application) routing handling&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리하자면, &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #252526; color: #d4d4d4; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;MIME 타입이 제대로 설정되지 않아 정적 파일들이 올바른 Content-Type으로 제공되지 않음&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;정적 파일 경로와 디렉토리 구조가 맞지 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Solution:&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;static 파일들의 경로와 MIME 타입 설정을 보완&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1386&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuqTm6/btsO4KmJvTQ/iobwPXldCHtMZNLEFeodrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuqTm6/btsO4KmJvTQ/iobwPXldCHtMZNLEFeodrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuqTm6/btsO4KmJvTQ/iobwPXldCHtMZNLEFeodrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuqTm6%2FbtsO4KmJvTQ%2FiobwPXldCHtMZNLEFeodrk%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;631&quot; height=&quot;672&quot; data-origin-width=&quot;1386&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1. Dockerfile Modification&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드된 react앱이 nginx 서빙 디렉토리에 제대로 복사되지 않음(멀티스테이지 빌드에서 빌드 결과물 복사 방식이 부적절. nginx 서빙 디렉토리 구조가 없거나 잘못됐을 가능성)&lt;/p&gt;
&lt;pre id=&quot;code_1751601982294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Create nginx serving directory
RUN mkdir -p /usr/share/nginx/html

# Copy build files to correct location
WORKDIR /usr/share/nginx/html
COPY --from=frontend-build /app/frontend/build/ .&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. &lt;span style=&quot;text-align: left;&quot;&gt;nginx.conf Modifications&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751602010314&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  # MIME 타입 명시적 정의 추가
  types {
      application/javascript  js;
      text/css               css;
      image/png              png;
      image/jpeg             jpg jpeg;
      image/svg+xml          svg;
      font/ttf               ttf;
      font/woff             woff;
      font/woff2            woff2;
  }

  # 정적 파일 위치별 설정 추가
  location /static/ {
      alias /usr/share/nginx/html/static/;
      expires 1y;
      add_header Cache-Control &quot;public, immutable&quot;;
  }

  location /fonts/ {
      alias /usr/share/nginx/html/fonts/;
      expires 1y;
      add_header Cache-Control &quot;public, immutable&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;&lt;b&gt;&lt;span&gt;&lt;span&gt;Key Learnings:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;Careful attention needed for file copy paths in Docker multi-stage builds&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;Understanding essential nginx configurations for serving SPAs&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;Importance of proper MIME type and path configurations for static files&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;nginx 설정 관련 문제&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;문제: 기본 nginx 페이지만 표시되고 React 앱이 로드되지 않음&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;원인:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;MIME 타입이 제대로 설정되지 않아 정적 파일들이 올바른 Content-Type으로 제공되지 않음&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;정적 파일 경로와 디렉토리 구조가 맞지 않음&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;해결: nginx&lt;/span&gt;
&lt;div id=&quot;22b58891-9cd2-43d2-9619-bbf1f3c23bbb&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #252526;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;plaintext&quot; data-keybinding-context=&quot;10859&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://zaoaxiuuym&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-mprt=&quot;8&quot; aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;#&amp;nbsp;MIME&amp;nbsp;타입&amp;nbsp;명시적&amp;nbsp;정의&amp;nbsp;추가&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;types&amp;nbsp;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;application/javascript&amp;nbsp;&amp;nbsp;js;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;text/css&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;&amp;nbsp;&amp;nbsp;css;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;image/png&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;&amp;nbsp;png;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;image/jpeg&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;jpg&amp;nbsp;jpeg;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;image/svg+xml&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;svg;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font/ttf&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;&amp;nbsp;&amp;nbsp;ttf;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font/woff&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;woff;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;font/woff2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;woff2;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;#&amp;nbsp;정적&amp;nbsp;파일&amp;nbsp;위치별&amp;nbsp;설정&amp;nbsp;추가&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;location&amp;nbsp;/static/&amp;nbsp;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alias&amp;nbsp;/usr/share/nginx/html/static/;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;expires&amp;nbsp;1y;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add_header&amp;nbsp;Cache-Control&amp;nbsp;&quot;public,&amp;nbsp;immutable&quot;&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;location&amp;nbsp;/fonts/&amp;nbsp;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;alias&amp;nbsp;/usr/share/nginx/html/fonts/;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;expires&amp;nbsp;1y;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;add_header&amp;nbsp;Cache-Control&amp;nbsp;&quot;public,&amp;nbsp;immutable&quot;&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-mprt=&quot;9&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;2. Dockerfile 구조 문제&lt;/span&gt;&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;문제: 빌드된 React 앱이 nginx 서빙 디렉토리에 제대로 복사되지 않음&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;원인:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;멀티스테이지 빌드에서 빌드 결과물 복사 방식이 부적절&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;nginx 서빙 디렉토리 구조가 없거나 잘못됨&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;해결: dockerfile&lt;/span&gt;
&lt;div id=&quot;ee587037-d3c4-4706-ba65-b3fb8d2c3a9c&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #252526;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;dockerfile&quot; data-keybinding-context=&quot;10860&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://qwcvvlkwzr&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-mprt=&quot;8&quot; aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;#&amp;nbsp;nginx&amp;nbsp;디렉토리&amp;nbsp;생성&amp;nbsp;보장&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;mkdir&amp;nbsp;-p&amp;nbsp;/usr/share/nginx/html&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #6a9955;&quot;&gt;#&amp;nbsp;작업&amp;nbsp;디렉토리&amp;nbsp;변경으로&amp;nbsp;정확한&amp;nbsp;경로에&amp;nbsp;복사&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;/usr/share/nginx/html&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #569cd6;&quot;&gt;COPY&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;--from=frontend-build&amp;nbsp;/app/frontend/build/&amp;nbsp;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div aria-hidden=&quot;true&quot; data-mprt=&quot;9&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;3. 프록시 설정 불일치&lt;/span&gt;&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;문제: package.json의 프록시 설정(3001)과 실제 백엔드 포트(5001) 불일치&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;원인: 개발 환경과 프로덕션 환경의 포트 설정 차이&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;해결: package.json의 프록시 설정을 실제 백엔드 포트에 맞게 수정&lt;/span&gt;
&lt;div id=&quot;8f12fa4d-ada2-4c82-b0d7-435a5093e97a&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #252526;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;json&quot; data-keybinding-context=&quot;10861&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://ntrldazquz&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-mprt=&quot;8&quot; aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;proxy&quot;&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;http://localhost:5001&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;4. 정적 파일 경로 문제&lt;/span&gt;&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;문제: React 앱의 정적 파일(CSS, JS)을 찾지 못함&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;원인:&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;homepage 설정이 부적절&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;2&quot;&gt;&lt;span&gt;빌드된 파일의 경로가 nginx 설정과 불일치&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;해결: package.json의 homepage 설정 수정&lt;/span&gt;
&lt;div id=&quot;dcc03e53-b472-40f0-8191-55525e759aa6&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #252526;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;json&quot; data-keybinding-context=&quot;10862&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://jvycuexajm&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-mprt=&quot;8&quot; aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;homepage&quot;&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;5. Docker 이미지 아키텍처 문제&lt;/span&gt;&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;문제: 로컬(ARM64)과 Azure(AMD64) 환경의 아키텍처 차이&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;원인: M3 맥에서 빌드된 이미지가 Azure의 AMD64 환경과 호환되지 않음&lt;/span&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 style=&quot;list-style-type: disc;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;해결: 명시적으로 AMD64 플랫폼 지정&lt;/span&gt;
&lt;div id=&quot;541ad10a-846e-4c68-92d6-520b0713df46&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #252526;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-mode-id=&quot;shellscript&quot; data-keybinding-context=&quot;10863&quot;&gt;
&lt;div style=&quot;background-color: #000000; color: #000000;&quot; data-uri=&quot;composer-code-block-anysphere://wdtuoyzybd&quot;&gt;
&lt;div data-mprt=&quot;3&quot;&gt;
&lt;div data-mprt=&quot;6&quot;&gt;
&lt;div style=&quot;background-color: #000000;&quot;&gt;
&lt;div aria-hidden=&quot;true&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div data-mprt=&quot;8&quot; aria-hidden=&quot;true&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&amp;nbsp;docker&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;--platform&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;linux/amd64&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;-t&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;barotalent-allinone:latest&lt;/span&gt;&lt;span style=&quot;color: #d4d4d4;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ce9178;&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주요 교훈:&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;프론트엔드 빌드 결과물의 디렉토리 구조를 정확히 이해하고 nginx 설정에 반영해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;개발 환경과 프로덕션 환경의 차이(포트, 경로 등)를 주의 깊게 관리해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;컨테이너화 시 호스트와 타겟 환경의 아키텍처 차이를 고려해야 함&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: decimal;&quot; data-indent=&quot;0&quot;&gt;&lt;span&gt;nginx의 정적 파일 서빙 설정과 MIME 타입 설정이 중요함&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Backend</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/549</guid>
      <comments>https://wildguess.tistory.com/549#entry549comment</comments>
      <pubDate>Fri, 4 Jul 2025 12:48:36 +0900</pubDate>
    </item>
    <item>
      <title>맥 패러랠즈 이후 벽돌 이슈(검정화면) 해결방법</title>
      <link>https://wildguess.tistory.com/548</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Control + Option + Shift + 전원&lt;/b&gt; 누르면 전에 안보이던 circle loading이 뜨는데 이때 바로 잽싸게&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Option + Cmd + P + R&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안될 경우, &lt;b&gt;재부팅하고 Cmd + R&lt;/b&gt; 바로 잽싸게 누르면 애플 로고 나옴!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기 &amp;nbsp; &amp;nbsp; 적!&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;/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;&amp;nbsp;&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;lt;서사 시작&amp;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;윈도우랑 같이 이용하려고 패러랠즈를 깔았는데 열고 닫을 때 snooze 모드일 때 조금 버벅이길래 뭔가 낌새가 이상했다. 그치만 애써 무시했다.&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;생각하면서 부팅 자체가 안되니까 OS 레벨의 문제라고 생각이 들었다.&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;그러다가 이번에 다시 오기로 오랜만에 재부팅하려고 하면서 찾아보니까 나왔다.&amp;nbsp;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론... 와이파이 연결하고 나서 지구본이 돌아가는데 그 다음 화면으로 넘어가기까지 겁 - 나 오래 걸린다. 분명 0:19라고 써져있는데 19분이 지나도 진행바는 가운데에도 도달하지 못했다.&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;support.apple.com/mac/startup&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-2100F&lt;/b&gt;라고 떠서 바로 잽싸게 다른 맥으로 찾아봄&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8WkmL/btsNSvSchtl/NKszgujkIJlvj5PXA3HeCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8WkmL/btsNSvSchtl/NKszgujkIJlvj5PXA3HeCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8WkmL/btsNSvSchtl/NKszgujkIJlvj5PXA3HeCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8WkmL%2FbtsNSvSchtl%2FNKszgujkIJlvj5PXA3HeCk%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;1728&quot; height=&quot;1190&quot; data-origin-width=&quot;1728&quot; data-origin-height=&quot;1190&quot;/&gt;&lt;/span&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 화면이랑 정확함 그래서 여기서 찾아봄&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://support.apple.com/en-us/102675&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://support.apple.com/en-us/102675&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746978411755&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;If your Mac doesn't start up all the way - Apple Support&quot; data-og-description=&quot;What to do if your Mac gets stuck on a screen during startup.&quot; data-og-host=&quot;support.apple.com&quot; data-og-source-url=&quot;https://support.apple.com/en-us/102675&quot; data-og-url=&quot;https://support.apple.com/en-us/102675&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Jf2if/hyYRzJknNx/3KpOmx80qHhk68a1LwXWrk/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832,https://scrap.kakaocdn.net/dn/1yO9c/hyYTommDPh/2K0UGY0PxB2YHKO6YT2Rak/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832,https://scrap.kakaocdn.net/dn/GEVDO/hyYRpmpFaO/qoouyTE8hXoKbYWkMYzVnK/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832&quot;&gt;&lt;a href=&quot;https://support.apple.com/en-us/102675&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://support.apple.com/en-us/102675&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Jf2if/hyYRzJknNx/3KpOmx80qHhk68a1LwXWrk/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832,https://scrap.kakaocdn.net/dn/1yO9c/hyYTommDPh/2K0UGY0PxB2YHKO6YT2Rak/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832,https://scrap.kakaocdn.net/dn/GEVDO/hyYRpmpFaO/qoouyTE8hXoKbYWkMYzVnK/img.png?width=1280&amp;amp;height=832&amp;amp;face=0_0_1280_832');&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;If your Mac doesn't start up all the way - Apple Support&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;What to do if your Mac gets stuck on a screen during startup.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;support.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 위쪽 드롭다운에서 지금 내 맥북 스펙에 맞게 intel chip 으로 바꿈&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://support.apple.com/en-us/102518?choose-your-type-of-mac=intel-based-mac#internet&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://support.apple.com/en-us/102518?choose-your-type-of-mac=intel-based-mac#internet&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1746978458044&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;How to start up from macOS Recovery - Apple Support&quot; data-og-description=&quot;macOS Recovery is your computer&amp;rsquo;s built-in recovery system, with utilities to reinstall macOS, repair or erase your startup disk, restore from a Time Machine backup, and more.&quot; data-og-host=&quot;support.apple.com&quot; data-og-source-url=&quot;https://support.apple.com/en-us/102518?choose-your-type-of-mac=intel-based-mac#internet&quot; data-og-url=&quot;https://support.apple.com/en-us/102518&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NxD4T/hyYRj7yHns/MKNj0UpVc9bT5dA7hvsUl0/img.png?width=1632&amp;amp;height=1080&amp;amp;face=0_0_1632_1080,https://scrap.kakaocdn.net/dn/bR1nET/hyYRoVj1jX/Ekf23cfkm5wif7ZYevoqMk/img.png?width=1202&amp;amp;height=1106&amp;amp;face=99_105_215_230,https://scrap.kakaocdn.net/dn/beQMhv/hyYPmX1Ohv/BH1RtkIRtR2GYxU73nlan0/img.png?width=1202&amp;amp;height=1106&amp;amp;face=99_105_215_230&quot;&gt;&lt;a href=&quot;https://support.apple.com/en-us/102518?choose-your-type-of-mac=intel-based-mac#internet&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://support.apple.com/en-us/102518?choose-your-type-of-mac=intel-based-mac#internet&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NxD4T/hyYRj7yHns/MKNj0UpVc9bT5dA7hvsUl0/img.png?width=1632&amp;amp;height=1080&amp;amp;face=0_0_1632_1080,https://scrap.kakaocdn.net/dn/bR1nET/hyYRoVj1jX/Ekf23cfkm5wif7ZYevoqMk/img.png?width=1202&amp;amp;height=1106&amp;amp;face=99_105_215_230,https://scrap.kakaocdn.net/dn/beQMhv/hyYPmX1Ohv/BH1RtkIRtR2GYxU73nlan0/img.png?width=1202&amp;amp;height=1106&amp;amp;face=99_105_215_230');&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;How to start up from macOS Recovery - Apple Support&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;macOS Recovery is your computer&amp;rsquo;s built-in recovery system, with utilities to reinstall macOS, repair or erase your startup disk, restore from a Time Machine backup, and more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;support.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그랬더니 여기서 하란대로 함.&lt;b&gt; 부팅하고 바로 Cmd+R&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;1768&quot; data-origin-height=&quot;730&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dD2mvC/btsNR1j62GX/O9kLnpocQo7h9Uyz2hBjk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dD2mvC/btsNR1j62GX/O9kLnpocQo7h9Uyz2hBjk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dD2mvC/btsNR1j62GX/O9kLnpocQo7h9Uyz2hBjk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdD2mvC%2FbtsNR1j62GX%2FO9kLnpocQo7h9Uyz2hBjk0%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;1768&quot; height=&quot;730&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;730&quot;/&gt;&lt;/span&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;/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;/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;난 볼륨 그룹 조절에서 그냥 바로 볼륨 그룹 없애버림. 미련없이 ㅂㅇ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 macOS Sonoma 버전 새로 깔기 모드 선택해버림. (네트워크 연결이 되어있어야 서버로부터 새 OS 다운 가능)&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;</description>
      <category>Error Handling</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/548</guid>
      <comments>https://wildguess.tistory.com/548#entry548comment</comments>
      <pubDate>Mon, 12 May 2025 00:42:29 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트 Var, Let, Const</title>
      <link>https://wildguess.tistory.com/547</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원래 JS에서는 변수를 선언할 때 var만 사용할 수 있었다. 그런데 2015년부터 let과 const가 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면서 원래 사용되던 var를 이제는..변수를 사용할 때 사용하게 되면 다소 superfluous한 느낌이 되어서 이제 거의 JS를 사용할 땐 변수에는 let, 상수에서는 const를 사용하는 편이 되었다.&amp;nbsp;&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;966&quot; data-origin-height=&quot;1022&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DYIKU/btsMR2ibFbw/0WsA5tfN8jM5zgHngqsEb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DYIKU/btsMR2ibFbw/0WsA5tfN8jM5zgHngqsEb0/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DYIKU/btsMR2ibFbw/0WsA5tfN8jM5zgHngqsEb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDYIKU%2FbtsMR2ibFbw%2F0WsA5tfN8jM5zgHngqsEb0%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;966&quot; height=&quot;1022&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;1022&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&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;var는 스코프 밖에서도 되지만,&lt;u&gt;&lt;b&gt; let과 const의 경우는 그들이 선언된 스코프 내에서만 존재&lt;/b&gt;&lt;/u&gt;한다. 스코프란 함수도 될 수 있고, 루프도 될 수 있고, if 조건문도 될 수 있다. {}를 이용해서 열고 닫는 모든 것들이 scope가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 아래와 같이 루프 안에서만 j가 존재하기 때문에, 출력을 하려고 하면 오류가 나는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1514&quot; data-origin-height=&quot;1456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spEHw/btsMQdS89KG/9rIRTesQuaksenhbcIjLJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spEHw/btsMQdS89KG/9rIRTesQuaksenhbcIjLJ0/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spEHw/btsMQdS89KG/9rIRTesQuaksenhbcIjLJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspEHw%2FbtsMQdS89KG%2F9rIRTesQuaksenhbcIjLJ0%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;549&quot; height=&quot;528&quot; data-origin-width=&quot;1514&quot; data-origin-height=&quot;1456&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&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;만약에 내가 변수를 오버라이딩 하고 싶으면, let을 사용한다. 근데 만약에 내가 늘 똑같은 상수같은 변수를 사용해야하면, 이때는 const를 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(let의 사용이 swift와 반대라서 헷갈릴수도.! ㅎ Swift는 변하면 안되는 상수가 let, 아닌 경우가 var)&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 표로 정리하면 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YamjW/btsMR1cDAuo/eCNuREOduUeUyvFxvDwfp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YamjW/btsMR1cDAuo/eCNuREOduUeUyvFxvDwfp0/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YamjW/btsMR1cDAuo/eCNuREOduUeUyvFxvDwfp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYamjW%2FbtsMR1cDAuo%2FeCNuREOduUeUyvFxvDwfp0%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;1998&quot; height=&quot;548&quot; data-origin-width=&quot;1998&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend/JS</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/547</guid>
      <comments>https://wildguess.tistory.com/547#entry547comment</comments>
      <pubDate>Thu, 20 Mar 2025 18:09:21 +0900</pubDate>
    </item>
    <item>
      <title>React 프로젝트 시작(CRA)</title>
      <link>https://wildguess.tistory.com/546</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CRA&lt;/b&gt;는 &lt;b&gt;Create React App&lt;/b&gt;의 준말으로, 리엑트 코어팀 소속이자 리덕스를 만든 Dan Abranmov가 만든 리액트 스타터 팩이다.&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: #009a87;&quot;&gt;&lt;b&gt;yarn create react app projectname&lt;/b&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: #009a87;&quot;&gt;&lt;b&gt;npm install -g create-react-app&lt;/b&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: #009a87;&quot;&gt;&lt;b&gt;create-react-app projectname&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 하면 projectname으로 된 폴더가 만들어지면서 그 안에 리액트 프로젝트가 생성된다.&amp;nbsp;&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;예를 들어, yarn으로 프로젝트를 설치하면 이렇게.. 아래와 같이 뜨는데 &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;1500&quot; data-origin-height=&quot;1242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8tG0T/btsMP1Fvh2P/o1BPA4xkqDcWK2sdYvKDOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8tG0T/btsMP1Fvh2P/o1BPA4xkqDcWK2sdYvKDOk/img.png&quot; data-alt=&quot;pc:educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8tG0T/btsMP1Fvh2P/o1BPA4xkqDcWK2sdYvKDOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8tG0T%2FbtsMP1Fvh2P%2Fo1BPA4xkqDcWK2sdYvKDOk%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;660&quot; height=&quot;546&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc:educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;yarn start&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dev 서버를 시작하는 것이다. npm이면 npm start를 하면 됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;yarn build&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;public server에 배포를 할 수 있게끔 앱의 빌드 폴더를 만드는 것이다. 개발용 빌드(yarn start)와 비교했을 때, public server용 빌드는 성능적으로 최적화되어있다. 그렇기 때문에 yarn start보다 yarn build를 했을 때 더 시간이 오래 걸린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;yarn test&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 실행하는건데, CRA를 하면 Jest도 같이 설치가 된다. 다른 테스팅 프레임워크와 비교했을 때, &lt;b&gt;snapshot testing&lt;/b&gt; 기능도 들어있다. 이건 내가 만든 컴포넌트의 현재 state의 복사본을 생성한 후, 향후 테스트 state와 비교를 하는 기능이다.&amp;nbsp;&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;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;yarn eject&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱의 Yarn coverage를 마치는 역할을 한다. 모든 빌드 스크립트, dependencies, config file이 현재 프로젝트 경로에 복사가 된다.&amp;nbsp;&lt;/p&gt;</description>
      <category>Frontend</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/546</guid>
      <comments>https://wildguess.tistory.com/546#entry546comment</comments>
      <pubDate>Thu, 20 Mar 2025 17:40:29 +0900</pubDate>
    </item>
    <item>
      <title>React 사전준비: 필요 라이브러리 및 패키지</title>
      <link>https://wildguess.tistory.com/545</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Node.js &lt;/b&gt;and&lt;b&gt; npm&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nvm을 이용해서 설치를 권장한다.&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;/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;b&gt;Yarn&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node, npm도 훌륭한 패키지 매니저긴 하지만, 페이스북에서 만든 yarn은 리액트를 좀더 쉽게 이용할 수 있도록 더 간결한 커맨드와 더 나은 캐싱을 제공하여 더 좋은 성능을 보인다.&amp;nbsp;&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: #009a87;&quot;&gt;&lt;b&gt;npm install --global yarn&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;npm i -g yarn&lt;/b&gt;&lt;/span&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Babel&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리엑트 기반의 프로젝트를 만들 때 의존성(dependency)용으로만 사용된다(npm package임). 바벨은 이슈 없이 모던 브라우저의 기준에 맞지 않거나 표준화되지 않은 자바스크립트가 실행될 수 있도록 transpile 과정을 도와주는 역할이다. (transpiling: 소스 코드의 언어를, 기능적으로 완전히 똑같게 다른 언어로 바꾸는 과정을 말함. 여기선 JSX or ES2015+를 어느 브라우저에서든 유효하고 실행 가능한 자바스크립트로 변환하는 것을 뜻함.)&amp;nbsp;&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;바벨은 코어 모듈(@babel/core)로 이루어저있는데, 보통 플러그인들은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;프리셋들로&lt;span&gt;&amp;nbsp;그&lt;/span&gt;&lt;/span&gt;룹이 지어져있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Before Babel&amp;rsquo;s&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;version 7&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;was released, this organization did not exist, and hyphens separated the packages.&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;@babel/preset-react&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;was called&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;babel-preset-react&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;@babel/core&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;was named&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;babel-core&lt;/b&gt;&lt;span style=&quot;background-color: #f9fafb; color: #374151; text-align: start;&quot;&gt;, and so on.&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;b&gt;@babel/core&lt;/b&gt;가 아닌 &lt;b&gt;babel-core&lt;/b&gt;라고 써져있어도 당황스러워하지 말자.( 이 경우 바벨 6 버전 이하라는 것이다.) 그러나 개발자에 따라 바벨 7과 호환이 되는데도 &lt;b&gt;babel-&lt;/b&gt;을 사용하는 사람도 있다. 이때는 어떤 일때문에 그런지 readme를 확인하면 된다.&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;ul style=&quot;list-style-type: disc; color: #374151; text-align: start;&quot; data-id=&quot;0836105b01f6fb8ea67a8018858cb134&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@babel/preset-env&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@babel/preset-react&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@babel/plugin-proposal-object-rest-spread&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@babel/plugin-proposal-class-properties&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@babel/plugin-syntax-dynamic-import&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-id=&quot;4a9505fb073774f16e2b441304c77a94&quot; data-ke-size=&quot;size16&quot;&gt;만약 &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Flow&lt;/b&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;TypeScript&lt;/b&gt;와 같은 정적 타입을 작업할 때엔 &lt;b&gt;@babel/preset-flow&lt;/b&gt;&lt;span&gt; 혹은&amp;nbsp;&lt;/span&gt;&lt;b&gt;@babel/preset-typescript&lt;/b&gt;&lt;span&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;도 설치해야 한다(respectively)&lt;/span&gt;.&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-id=&quot;4a9505fb073774f16e2b441304c77a94&quot; 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: #009a87;&quot;&gt;&lt;b&gt;npm install --save dev [package]&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;yarn add --dev [package]&lt;/b&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;로 설치 (--dev 나 --save dev는 devDependency에만 추가한다는 것이라 production code에는 추가되지 않을 것을 뜻함)&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;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Webpack&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹팩은 리액트 생태계에서 제일 중심을 이루는 도구 중 하나다. 이게 없으면 리액트에서 효율적인 워크플로우는 불가능하다고 볼 수 있다. 웹팩은 모듈 번들러인데, Node.js같은 모듈 기반의 개발을 브라우저로 가져온 것이다. 이를 통해 앱 코드를 자체 파일에 깔끔하게 구조화하고, import 또는 require()를 통해 종속성을 사용할 수 있다. 이렇게 하면 종속성이 자체 모듈 범위에 로드되어서 모듈 내에서 사용할 수 있고, 결국 단일 자바스크립트 파일만 생성된다.&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;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;ESLint&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 코드 분석에 필요한 도구이다. 거의 de-facto 스탠다드로 쓰이는. 리액트 프로젝트에서 eslint-plugin-react&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;eslint-plugin-babel&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;, and&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;eslint-plugin-react-hooks&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;&lt;span&gt; 와 같은 것들을 볼 수 있다.&lt;/span&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;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;&lt;span&gt;Prettier&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;color: #374151;&quot;&gt;&lt;span style=&quot;caret-color: #374151; background-color: #ffffff;&quot;&gt;코드 포맷을 규칙적으로 교정해주는 툴 정도&lt;/span&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;&lt;b&gt;&lt;span style=&quot;color: #374151;&quot;&gt;&lt;span style=&quot;caret-color: #374151; background-color: #ffffff;&quot;&gt;브라우저 플러그인&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;color: #374151;&quot;&gt;&lt;span style=&quot;caret-color: #374151; background-color: #ffffff;&quot;&gt;크롬에 React Dev Tool, Redux Dev Tool이 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSs5Wm/btsMRmVPTKt/GHQP7urceNXcNIqQ2LDeYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSs5Wm/btsMRmVPTKt/GHQP7urceNXcNIqQ2LDeYK/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSs5Wm/btsMRmVPTKt/GHQP7urceNXcNIqQ2LDeYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSs5Wm%2FbtsMRmVPTKt%2FGHQP7urceNXcNIqQ2LDeYK%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;540&quot; height=&quot;268&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Frontend</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/545</guid>
      <comments>https://wildguess.tistory.com/545#entry545comment</comments>
      <pubDate>Thu, 20 Mar 2025 17:28:29 +0900</pubDate>
    </item>
    <item>
      <title>[Two Pointers] 19. Remove Nth Node From End of List</title>
      <link>https://wildguess.tistory.com/544</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 링크&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/remove-nth-node-from-end-of-list/description/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caJzgH/btsMhPSecHF/qTPTFFmVwgSIR32T1mCJn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caJzgH/btsMhPSecHF/qTPTFFmVwgSIR32T1mCJn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caJzgH/btsMhPSecHF/qTPTFFmVwgSIR32T1mCJn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaJzgH%2FbtsMhPSecHF%2FqTPTFFmVwgSIR32T1mCJn0%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;637&quot; height=&quot;620&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYx9RA/btsMjg2cW7E/YxQaj6F8giGljxrNDvvKtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYx9RA/btsMjg2cW7E/YxQaj6F8giGljxrNDvvKtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYx9RA/btsMjg2cW7E/YxQaj6F8giGljxrNDvvKtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYx9RA%2FbtsMjg2cW7E%2FYxQaj6F8giGljxrNDvvKtk%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;677&quot; height=&quot;204&quot; data-origin-width=&quot;1672&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&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;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/h3&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;tail으로부터 출발하면 투포인터 쓰지 않아도 되지 않나...생각했는데, 투포인터를 쓴대니까 right pointer로 삭제할 노드를 짚어내나? 라고 생각해서 접근했는데 이렇게는 도무지 투포인터 패턴으로 문제가 안풀리는거다.&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일단 left pointer의 역할은 연결리스트 특성상 노드를 삭제하고 나면 삭제된 노드 이전 노드랑 연결하는 역할일거라 생각해서, left pointer는 루프가 끝났을 때 무조건 그 곳으로 가있어야할 것 같았고.. (즉, Nth Node - 1에 위치하고 있어야함)&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그럼 left/right pointer 둘 중 어떤 걸로 삭제할 Nth Node를 짚어내나? 어떻게 하지..? 생각했는데 일단 right 포인터가 완전 tail으로 이동했다고 생각했을 때, left pointer와 right pointer가 주어진 n만큼 벌어져있으면 자연스럽게 left pointer는 삭제할 Nth Node에 위치할 것이라고 나왔다.&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The optimized two-pointer approach removes the&lt;span&gt; N&lt;/span&gt;th node from the end of a linked list in one traversal by maintaining a fixed gap between two pointers. Initially, both &lt;b&gt;left and right pointers start at the head&lt;/b&gt;, and the r&lt;b&gt;ight pointer is moved forward&lt;/b&gt; by&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;steps, creating &lt;u&gt;&lt;b&gt;a gap of&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;nodes&lt;/b&gt;&lt;/u&gt;. &lt;b&gt;This gap ensures&lt;/b&gt; that &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;when the right pointer reaches the end of the list, the left pointer is positioned just before the node to be removed&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;. Both pointers then move forward together, maintaining the gap, until the right pointer reaches the end. At this point, the target node is skipped by updating the left pointer&amp;rsquo;s next link. If the right pointer reaches the end during the initial&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;steps, it indicates the head node is the target, which is removed by returning the next node of the head.&lt;/p&gt;
&lt;p id=&quot;gTKhry8n5O5PhycdzuMbt&quot; style=&quot;color: #374151; text-align: start;&quot; data-id=&quot;f88d59dcfdd4d026a539e645d4fa08c8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #374151; text-align: start;&quot; data-id=&quot;f88d59dcfdd4d026a539e645d4fa08c8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol id=&quot;jLGoptHi6BD3TgWDfv4Md&quot; style=&quot;list-style-type: decimal; color: #374151; text-align: start;&quot; data-id=&quot;e253520aae00d0214f003c466e995685&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;XGBFkP0hJW2t46jfjXbsS&quot;&gt;&lt;b&gt;Initialize two pointers&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;left&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;right, both pointing to the &lt;b&gt;head&lt;/b&gt; of the linked list.&lt;/li&gt;
&lt;li id=&quot;dO1gx2225lyKQLrMpTxQ5&quot;&gt;Move the &lt;b&gt;right pointer&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;steps ahead&lt;/b&gt;. This creates &lt;u&gt;&lt;b&gt;a gap of&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;nodes&lt;/b&gt;&lt;/u&gt; between the&lt;span&gt;&amp;nbsp;&lt;/span&gt;left&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointers.&lt;/li&gt;
&lt;li id=&quot;MNlGCaYR1eCZHTUCt3Qtl&quot;&gt;If, after moving the&lt;span&gt;&amp;nbsp;&lt;/span&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointer&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;steps forward, it becomes &lt;b&gt;NULL&lt;/b&gt;, it means &lt;b&gt;the head node is the target for removal&lt;/b&gt;. In this case,&lt;b&gt; return&lt;span&gt;&amp;nbsp;&lt;/span&gt;head.next&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;as the new head of the linked list, effectively removing the original head node.&lt;/li&gt;
&lt;li id=&quot;wOSftUG6QkWt0DRniPBXL&quot;&gt;If the&lt;span&gt;&amp;nbsp;&lt;/span&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointer hasn&amp;rsquo;t reached the end after moving&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;steps, &lt;b&gt;move both the&lt;span&gt;&amp;nbsp;&lt;/span&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;left&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointers forward&lt;/b&gt; by one step at a time, maintaining the gap between them. This ensures that when the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;right&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointer reaches the end of the linked list, the&lt;span&gt;&amp;nbsp;&lt;/span&gt;left&lt;span&gt;&amp;nbsp;&lt;/span&gt;pointer will be positioned just before the node that needs to be removed&lt;/b&gt;&lt;/u&gt;.&lt;/li&gt;
&lt;li id=&quot;wM-Dzu3u_9BfSJDaAwq9m&quot;&gt;Once the right pointer reaches the end of the linked list, update&lt;span&gt;&amp;nbsp;&lt;/span&gt;left.next&lt;span&gt;&amp;nbsp;&lt;/span&gt;to&lt;span&gt;&amp;nbsp;&lt;/span&gt;left.next.next. This action skips over the target node, effectively removing it from the linked list.&lt;/li&gt;
&lt;li id=&quot;E87jL8Ndoa0-7QM2_CaOw&quot;&gt;Finally, return the original&lt;span&gt;&amp;nbsp;&lt;/span&gt;head, which now points to the updated linked list with the&lt;span&gt;&amp;nbsp;&lt;/span&gt;nth node removed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmtUGi/btsMjfhV6tI/tcftZ8HKOdwocBgffWEM71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmtUGi/btsMjfhV6tI/tcftZ8HKOdwocBgffWEM71/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmtUGi/btsMjfhV6tI/tcftZ8HKOdwocBgffWEM71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmtUGi%2FbtsMjfhV6tI%2FtcftZ8HKOdwocBgffWEM71%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;637&quot; height=&quot;257&quot; data-origin-width=&quot;1494&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;position: absolute;&quot; 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;1502&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wAkUe/btsMh6ffQOr/O1qCTFvoHNmpqouz98wbyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wAkUe/btsMh6ffQOr/O1qCTFvoHNmpqouz98wbyk/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wAkUe/btsMh6ffQOr/O1qCTFvoHNmpqouz98wbyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwAkUe%2FbtsMh6ffQOr%2FO1qCTFvoHNmpqouz98wbyk%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;638&quot; height=&quot;256&quot; data-origin-width=&quot;1502&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2u7QH/btsMiEoYO0E/uPJkqOjOwpTZG5c0ZtkZsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2u7QH/btsMiEoYO0E/uPJkqOjOwpTZG5c0ZtkZsk/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2u7QH/btsMiEoYO0E/uPJkqOjOwpTZG5c0ZtkZsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2u7QH%2FbtsMiEoYO0E%2FuPJkqOjOwpTZG5c0ZtkZsk%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;675&quot; height=&quot;291&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BOU2Z/btsMi5zLBnT/GoqyWp7L63FjzDGa1DrDNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BOU2Z/btsMi5zLBnT/GoqyWp7L63FjzDGa1DrDNk/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BOU2Z/btsMi5zLBnT/GoqyWp7L63FjzDGa1DrDNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBOU2Z%2FbtsMi5zLBnT%2FGoqyWp7L63FjzDGa1DrDNk%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;692&quot; height=&quot;308&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;662&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ncZ8c/btsMivyVl1G/nHteLW82vwuBEKQRt7mBNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ncZ8c/btsMivyVl1G/nHteLW82vwuBEKQRt7mBNK/img.png&quot; data-alt=&quot;pc: educative&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ncZ8c/btsMivyVl1G/nHteLW82vwuBEKQRt7mBNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FncZ8c%2FbtsMivyVl1G%2FnHteLW82vwuBEKQRt7mBNK%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;614&quot; height=&quot;275&quot; data-origin-width=&quot;1478&quot; data-origin-height=&quot;662&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;pc: educative&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;고민한 부분, &lt;b&gt;주의사항&lt;/b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H78Cr/btsMjgnBr2H/K5ZgZsRLS6FKxjJ9OgJyhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H78Cr/btsMjgnBr2H/K5ZgZsRLS6FKxjJ9OgJyhk/img.png&quot; style=&quot;width:51.543311677235735%&quot; data-origin-width=&quot;1598&quot; data-origin-height=&quot;694&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;52.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H78Cr/btsMjgnBr2H/K5ZgZsRLS6FKxjJ9OgJyhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH78Cr%2FbtsMjgnBr2H%2FK5ZgZsRLS6FKxjJ9OgJyhk%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;1598&quot; height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lFkQf/btsMgPyOwLQ/9YgDeEgGAib5CvTY6CBik1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lFkQf/btsMgPyOwLQ/9YgDeEgGAib5CvTY6CBik1/img.png&quot; style=&quot;width:47.29389762508985%&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;674&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lFkQf/btsMgPyOwLQ/9YgDeEgGAib5CvTY6CBik1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlFkQf%2FbtsMgPyOwLQ%2F9YgDeEgGAib5CvTY6CBik1%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;1424&quot; height=&quot;674&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;출처: eductive&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;example 4에서, 만약에 내가 삭제해야하는 Nth Node가 head인 경우의 테스트 케이스를 처리해주지 않아서 통과를 안하는거다!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;세운 알고리즘 대로라면, gap으로 벌린 n이 너무 커서 right pointer가 Null으로 넘어가는 경우(if not right)에는 head를 버리는 거니까 head 이후의 노드들을 반환하는 경우도 처리를 해주어야 했다.&amp;nbsp;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;if not right:&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;head.next&lt;/b&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;&lt;b&gt;코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1735737752664&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for a Linked List node
# class LinkedListNode:
#     def __init__(self, data, next=None):
#         self.data = data
#         self.next = next

from linked_list import LinkedList
from linked_list_node import LinkedListNode

def remove_nth_last_node(head, n):
    left = right = head 
    for i in range(n):
      right = right.next
      
    if not right: # n의 크기가 연결리스트 크기만큼 큰 바람에 right가 None으로 벗어나서, head node를 없애야 하는 경우 
      return head.next
      
    while right.next:
      left = left.next
      right = right.next
    
    left.next = left.next.next
      
    
    return head&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;풀고 나서 (접근법, 사용되는 알고리즘 개념)&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSQjS6/btsMgSbaEKC/Pe3h7sWtEYfqQZjSRV6hTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSQjS6/btsMgSbaEKC/Pe3h7sWtEYfqQZjSRV6hTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSQjS6/btsMgSbaEKC/Pe3h7sWtEYfqQZjSRV6hTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSQjS6%2FbtsMgSbaEKC%2FPe3h7sWtEYfqQZjSRV6hTk%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;736&quot; height=&quot;398&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>알고리즘</category>
      <author>달모드</author>
      <guid isPermaLink="true">https://wildguess.tistory.com/544</guid>
      <comments>https://wildguess.tistory.com/544#entry544comment</comments>
      <pubDate>Thu, 13 Feb 2025 21:44:01 +0900</pubDate>
    </item>
  </channel>
</rss>