<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Coding Note</title>
    <link>https://jun-coding.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 23 May 2026 14:17:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>KimMinJun</managingEditor>
    <item>
      <title>Next.js 16에서 useSearchParams() 사용 시 should be wrapped in a suspense boundary 에러가 발생한 이유와 해결 방법</title>
      <link>https://jun-coding.tistory.com/792</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 16(App Router)을 사용하는 프로젝트에서 `searchbar`컴포넌트를 구현하던 중,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL 쿼리 스트링을 읽기 위해 `useSearchParams()`훅을 사용했다.&lt;/p&gt;
&lt;pre id=&quot;code_1765817232984&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;use client&quot;;

import { useEffect, useState } from &quot;react&quot;;
import { useRouter, useSearchParams } from &quot;next/navigation&quot;;
import style from &quot;./serachbar.module.css&quot;;

export default function Searchbar() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const [search, setSearch] = useState(&quot;&quot;);

  const q = searchParams.get(&quot;q&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;에디터와 개발 모드(`npm run dev`)에서 에러는 없었지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로덕션 모드에서도 확인하기 위해 빌드(`npm run build`)를 수행하자 다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에러 증상&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;⨯ useSearchParams() should be wrapped in a suspense boundary at page &quot;/&quot;. &lt;br /&gt;Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발 서버에서는 에러가 발생하지 않음&lt;/li&gt;
&lt;li&gt;빌드 시에 위 문구가 뜨면서 빌드 실패
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;suspense boundary로 감싸야 한다는 에러가 출력됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;원인 분석 과정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. `useSearchParams()`에 대해 알아보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, `useSearchParams()`에 관한 오류이기 때문에 해당 훅에 대해 알아보는게 먼저라고 생각했다.&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://nextjs.org/docs/app/api-reference/functions/use-search-params&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/app/api-reference/functions/use-search-params&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765831477780&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;Functions: useSearchParams | Next.js&quot; data-og-description=&quot;API Reference for the useSearchParams hook.&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/app/api-reference/functions/use-search-params&quot; data-og-url=&quot;https://nextjs.org/docs/app/api-reference/functions/use-search-params&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BEgxL/hyZPMs1PRf/WomR3IAoLAkLK37SwDiSfk/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/ctpgpf/hyZPFgm0tl/Er7UYBT4gKrZZDkA4PqhLK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/api-reference/functions/use-search-params&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/app/api-reference/functions/use-search-params&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BEgxL/hyZPMs1PRf/WomR3IAoLAkLK37SwDiSfk/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/ctpgpf/hyZPFgm0tl/Er7UYBT4gKrZZDkA4PqhLK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628');&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;Functions: useSearchParams | Next.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;API Reference for the useSearchParams hook.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.org&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;조금 내리다보면, 'Static Rendering' 부분에 `&amp;lt;SearchBar /&amp;gt;` 컴포넌트를 구현한 예제가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 그 바로 밑에 보면 `&amp;lt;SearchBar /&amp;gt;` 컴포넌트를 사용하는 Page 컴포넌트가 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1765832813075&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Suspense } from 'react'
import SearchBar from './search-bar'
 
// This component passed as a fallback to the Suspense boundary
// will be rendered in place of the search bar in the initial HTML.
// When the value is available during React hydration the fallback
// will be replaced with the `&amp;lt;SearchBar&amp;gt;` component.
function SearchBarFallback() {
  return &amp;lt;&amp;gt;placeholder&amp;lt;/&amp;gt;
}
 
export default function Page() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;nav&amp;gt;
        &amp;lt;Suspense fallback={&amp;lt;SearchBarFallback /&amp;gt;}&amp;gt;
          &amp;lt;SearchBar /&amp;gt;
        &amp;lt;/Suspense&amp;gt;
      &amp;lt;/nav&amp;gt;
      &amp;lt;h1&amp;gt;Dashboard&amp;lt;/h1&amp;gt;
    &amp;lt;/&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면, `&amp;lt;SearchBar /&amp;gt;` 컴포넌트를 `&amp;lt;Suspense&amp;gt;`로 감싸서 구현한 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Suspense Boundary&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 문구를 해석해보면 다음과 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;`useSearchParams()`는 '/' 페이지에서 suspense boundary로 감싸져 있어야 한다.&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;위 예제로 suspense boundary를 어떻게 적용해야하는지 알았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, &lt;b&gt;suspense boundary란&lt;/b&gt; 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react.dev/reference/react/Suspense&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://react.dev/reference/react/Suspense&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765833063205&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;lt;Suspense&amp;gt; &amp;ndash; React&quot; data-og-description=&quot;The library for web and native user interfaces&quot; data-og-host=&quot;react.dev&quot; data-og-source-url=&quot;https://react.dev/reference/react/Suspense&quot; data-og-url=&quot;https://react.dev/reference/react/Suspense&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLtmMU/hyZPTlnvEA/sYZmF0FP9SXbBmNW2AFWT1/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/cQav0d/hyZPBFLEyJ/Qn4ArgrqWKJvp4ADelUg71/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567&quot;&gt;&lt;a href=&quot;https://react.dev/reference/react/Suspense&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://react.dev/reference/react/Suspense&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLtmMU/hyZPTlnvEA/sYZmF0FP9SXbBmNW2AFWT1/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567,https://scrap.kakaocdn.net/dn/cQav0d/hyZPBFLEyJ/Qn4ArgrqWKJvp4ADelUg71/img.png?width=1080&amp;amp;height=567&amp;amp;face=0_0_1080_567');&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;lt;Suspense&amp;gt; &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The library for web and native user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;react.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 제공하는 기능으로,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;자식 요소들이 모두 로딩이 끝날때까지 fallback을 보여주는 컴포넌트이다.&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;3. 왜 &amp;lt;Suspense&amp;gt;를 사용해야 할까?&lt;/h3&gt;
&lt;pre id=&quot;code_1765833215706&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const router = useRouter();
  const q = searchParams.get(&quot;q&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 중에 search params가 아직 준비되지 않으면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js는 렌더링을 멈추려 하지만 이를 감싸는 `&amp;lt;Suspense /&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;더 자세히 알아보기 위해서,&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://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765833529243&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;Missing Suspense boundary with useSearchParams&quot; data-og-description=&quot;Using App Router Features available in /app&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&quot; data-og-url=&quot;https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Missing Suspense boundary with useSearchParams&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Using App Router Features available in /app&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.org&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Reading search parameters through useSearchParams() without a Suspense boundary &lt;br /&gt;will opt the entire page into client-side rendering. &lt;br /&gt;This could cause your page to be blank until the client-side JavaScript has loaded.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해석해보면 다음과 같다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Suspense boundary 없이 useSearchParams()를 이용해서 search parameter를 읽는것은&lt;br /&gt;모든 페이지를 CSR 방식으로 렌더링하게 한다.&lt;br /&gt;이로 인해서 클라이언트에서 JavaScript가 로딩될때까지 페이지가 비어있을 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Next.js(App Router)의 기본 렌더링은 &quot;서버가 먼저 그려준다&quot;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App Router에서는 기본적으로 &lt;b&gt;서버 컴포넌트(RSC) 중심&lt;/b&gt;으로 렌더링된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;HTML이 서버에서 먼저 만들어져서 내려오고&lt;/b&gt;, 클라이언트 JS는 나중에 로딩된 후, 하이드레이션 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2) 그런데 `useSearchParams()`는 '클라이언트 훅'이고, 경우에 따라 렌더링을 멈출 수 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/messages/deopted-into-client-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://nextjs.org/docs/messages/deopted-into-client-rendering&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765872385142&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;Entire page deopted into client-side rendering&quot; data-og-description=&quot;Using App Router Features available in /app&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/messages/deopted-into-client-rendering&quot; data-og-url=&quot;https://nextjs.org/docs/messages/deopted-into-client-rendering&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/messages/deopted-into-client-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/messages/deopted-into-client-rendering&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Entire page deopted into client-side rendering&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Using App Router Features available in /app&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서에 따르면, Suspense boundary가 없으면&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;정적 라우팅의 경우에, `useSearchParams()`훅을 호출하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 가까운 Suspense boundary까지의 트리를 클라이언트 사이드에서 렌더링하게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Suspense가 없으면 대체 UI를 보여줄 방법이 없기 때문에,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태로 서버가 HTML을 만들다가 중단되면, 사용자에게 보낼 완성된 HTML이 애매해진다.&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;그래서 Next.js는 해당 페이지는 서버에서 미리 렌더링하지 말고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트에서 JS가 로드된 다음에 전부 렌더링, 즉 CSR이 되는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3) Suspense를 사용하면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 가까운 Suspense Boundary까지만 CSR로 만들기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 서버 SSR, 혹은 정적 렌더링을 유지할 수 있다.&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;'페이지 전체 CSR'을 막고, 동적인 부분만 격리하는 용도&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;`&amp;lt;Searchbar /&amp;gt;` 컴포넌트를 Suspense로 감싸서 렌더링한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1765874954292&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { ReactNode, Suspense } from 'react';
import Searchbar from '../../components/searchbar';

export default function Layout({ children }: { children: ReactNode }) {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Suspense&amp;gt;
        &amp;lt;Searchbar /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
      {children}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/792</guid>
      <comments>https://jun-coding.tistory.com/792#entry792comment</comments>
      <pubDate>Tue, 16 Dec 2025 17:50:51 +0900</pubDate>
    </item>
    <item>
      <title>[스위프 웹 11기 후기] - 팀 빌딩부터 네트워킹까지</title>
      <link>https://jun-coding.tistory.com/791</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스위프란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://swyp.im/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://swyp.im/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1765618031463&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;스위프 | IT 직군을 위한 취업&amp;middot;커리어 성장 플랫폼&quot; data-og-description=&quot;실전 프로젝트로 배우고 협업하며 성장하는 IT 커리어, 스위프에서 포트폴리오와 실무 역량을 완성하세요.&quot; data-og-host=&quot;swyp.im&quot; data-og-source-url=&quot;https://swyp.im/&quot; data-og-url=&quot;https://swyp.im/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cq8VAD/hyZPcUxesH/kbxiDpSlpGFVCEgzJ9ZXs1/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/dTlV37/hyZO8EAnHj/AKFOQxRcekQk9AaxVVpx2k/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/b0S2qv/hyZPHLSujL/RGPvt6KOKJ5cfPdYEyUsJ1/img.png?width=3840&amp;amp;height=2562&amp;amp;face=0_0_3840_2562&quot;&gt;&lt;a href=&quot;https://swyp.im/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://swyp.im/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cq8VAD/hyZPcUxesH/kbxiDpSlpGFVCEgzJ9ZXs1/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/dTlV37/hyZO8EAnHj/AKFOQxRcekQk9AaxVVpx2k/img.png?width=3600&amp;amp;height=1890&amp;amp;face=0_0_3600_1890,https://scrap.kakaocdn.net/dn/b0S2qv/hyZPHLSujL/RGPvt6KOKJ5cfPdYEyUsJ1/img.png?width=3840&amp;amp;height=2562&amp;amp;face=0_0_3840_2562');&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;스위프 | IT 직군을 위한 취업&amp;middot;커리어 성장 플랫폼&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;실전 프로젝트로 배우고 협업하며 성장하는 IT 커리어, 스위프에서 포트폴리오와 실무 역량을 완성하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;swyp.im&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스위프는 기획자(PM), 개발자, 디자이너 등&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;IT 직군이 실전형 팀 프로젝트를 경험하면서 취업과 커리어 성장을 준비할 수 있도록 돕는 플랫폼&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹/앱 프로젝트 &lt;u&gt;기수제&lt;/u&gt;로 운영되면서 지원자들을 팀으로 매칭해주는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나는 웹 11기 프론트엔드 직군으로 참여해서 프로젝트를 수행했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 6.43.51.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEKDxq/dJMcadtJ6JE/ZBiCOKTCPGgWFlZWuNkVBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEKDxq/dJMcadtJ6JE/ZBiCOKTCPGgWFlZWuNkVBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEKDxq/dJMcadtJ6JE/ZBiCOKTCPGgWFlZWuNkVBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEKDxq%2FdJMcadtJ6JE%2FZBiCOKTCPGgWFlZWuNkVBK%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;1374&quot; height=&quot;578&quot; data-filename=&quot;스크린샷 2025-12-13 오후 6.43.51.png&quot; data-origin-width=&quot;1374&quot; data-origin-height=&quot;578&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최종적으로 우리 팀은 PM 1명, 디자이너 1명, 프론트엔드 2명, 백엔드 3명으로 이루어졌다.&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;font-family: 'Nanum Gothic';&quot;&gt;뭐니뭐니해도 가장 좋았던 점은 &lt;b&gt;'다양한 직군과 협업할 수 있는 기회'&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;font-family: 'Nanum Gothic';&quot;&gt;항상 사이드 프로젝트 팀원을 구하거나 수행할때마다,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발자들끼리 모여서 누군가는 PM 역할을 수행하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;누군가는 디자이너 역할을 수행해야 했다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;하기싫은건 둘째치고, 아무래도 그 직군의 작업에 대한 전문성이 떨어졌었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, PM님과 디자이너님과 하니 개발에만 집중할 수 있었고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;퀄리티있는 산출물과 디자인으로 개발할 수 있어서 매우 좋았다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;팀 빌딩&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에는 팀 빌딩 기간이 주어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;무작위로 팀 빌딩이 이루어지는 것이 아니라,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;본인을 나타내는 프로필 카드를 작성하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 후에는 다른 사람의 직군, 선호 도메인, 기술 스택, 등...을 보면서 자유롭게 팀 빌딩을 하면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;아무래도 개발 직군에서는 백엔드 개발자가 많고, 프론트 개발자가 상대적으로 적다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, PM 인원도 굉장히 적기 때문에 PM 분이랑 꼭 같이 협업해보고 싶었는데...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;감사하게도 PM 님이 있는 팀에서 먼저 연락이 와서 같이할 수 있게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 6.53.38.png&quot; data-origin-width=&quot;1950&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciKnsv/dJMcaacKZYf/OtuRDJvNcw3xIbYbTD12IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciKnsv/dJMcaacKZYf/OtuRDJvNcw3xIbYbTD12IK/img.png&quot; data-alt=&quot;좋게 봐주셔서 감사합니다...!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciKnsv/dJMcaacKZYf/OtuRDJvNcw3xIbYbTD12IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciKnsv%2FdJMcaacKZYf%2FOtuRDJvNcw3xIbYbTD12IK%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;1950&quot; height=&quot;374&quot; data-filename=&quot;스크린샷 2025-12-13 오후 6.53.38.png&quot; data-origin-width=&quot;1950&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;좋게 봐주셔서 감사합니다...!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;Tip!&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;팀 빌딩은 굉장히 빠른 시간내에 거의 완성됩니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같이하고 싶은 분이 있다면, 적극적으로 빠르게 연락을 하시는것을 추천드려요!&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, PM과 디자이너 직군이 상대적으로 적기 때문에 빠르게 포섭을...&lt;/span&gt;&lt;/blockquote&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6주 간의 과정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;총 개발 기간은 6주 + 고도화 2주로 진행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;총 8주라고 생각할 수 있겠지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수료 기준은 6주 개발 후의 완성도를 보기 때문에 MVP는 6주안에 꼭 만들어야 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;그 외의 고정적인 일정은 매주 목요일 진행되는 &lt;b&gt;'리뷰데이'&lt;/b&gt;가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;각 팀이 한 주간 어떤것을 했는지,&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;어떤 것을 할건지 짧게 공유하는 스프린트 회고 시간&lt;/u&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;font-family: 'Nanum Gothic';&quot;&gt;이 '리뷰데이' 참석도 수료기준에 들어가있기 때문에 참석해야 한다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;귀찮을수도 있겠지만, 다른 팀들은 어떤것을 만들고 있는지 알아보는게 재밌었다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그 외에는, 팀 자체적으로 일정을 진행하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;뤼이도(Riido)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스위프에 참여하게 되면 2가지의 혜택이 주어지는데, 그 중 하나가 '뤼이도'이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;뤼이도는 &lt;b&gt;프로젝트 관리 툴&lt;/b&gt;으로, 흔히 많이 사용하는 Jira와 비슷한 툴이라고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그냥 사용권이 아닌 유료 플랜 사용권이 주어진다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이런 관리 툴을 사용하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;확실히 내가 하고있지 않은 작업 포함 프로젝트 전체의 진행을 트래킹하기 편해진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만,,, 본격적으로 개발 시작하고 나서는 github issue로 작업을 트래킹하다보니&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무래도 중후반엔 자주 사용하지 않게 되어 아쉬움이 있다...&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.02.33.png&quot; data-origin-width=&quot;3464&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ycs5E/dJMcahpqEM2/mnS9VyivuLG2lJf40PkKP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ycs5E/dJMcahpqEM2/mnS9VyivuLG2lJf40PkKP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ycs5E/dJMcahpqEM2/mnS9VyivuLG2lJf40PkKP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fycs5E%2FdJMcahpqEM2%2FmnS9VyivuLG2lJf40PkKP1%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;3464&quot; height=&quot;1482&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.02.33.png&quot; data-origin-width=&quot;3464&quot; data-origin-height=&quot;1482&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;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;네이버 클라우드 크레딧&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;배포를 하게되면 AWS나 기타 클라우드 서비스를 요즘 많이 이용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;그래서 당연히 비용처리에 대한 부분도 생각할 수 밖에 없는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;네이버 클라우드 크레딧을 최대 100만원까지 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;이러한 혜택 덕분에 서버 비용에 대한 걱정은 거의 하지 않아도 되서 좋았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #17171b; text-align: center; font-family: 'Nanum Gothic';&quot;&gt;두드림 - AI 팀 빌딩 서비스&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1687&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc5xTA/dJMcacPaZEk/dSRNqK1admwR7AmzY4hH0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc5xTA/dJMcacPaZEk/dSRNqK1admwR7AmzY4hH0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc5xTA/dJMcacPaZEk/dSRNqK1admwR7AmzY4hH0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc5xTA%2FdJMcacPaZEk%2FdSRNqK1admwR7AmzY4hH0K%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;3000&quot; height=&quot;1687&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;1687&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트는 AI를 활용해서 팀 빌딩을 쉽게 해주는 '두드림'이라는 서비스를 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트에 대한 자세한 정보는 다음 게시글에서 다룰것이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;완성하기까지의 과정에 대한것만 담아보려 한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;팀 그라운드룰&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.14.50.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ONocQ/dJMcadtJ7et/BGTTEzSN7mdwAkOvkqeHZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ONocQ/dJMcadtJ7et/BGTTEzSN7mdwAkOvkqeHZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ONocQ/dJMcadtJ7et/BGTTEzSN7mdwAkOvkqeHZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FONocQ%2FdJMcadtJ7et%2FBGTTEzSN7mdwAkOvkqeHZk%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;445&quot; height=&quot;529&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.14.50.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 자체적 팀 회의에서는 '팀 그라운드룰'을 정했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;팀 문화 규칙, 소통같은 부분은 어쩌면 당연하다고 생각될 수 있겠지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;확실히 문서화를 해놓으면 다같이 지키게 되므로 필수라고 생각한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아이디에이션&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아이디에이션 과정에서도 재밌는 아이디어들이 많았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;내 아이디어가 채택되지 못했지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같은 형식으로 각자의 아이디어를 간략하게 소개하는 노션 페이지를 만들어서 공유했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.18.11.png&quot; data-origin-width=&quot;1976&quot; data-origin-height=&quot;1542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjFSAw/dJMcafLT7RN/pk836U4K1fmKC7AE6fUcT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjFSAw/dJMcafLT7RN/pk836U4K1fmKC7AE6fUcT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjFSAw/dJMcafLT7RN/pk836U4K1fmKC7AE6fUcT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjFSAw%2FdJMcafLT7RN%2Fpk836U4K1fmKC7AE6fUcT1%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;1976&quot; height=&quot;1542&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.18.11.png&quot; data-origin-width=&quot;1976&quot; data-origin-height=&quot;1542&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음에 기회되면 혼자서라도 구현해보고 싶은 아이디어인데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네이버가 평점 시스템을 없앤점,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;별점을 얻는 API가 없는 플랫폼이 있는데 데이터를 어떻게 얻을것인지 등...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 문제점이 있어서 조금 더 생각해보고 해보려고한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 후 개발 시작전까지의 과정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 다음에도 아이디어 구체화, 기능 명세 등...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발 전 산출물들을 만들어내는데 약 3주의 시간을 쏟았다.&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;font-family: 'Nanum Gothic';&quot;&gt;그러다보니 개발을 할 시간이 생각보다 충분치 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 기획과 디자인이 탄탄해야 개발 과정에서 수정사항이 줄어 좋다고 하지만...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무래도 결국 시간에 쫓기게 되었다 ㅎ...&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발 과정&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.27.17.png&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtiFgX/dJMcafrBoiy/upxVc6forq1JxMr72fSTLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtiFgX/dJMcafrBoiy/upxVc6forq1JxMr72fSTLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtiFgX/dJMcafrBoiy/upxVc6forq1JxMr72fSTLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtiFgX%2FdJMcafrBoiy%2FupxVc6forq1JxMr72fSTLk%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;676&quot; height=&quot;316&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.27.17.png&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;686&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몇개만 간략히 설명하자면, 일단 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;기술스택&lt;/b&gt;&lt;/span&gt;은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;기본&lt;/b&gt;: Next.js, TypeScript&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;스타일링&lt;/b&gt;: Emotion, Radix UI, svgr&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;상태관리&lt;/b&gt;: Tanstack Query, (Zustand)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;폼&lt;/b&gt;: React Hook Form, Zod&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Linting/Formatting&lt;/b&gt;: Biome, husky&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;에디터&lt;/b&gt;: Tiptap Editor&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;s&gt;&lt;b&gt;테스트&lt;/b&gt;: Jest (시간 부족 이슈...)&lt;/s&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;날짜&lt;/b&gt;: date-fns&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;알림&lt;/b&gt;: SSE(Sever Sent Event), EventSourcePolyfill&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 프로젝트를 시작하게 되면 항상 내가 맡아서 해왔던 작업이 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨벤션 정리와 프로젝트 세팅 가이드를 만드는 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;컨벤션&lt;/b&gt;&lt;/span&gt;에는 다음과 같은 것들을 정리한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Git Convention&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Branch Convention&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Commit Convention&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Issue Template&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;PR Template&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Labels&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Naming Convention&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Folder Structure&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Code Style&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정할게 많지만, 이전 프로젝트에서 사용했던 것들을 가져오면서 생각보다 금방 끝났다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;프로젝트 세팅 가이드&lt;/b&gt;&lt;/span&gt;는 대충 아래와 같은 순서로 이미지와 함께 간단 설명을 적어놓는다.&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;스크린샷 2025-12-13 오후 7.32.28.png&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ufElp/dJMcahbSCaP/W54cDPtWzC7GkeWSwjALdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ufElp/dJMcahbSCaP/W54cDPtWzC7GkeWSwjALdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ufElp/dJMcahbSCaP/W54cDPtWzC7GkeWSwjALdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FufElp%2FdJMcahbSCaP%2FW54cDPtWzC7GkeWSwjALdk%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;622&quot; height=&quot;319&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.32.28.png&quot; data-origin-width=&quot;1468&quot; data-origin-height=&quot;752&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이후 컨벤션에 따라 쭉 개발을 진행했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;약 한 달 정도의 짧은 시간에도 불구하고 650개정도의 커밋을...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같이 프론트엔드를 맡으신 분과 정말 슬랙으로 활발히 소통하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오늘은 이정도까지만 하자며 아침 6시정도에 merge후 테스트를 하고 잠들었다 ㅎ...&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.33.49.png&quot; data-origin-width=&quot;2034&quot; data-origin-height=&quot;1572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5zgPQ/dJMcajnbnmg/n3Nu4AzY5ppMKKcJjM1tCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5zgPQ/dJMcajnbnmg/n3Nu4AzY5ppMKKcJjM1tCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5zgPQ/dJMcajnbnmg/n3Nu4AzY5ppMKKcJjM1tCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5zgPQ%2FdJMcajnbnmg%2Fn3Nu4AzY5ppMKKcJjM1tCk%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;2034&quot; height=&quot;1572&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.33.49.png&quot; data-origin-width=&quot;2034&quot; data-origin-height=&quot;1572&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 좋았던 점은 그렇게 바쁜 일정에도 불구하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;코드리뷰가 활발히 이루어져서 정말 좋았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 어떤것을 구현하고 기술을 적용할 때 보다,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;코드리뷰를 주고 받으며 수정해나갈때 실력이 상승한다고 생각하는데 그런 의미로 정말 감사했다...&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.38.20.png&quot; data-origin-width=&quot;2694&quot; data-origin-height=&quot;1166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbIFXt/dJMcabJv06E/SjwuKzKQ0DmruEt8cNlRD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbIFXt/dJMcabJv06E/SjwuKzKQ0DmruEt8cNlRD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbIFXt/dJMcabJv06E/SjwuKzKQ0DmruEt8cNlRD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbIFXt%2FdJMcabJv06E%2FSjwuKzKQ0DmruEt8cNlRD1%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;2694&quot; height=&quot;1166&quot; data-filename=&quot;스크린샷 2025-12-13 오후 7.38.20.png&quot; data-origin-width=&quot;2694&quot; data-origin-height=&quot;1166&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데모데이 및 마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d72mqO/dJMcagRzGaU/4IpoeIIfe88K5wzwmC0wVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d72mqO/dJMcagRzGaU/4IpoeIIfe88K5wzwmC0wVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d72mqO/dJMcagRzGaU/4IpoeIIfe88K5wzwmC0wVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd72mqO%2FdJMcagRzGaU%2F4IpoeIIfe88K5wzwmC0wVK%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;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스위프는 마무리까지도 정말 좋은 경험이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순히 만든 프로젝트에 대해 발표하고 끝나는 것이 아니라,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 사진처럼 우리 서비스를 다른 사람이 사용해볼 수 있게 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 팀들의 서비스를 사용해볼 수 있는 시간을 갖는다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&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&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;다양한 직군과의 협업&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;단기간에 몰입&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실사용자의 피드백&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 세가지만으로도 충분히 좋은 경험이라고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 제일 중요한 &lt;b&gt;네트워킹&lt;/b&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 낯을 좀 가리기도 해서 하기전엔 탈출하고 싶은 생각이 들었지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프론트엔드끼리 모여서 네트워킹 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다양한 직군끼리 모여서 네트워킹 하는 시간이 생각보다 재밌고 시간이 잘갔다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초상권 때문에 사진은 못올리지만... 재밌는 경험이었다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;데모데이를 마치고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단히 팀 회식을 하며 프로젝트 방향에 대한 이야기를 나눴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아쉽게도 일정상 고도화에는 같이 못하시는 분이 생겼지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트는 계속해서 고도화해보려고 한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;6주간 정말 힘들고 재밌는 경험이었으며,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;참여를 고민하는 사람들에겐 여건이 되면 꼭 해보라고 말씀드리고 싶다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;궁금한 점은 댓글로 남겨주시길 바라며 포스팅 끝!&lt;/span&gt;&lt;/p&gt;</description>
      <category>Project/두드림</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/791</guid>
      <comments>https://jun-coding.tistory.com/791#entry791comment</comments>
      <pubDate>Sat, 13 Dec 2025 19:52:03 +0900</pubDate>
    </item>
    <item>
      <title>프로젝트에 Ncloud를 사용해보자</title>
      <link>https://jun-coding.tistory.com/790</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Ncloud란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.ncloud.com/intro/feature&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.ncloud.com/intro/feature&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1764049966812&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;NAVER CLOUD PLATFORM&quot; data-og-description=&quot;cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification&quot; data-og-host=&quot;www.ncloud.com&quot; data-og-source-url=&quot;https://www.ncloud.com/intro/feature&quot; data-og-url=&quot;https://www.ncloud.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DkNff/hyZOedMO9R/n35W9m0bmKCFqRVsfsKlS0/img.jpg?width=526&amp;amp;height=274&amp;amp;face=0_0_526_274,https://scrap.kakaocdn.net/dn/qT9kw/hyZOjLkKBU/sypMbKtfDeXn4ws90p9Cck/img.png?width=1600&amp;amp;height=720&amp;amp;face=0_0_1600_720,https://scrap.kakaocdn.net/dn/dqUoUf/hyZN25wo6F/ivyQ2mqBD2TJgovVr20UJ1/img.png?width=1600&amp;amp;height=720&amp;amp;face=0_0_1600_720&quot;&gt;&lt;a href=&quot;https://www.ncloud.com/intro/feature&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ncloud.com/intro/feature&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DkNff/hyZOedMO9R/n35W9m0bmKCFqRVsfsKlS0/img.jpg?width=526&amp;amp;height=274&amp;amp;face=0_0_526_274,https://scrap.kakaocdn.net/dn/qT9kw/hyZOjLkKBU/sypMbKtfDeXn4ws90p9Cck/img.png?width=1600&amp;amp;height=720&amp;amp;face=0_0_1600_720,https://scrap.kakaocdn.net/dn/dqUoUf/hyZN25wo6F/ivyQ2mqBD2TJgovVr20UJ1/img.png?width=1600&amp;amp;height=720&amp;amp;face=0_0_1600_720');&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;NAVER CLOUD PLATFORM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ncloud.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Ncloud는 &lt;b&gt;클라우드 서비스 플랫폼&lt;/b&gt;으로, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버, 스토리지, 네트워킹, 데이터베이스, AI 서비스 등 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다양한 IT 인프라와 소프트웨어 서비스를 클라우드 형태로 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-11-25 오후 3.08.46.png&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL7F44/dJMcaaDIxTe/Qp3ekB5IkXEDCrRzv4Y0Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL7F44/dJMcaaDIxTe/Qp3ekB5IkXEDCrRzv4Y0Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL7F44/dJMcaaDIxTe/Qp3ekB5IkXEDCrRzv4Y0Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL7F44%2FdJMcaaDIxTe%2FQp3ekB5IkXEDCrRzv4Y0Xk%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;1804&quot; height=&quot;856&quot; data-filename=&quot;스크린샷 2025-11-25 오후 3.08.46.png&quot; data-origin-width=&quot;1804&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리 서비스에서는 위 이미지와 같이 사용중입니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;하나씩 간단히 어떤 서비스인지에 대해 설명을 드리자면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, &lt;b&gt;Cloud Log Analytics&lt;/b&gt;는 다음과 같이 한 문장으로 나타낼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&quot;네이버 클라우드 플랫폼의 상품을 이용하면서 발생하는 다양한 로그를 손쉽게 저장하고 분석 데이터를 제공하는 시스템&quot;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 대시보드에서 본인이 이용중인 서비스를 UI로 한 눈에 볼 수 있지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모두 모아서 로그로 빠르게 보고싶을 때나 서비스 이용중에 이슈가 생겼을 시 트래킹하기 편합니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;다음으로, &lt;b&gt;Server&lt;/b&gt;와 &lt;b&gt;Public IP&lt;/b&gt; 서비스는 다음과 같이 나타낼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;&quot;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;빠르게 생성하여 원하는 분야에 효율적으로 활용하는 서버&quot;&lt;/span&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;많은 분들이 필수, 혹은 주로 이용할 서비스라고 생각됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;직접 서버를 구축하는것보다, 클라우드에서 제공하는 서버를 이용해 간편히 인프라를 구축할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Software&lt;/b&gt; 서비스 또한 서버 구축시에 연관된 서비스인데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;서버 이미지(종류)를 선택하고, 관리할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;마지막으로, &lt;b&gt;CLOVA Studio&lt;/b&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&quot;&lt;/span&gt;&lt;/u&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;&lt;u&gt;비즈니스에 최적화된 하이퍼스케일 AI 개발 도구&quot;&lt;/u&gt;라고 나타낼 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;우리 서비스에는 'AI를 이용한 자기소개 생성' 서비스를 이용하고 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;CLOVA와 연동하여 쉽게 연결 및 관리할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;프로젝트 - 두드림&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;i&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start;&quot;&gt;(아직 개발중입니다.)&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: start; font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://dodream.store/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dodream.store/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1764051790360&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;두드림&quot; data-og-description=&quot;놓치고 있는 기회가 있을지 몰라요! AI가 회원님의 프로필과 관심사를 분석하여 최적의 글을 추천해 드립니다. 지금 로그인하고 숨겨진 기회를 두드려보세요.&quot; data-og-host=&quot;dodream.store&quot; data-og-source-url=&quot;https://dodream.store/&quot; data-og-url=&quot;https://dodream.store/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://dodream.store/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dodream.store/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;두드림&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;놓치고 있는 기회가 있을지 몰라요! AI가 회원님의 프로필과 관심사를 분석하여 최적의 글을 추천해 드립니다. 지금 로그인하고 숨겨진 기회를 두드려보세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dodream.store&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두드림은,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&quot;사이드 프로젝트/스터디를 함께할 팀원을 찾는 과정을 AI 추천으로 간소화하는 협업 매칭 서비스입니다.&quot;&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;font-family: 'Nanum Gothic';&quot;&gt;기존의 여러 팀원을 찾는 플랫폼들은&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지원자가 지원하면 보통 카카오톡 오픈채팅이나 디스코드 등 외부 서비스를 이용해 소통하는 방식입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모집부터 매칭까지, 사용자는 수동적인 탐색과 외부 채널 이동을 반복해야 하죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 과정에서 탐색 피로가 누적되고 신뢰 검증이 불가능해지는 포인트들이 있습니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&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&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지원자에게는 : &lt;b&gt;가입 시 입력한 기술 스택, 관심사를 &lt;u&gt;AI가 분석 후&lt;/u&gt; 모집글 추천&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모집글 작성자에게는 : &lt;b&gt;모집글을 &lt;u&gt;AI가 분석 후&lt;/u&gt; 최적의 유저를 추천&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모두에게: &lt;b&gt;지원 전에 궁금한점은 서비스 내 &lt;u&gt;1:1 채팅 기능&lt;/u&gt;을 이용해서 해소&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;AI 기능이 필요했고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 기능들과 웹 소켓을 이용한 채팅 기능등 여러 기능들이 얽힌 서버를 관리해야 했기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NCP의 &lt;u&gt;CLOVA&lt;/u&gt;와 &lt;u&gt;Server&lt;/u&gt; 기능들을 이용해서 간단히 구축할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfEkpN/dJMcag40IxN/hCMYzqOTxr9AJJKk1B7jnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfEkpN/dJMcag40IxN/hCMYzqOTxr9AJJKk1B7jnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfEkpN/dJMcag40IxN/hCMYzqOTxr9AJJKk1B7jnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfEkpN%2FdJMcag40IxN%2FhCMYzqOTxr9AJJKk1B7jnk%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;2000&quot; height=&quot;1856&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1856&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NCloud 후기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 후기는 둘러보면서 느낀것과, 팀원들의 사용 및 설정 후기를 취합하여 작성되었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좋았던 점&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같은 클라우드 서비스인 AWS보다 전반적으로 사용 방식이 직관적이라 편리했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NCP 콘솔, 가이드, 문서가 한국어로 제공되어 국내 개발자 입장에서 이해하기 편했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한국 리전이 있어서 '국내망', '낮은 지연'이라는 점에서 국내 서비스 목적이라면 편리할 수 있다고 생각했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UI과 콘솔 또한 한국어로 되어있어 비교적 직관적이라 편리했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좋았던 점을 취합해보면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무래도 네이버가 한국 서비스이기 때문에 한국인들이 사용하기 편하다는것이 전반적입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, UI로도 많은 정보를 보고 관리할 수 있어서 사용법이 직관적이라는 후기 입니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아쉬웠던 점&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 공개된 이용 안내문과 실제 화면이 달라 혼란스러운 부분이 있었습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서브계정 생성시에 sudo 설정, root 접속 잠금 등의 절차가 복잡한 부분이 있었습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;vectorDB 관련 임베딩이 눈에 띄지 않아서 찾기 힘들었습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NCP ObjectStorage&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;aws s3와 호환이 된다고 설명이 되어있음에도, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;엔드포인트 변경 / 키 인증 / 권한 설정 / 네트워크 구조 등 번거로운 부분이 너무 많았습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;세부설정 조차도 다르고, 기본 엔드포인트가 아닌 액세스키 별도 생성등이 요구되는데 너무 불편했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대부분의 문서가 한국어로 되어있는건 좋았지만,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실상 엣지케이스가 상세하게 다뤄지지는 않아서 정보 부족으로 더 많이 구글링하고 찾아봐야 했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Clova 임베딩이 모델마다 차원수가 강하게 고정되어 있어서 정확하게 설정하지 않으면 오류가 발생했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대량 임베딩 처리시 rate-limit 문제가 발생해서 불편했습니다. (약 500개 정도의 데이터에서도 발생)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아쉬웠던 점을 취합해보면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;공식문서가 UI/UX 업데이트나 기능 업데이트를 따라오지 못하는 느낌이었습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한국어로 되어있어 보기 편함에도, 오히려 더 많이 찾아봐야 했습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, 편리한 서비스들을 제공한다는 느낌이지만&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;막상 사용해보면 세부 설정등 안내된것보다 복잡하거나 어려운것이 많았습니다.&lt;/span&gt;&lt;/blockquote&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Green Developers&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;네이버클라우드 예비 개발자 지원 프로그램&lt;/u&gt; Green Developer에 참여해 크레딧을 받아서 NCloud를 사용해봤습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;확실히 클라우드 서비스라 인프라 구축에서 많은 도움을 직관적으로 받을 수 있어서 편리했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발자들에게 제일 귀찮고도 어려운 부분이 이런 환경 구축이라고 생각되는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좋은 기회를 통해 좋은 경험을 할 수 있었습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Project/두드림</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/790</guid>
      <comments>https://jun-coding.tistory.com/790#entry790comment</comments>
      <pubDate>Tue, 25 Nov 2025 16:41:07 +0900</pubDate>
    </item>
    <item>
      <title>Next.js + node.js로 간단한 Web Scoket 채팅 구현하기 - 1</title>
      <link>https://jun-coding.tistory.com/789</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그동안 여러 프로젝트를 진행해오면서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SSE(Server Sent Event), CRUD API 연동은 진행해봤지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Web Socket을 다뤄본적은 없었다.&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;font-family: 'Nanum Gothic';&quot;&gt;Web Socket 대신 SSE를 사용했던 이유는 알림 기능을 구현하기 위해서였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 Web Socket을 사용해도 되지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트는 단순히 알림조회를 하므로 양방향 소통이 필요하지 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 단방향인 SSE를 다뤘었다.&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;font-family: 'Nanum Gothic';&quot;&gt;그래서 Web Socket을 한번쯤은 다뤄보고 싶었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;언젠간 분명히 사용할 것 같아서 그냥 간단한 채팅을 구현하면서 트러블 슈팅을 해보려한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Server&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;평소에 프론트엔드를 주로 공부하고, 프로젝트도 모두 프론트엔드로 참여를 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 프론트엔드 직무로 프론트엔드를 준비중이기도 하다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;따라서 서버를 다룬 경험은 거의 없어서 고민했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어차피 일단은 단순히 맛보기만 할것이기 때문에 node.js를 사용해서 서버를 구성하였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759478356083&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });
console.log('웹소켓 서버가 8080 포트에서 실행되었습니다.');

wss.on('connection', (ws) =&amp;gt; {
  console.log('클라이언트가 연결되었습니다.');

  ws.on('message', (message) =&amp;gt; {
    wss.clients.forEach((client) =&amp;gt; {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });

  ws.on('close', () =&amp;gt; {
    console.log('클라이언트 연결이 끊어졌습니다.');
  });
});

wss.on('error', (error) =&amp;gt; {
  console.error('웹소켓 에러:', error);
});&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 기본 설정&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초기 설정은 아래 영상 참고해서 했습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ckaAhENDLLQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=ckaAhENDLLQ&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=ckaAhENDLLQ&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/gxeGU/hyZKl343V8/XSr7De2oQ5OjOxCGe5eZw1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720,https://scrap.kakaocdn.net/dn/Dh9lQ/hyZKmBTlqg/mQjfq3xfJLGtgHporYf3S0/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;알고 있으면 너무 좋은 프론트엔드 웹 기술 : WebSocket&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/ckaAhENDLLQ&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 client와 server 폴더를 나눠서 만들어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.09.54.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LDawk/btsQ2srrx2P/Rzc6C2RYmubCmELkYE9ew0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LDawk/btsQ2srrx2P/Rzc6C2RYmubCmELkYE9ew0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LDawk/btsQ2srrx2P/Rzc6C2RYmubCmELkYE9ew0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLDawk%2FbtsQ2srrx2P%2FRzc6C2RYmubCmELkYE9ew0%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;526&quot; height=&quot;192&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.09.54.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;192&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로, 터미널에서 server 폴더로 들어간 뒤,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로젝트를 다음 명령어로 초기화해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759479098960&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# server 폴더로 이동
cd server
# 프로젝트 초기화
npm init&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명령어를 입력하게 되면 여러 옵션을 선택하는것이 나오는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단은 모두 기본값으로 하기 위해 계속 엔터를 눌러준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정상적으로 모두 마쳤다면, server 폴더 밑에 package.json 파일이 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.16.34.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGX6pq/btsQ2nYlyMU/MBdtoPRIL4Agw7Q0RVFX80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGX6pq/btsQ2nYlyMU/MBdtoPRIL4Agw7Q0RVFX80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGX6pq/btsQ2nYlyMU/MBdtoPRIL4Agw7Q0RVFX80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGX6pq%2FbtsQ2nYlyMU%2FMBdtoPRIL4Agw7Q0RVFX80%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;526&quot; height=&quot;228&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.16.34.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;228&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이후에 소켓을 직접 구현해도 되지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비트 연산을 활용해서 소켓 프레임을 직접 구상하는 등 복잡하기 때문에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 웹 소켓 라이브러리를 설치해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759479546954&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i ws&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. server.js 구현&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설정을 모두 마쳤다면 server.js 파일을 만들어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.22.30.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;396&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doVvOF/btsQ3dAGfRJ/k7QRaykqrzmYTbbpPockwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doVvOF/btsQ3dAGfRJ/k7QRaykqrzmYTbbpPockwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doVvOF/btsQ3dAGfRJ/k7QRaykqrzmYTbbpPockwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoVvOF%2FbtsQ3dAGfRJ%2Fk7QRaykqrzmYTbbpPockwk%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;526&quot; height=&quot;396&quot; data-filename=&quot;스크린샷 2025-10-03 오후 5.22.30.png&quot; data-origin-width=&quot;526&quot; data-origin-height=&quot;396&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 다음과 같이 코드를 작성해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759479698256&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });
console.log('웹소켓 서버가 8080 포트에서 실행되었습니다.');

// ws는 클라이언트와 연결된 웹소켓 인스턴스
wss.on('connection', (ws) =&amp;gt; {
  console.log('클라이언트가 연결되었습니다.');

  ws.on('message', (message, isBinary) =&amp;gt; {
    wss.clients.forEach((client) =&amp;gt; {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message, { binary: false });
      }
    });
  });

  ws.on('close', () =&amp;gt; {
    console.log('클라이언트 연결이 끊어졌습니다.');
  });
});

wss.on('error', (error) =&amp;gt; {
  console.error('웹소켓 에러:', error);
});

wss.on('close', () =&amp;gt; {
  console.log('웹소켓 서버가 종료되었습니다.');
});&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하나씩 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759483216719&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });
console.log('웹소켓 서버가 8080 포트에서 실행되었습니다.');&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;서버는 8080 포트&lt;/b&gt;에서 열리도록 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 포트가 다른것과 충돌난다면, 포트번호를 바꿔서 하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759483232787&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// ws는 클라이언트와 연결된 웹소켓 인스턴스
wss.on('connection', (ws) =&amp;gt; {
  console.log('클라이언트가 연결되었습니다.');

  ws.on('message', (message, isBinary) =&amp;gt; {
    wss.clients.forEach((client) =&amp;gt; {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message, { binary: false });
      }
    });
  });

  ws.on('close', () =&amp;gt; {
    console.log('클라이언트 연결이 끊어졌습니다.');
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;`on`이벤트를 통해서 웹 소켓관련 액션들을 처리&lt;/b&gt;하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;'connection'은 클라이언트가 연결되었을 때 실행&lt;/b&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 콜백의 인자로 넘겨주는 &lt;b&gt;`ws`는 클라이언트와 연결된 웹소켓 객체(인스턴스)&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;font-family: 'Nanum Gothic';&quot;&gt;연결이 완료된 후,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 클라이언트 별로 이벤트 처리를 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;'message' 이벤트는 클라이언트로부터 어떠한 메시지를 받았을 때 실행되는 이벤트&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를 처리할 콜백인자로 `message`와 `isBinary`를 넘겨주었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;`message`는 클라이언트로부터 받은 메시지,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;`isBinary`는 받은 메시지가 바이너리 형식인지 판단하는 boolean 값&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;font-family: 'Nanum Gothic';&quot;&gt;모두가 같은 채팅방에 있다는 가정하에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한 클라이언트가 보낸 메시지는 다른 모든 클라이언트에게 보여야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 연결된 모든 클라이언트를 순회하면서 메시지를 보내준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 메시지는 문자열이기 때문에, binary는 false로 지정해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(기본값이 false이므로 따로 지정해주지 않아도 된다.)&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;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 &lt;b&gt;클라이언트의 연결이 끊어졌을 때인 'close' 이벤트&lt;/b&gt;를 처리해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. server 구동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버를 모두 구현한 후,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버를 구동하려면 터미널에서 다음 명령어를 입력해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759483590296&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;node server.js&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정상적으로 작동이 되었다면, 터미널에서 다음 메시지를 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-03 오후 6.25.49.png&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tM6kT/btsQ38yJka3/62yZSfx5QSUZX48kpmlez1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tM6kT/btsQ38yJka3/62yZSfx5QSUZX48kpmlez1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tM6kT/btsQ38yJka3/62yZSfx5QSUZX48kpmlez1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtM6kT%2FbtsQ38yJka3%2F62yZSfx5QSUZX48kpmlez1%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;1106&quot; height=&quot;424&quot; data-filename=&quot;스크린샷 2025-10-03 오후 6.25.49.png&quot; data-origin-width=&quot;1106&quot; data-origin-height=&quot;424&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Client&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트는 Next.js로 구현하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 어떠한 서비스를 만드는것이 아니라 연습하는 것이므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순 JS나 React로 구성해도 상관이없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS는 Tailwind CSS와 shadcn/ui로 작성하였다.&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;font-family: 'Nanum Gothic';&quot;&gt;최대한 복잡한 db나 서버가 필요하지 않는 범위에서 카카오톡 채팅방을 클론해보며 하려한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음은 1차로 구현한 전체 코드이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1759669235987&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client';

import useSocket from '@/hooks/useSocket';
import { Avatar, AvatarFallback, AvatarImage } from '@radix-ui/react-avatar';
import { SearchIcon } from 'lucide-react';
import { useState } from 'react';

export default function Home() {
  const { messages, socket } = useSocket();
  const [message, setMessage] = useState('');

  function handleSend(e: React.FormEvent&amp;lt;HTMLFormElement&amp;gt;) {
    e.preventDefault();

    socket?.send(message);
    setMessage('');
  }

  return (
    &amp;lt;div className=&quot;bg-blue-300 w-1/3 h-3/5 rounded-lg flex flex-col border border-gray-300 justify-between&quot;&amp;gt;
      &amp;lt;header className=&quot;p-2 flex items-center gap-2 justify-between&quot;&amp;gt;
        &amp;lt;div className=&quot;flex items-center gap-2&quot;&amp;gt;
          &amp;lt;Avatar&amp;gt;
            &amp;lt;AvatarImage
              src=&quot;https://github.com/shadcn.png&quot;
              className=&quot;rounded-full w-5 h-5&quot;
            /&amp;gt;
            &amp;lt;AvatarFallback&amp;gt;CN&amp;lt;/AvatarFallback&amp;gt;
          &amp;lt;/Avatar&amp;gt;

          &amp;lt;p&amp;gt;유저1&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className=&quot;flex items-center gap-2&quot;&amp;gt;
          &amp;lt;button&amp;gt;
            &amp;lt;SearchIcon className=&quot;w-4 h-4&quot; /&amp;gt;
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/header&amp;gt;

      &amp;lt;div className=&quot;p-2 overflow-y-auto&quot;&amp;gt;
        {messages.map((item, index) =&amp;gt; (
          &amp;lt;div key={index}&amp;gt;{item}&amp;lt;/div&amp;gt;
        ))}
      &amp;lt;/div&amp;gt;

      &amp;lt;form className=&quot;h-1/5 flex flex-col p-2 bg-white&quot; onSubmit={handleSend}&amp;gt;
        &amp;lt;textarea
          className=&quot;w-full h-full resize-none focus:outline-none text-sm p-1&quot;
          value={message}
          onChange={(e) =&amp;gt; setMessage(e.target.value)}
          placeholder=&quot;메시지 입력&quot;
          onKeyDown={(e) =&amp;gt; {
            if (e.key === 'Enter' &amp;amp;&amp;amp; !e.shiftKey) {
              e.preventDefault();
              e.currentTarget.form?.requestSubmit();
            }
          }}
        /&amp;gt;
        &amp;lt;div className=&quot;flex justify-end&quot;&amp;gt;
          &amp;lt;button
            type=&quot;submit&quot;
            className={`font-semibold text-sm rounded-lg py-2 px-4 ${
              message.length &amp;gt; 0
                ? 'bg-yellow-300 '
                : 'bg-gray-100 text-gray-400'
            }`}
            disabled={message.length === 0}
          &amp;gt;
            전송
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759830665151&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;textarea
  className=&quot;w-full h-full resize-none focus:outline-none text-sm p-1&quot;
  value={message}
  onChange={(e) =&amp;gt; setMessage(e.target.value)}
  placeholder=&quot;메시지 입력&quot;
  onKeyDown={(e) =&amp;gt; {
    if (e.key === 'Enter' &amp;amp;&amp;amp; !e.shiftKey) {
      e.preventDefault();
      e.currentTarget.form?.requestSubmit();
    }
  }}
/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;socket 관련 로직 부분은 조금 길어서 커스텀 훅으로 별도로 분리했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 전에, UI 조금만 살펴보자면 메시지 입력 부분에 &amp;lt;textarea&amp;gt;를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;onKeyDown 이벤트에 엔터를 눌렀을 때 처리를 해주었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;엔터를 누르면 입력한 메시지가 전송이 되도록 폼 제출을 하도록 해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;shift 키를 같이 누르면, 카카오톡과 똑같이 전송은 안되고 줄바꿈이 되도록 조건을 걸어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1759830749249&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;div className=&quot;flex justify-end&quot;&amp;gt;
  &amp;lt;button
    type=&quot;submit&quot;
    className={`font-semibold text-sm rounded-lg py-2 px-4 ${
      message.length &amp;gt; 0
        ? 'bg-yellow-300 '
        : 'bg-gray-100 text-gray-400'
    }`}
    disabled={message.length === 0}
  &amp;gt;
    전송
  &amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;전송버튼은 입력한 메시지가 없을 때 disable 되도록 해놨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, 입력한 메시지가 있는지 여부에 따라 디자인도 바뀌도록 해놨다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;완성하면 다음과 같은데, 여러 브라우저에서 실행해서 테스트해보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음에는 각 유저 구별을 위한 기능을 추가해봐야겠다!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.21.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;1964&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSEmqf/btsQ5a4kv5l/vOuww0V2pucCdedlEN7KSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSEmqf/btsQ5a4kv5l/vOuww0V2pucCdedlEN7KSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSEmqf/btsQ5a4kv5l/vOuww0V2pucCdedlEN7KSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSEmqf%2FbtsQ5a4kv5l%2FvOuww0V2pucCdedlEN7KSk%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;3024&quot; height=&quot;1964&quot; data-filename=&quot;스크린샷 2025-10-07 오후 6.57.21.png&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;1964&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;</description>
      <category>Web/Web Socket</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/789</guid>
      <comments>https://jun-coding.tistory.com/789#entry789comment</comments>
      <pubDate>Tue, 7 Oct 2025 18:58:27 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 4195번 / 친구 네트워크 / JS</title>
      <link>https://jun-coding.tistory.com/788</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/4195&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/4195&lt;/a&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1758613064410&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? 0 : './input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');

const T = +input.shift();

function* idGenerator() {
  let id = 0;

  while (true) {
    yield id++;
  }
}

class UnionFind {
  constructor() {
    this.parent = [];
    this.count = [];
    this.nameMap = new Map();
    this.idGenerator = idGenerator();
  }

  getId(name) {
    if (!this.nameMap.has(name)) {
      const newId = this.idGenerator.next().value;

      this.nameMap.set(name, newId);
      this.parent.push(newId);
      this.count.push(1);
    }

    return this.nameMap.get(name);
  }

  getParent(id) {
    if (this.parent[id] === id) {
      return id;
    }

    return (this.parent[id] = this.getParent(this.parent[id]));
  }

  union(id1, id2) {
    const rootId1 = this.getParent(id1);
    const rootId2 = this.getParent(id2);

    if (rootId1 === rootId2) {
      return this.count[rootId1];
    }

    if (this.count[rootId1] &amp;lt; this.count[rootId2]) {
      this.parent[rootId1] = rootId2;
      this.count[rootId2] += this.count[rootId1];
    } else {
      this.parent[rootId2] = rootId1;
      this.count[rootId1] += this.count[rootId2];
    }

    return this.count[this.getParent(id1)];
  }
}

function solution() {
  const result = [];

  for (let testCase = 0; testCase &amp;lt; T; testCase++) {
    const F = +input.shift();
    const uf = new UnionFind();

    for (let i = 0; i &amp;lt; F; i++) {
      const [user1, user2] = input.shift().split(' ');

      const user1Id = uf.getId(user1);
      const user2Id = uf.getId(user2);

      const count = uf.union(user1Id, user2Id);

      result.push(count);
    }
  }

  console.log(result.join('\n'));
}

solution();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Union Find를 활용하는 문제였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본 Union Find와 다른 점은, 문자열로 입력을 받기 때문에 그에 해당하는 숫자를 만들어주어야 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래야 기존 배열에서 인덱스로 바로 접근 가능하도록 하는 구현이 가능하기 때문이다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`idGenerator()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758613209950&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function* idGenerator() {
  let id = 0;

  while (true) {
    yield id++;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;입력받는 문자열 이름의 숫자 id를 만들어주는 &lt;b&gt;제너레이터 함수&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 id를 전역 변수로 만든 후에, 일반 함수로 만들어서 써도 상관은 없지만&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제너레이터 함수를 써본적이 없어서 이번에 한 번 써보기로 했다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;간단히 설명하자면, 제너레이터 함수는 함수를 선언하는 것도 약간 다른데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;' * ' 문자를 붙여줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 하나의 값을 반환하는 것이 아니라, 여러 개의 값을 필요에 따라 반환할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`next()` 메서드를 부를 때 마다 가장 가까운 yield 문을 만날 때까지 실행이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`next()`는 `value`와 `done`을 가지는 객체를 반환한다.&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;font-family: 'Nanum Gothic';&quot;&gt;자세한 건 아래에서!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/generators&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.javascript.info/generators&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1758614332269&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;제너레이터&quot; data-og-description=&quot;&quot; data-og-host=&quot;ko.javascript.info&quot; data-og-source-url=&quot;https://ko.javascript.info/generators&quot; data-og-url=&quot;https://ko.javascript.info/generators&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kKu1t/hyZJv7GDAX/8qFhOhjFPC2hltnrQNCtV0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/pzpui/hyZJvNofqA/toXd2kRvIc8N2zT0qBA1WK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/generators&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.javascript.info/generators&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kKu1t/hyZJv7GDAX/8qFhOhjFPC2hltnrQNCtV0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/pzpui/hyZJvNofqA/toXd2kRvIc8N2zT0qBA1WK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;제너레이터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.javascript.info&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`class UnionFind`&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로 문제 풀이에 필요한 Union Find에 관련된 것을 한 군데서 관리하기 위해 클래스를 만들어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1758614418443&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class UnionFind {
  constructor() {
    this.parent = [];
    this.count = [];
    this.nameMap = new Map();
    this.idGenerator = idGenerator();
  }

  getId(name) {
    if (!this.nameMap.has(name)) {
      const newId = this.idGenerator.next().value;

      this.nameMap.set(name, newId);
      this.parent.push(newId);
      this.count.push(1);
    }

    return this.nameMap.get(name);
  }

  getParent(id) {
    if (this.parent[id] === id) {
      return id;
    }

    return (this.parent[id] = this.getParent(this.parent[id]));
  }

  union(id1, id2) {
    const rootId1 = this.getParent(id1);
    const rootId2 = this.getParent(id2);

    if (rootId1 === rootId2) {
      return this.count[rootId1];
    }

    if (this.count[rootId1] &amp;lt; this.count[rootId2]) {
      this.parent[rootId1] = rootId2;
      this.count[rootId2] += this.count[rootId1];
    } else {
      this.parent[rootId2] = rootId1;
      this.count[rootId1] += this.count[rootId2];
    }

    return this.count[this.getParent(id1)];
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`UnionFind.constructor()`&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758614455069&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  constructor() {
    this.parent = [];
    this.count = [];
    this.nameMap = new Map();
    this.idGenerator = idGenerator();
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UnionFind 클래스를 만드는 생성자 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 초기변수가 의미하는 것은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;parent&lt;/b&gt; : 각 요소의 부모 id를 나타내는 배열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;count&lt;/b&gt; : 현재 id가 속한 네트워크의 친구 수를 저장하는 배열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;nameMap&lt;/b&gt; : key는 이름, value는 id를 가지는 Map&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;idGenerator&lt;/b&gt; : 위에서 선언한 id 제너레이터 함수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`UnionFind.getId(name)`&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758614677392&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  getId(name) {
    if (!this.nameMap.has(name)) {
      const newId = this.idGenerator.next().value;

      this.nameMap.set(name, newId);
      this.parent.push(newId);
      this.count.push(1);
    }

    return this.nameMap.get(name);
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;이름을 인자로 받아 해당 이름에 해당하는 id를 반환해주는 함수&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;코드를 보면 `next()`를 호출하면 제너레이터 함수의 다음 yield를 만나고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 때 해당하는 value값을 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제너레이터 함수에서 whie(true)로 무한 반복을 하고 있기 때문에,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;1씩 증가된 id를 `next()`로 부르면 계속 생성할 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;만약 `nameMap`에 인자로 들어온 이름이 없다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`nameMap`에 이름과 생성한 아이디를 넣어주고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`parent`에 생성한 id를 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때, 배열의 인덱스와 id 모두 0부터 시작하기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본 Union Find 문제 풀 때 처럼 자기 인덱스를 값으로 가지는 배열을 생성하는 것과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 후, 초기에는 네트워크에 본인만 있으므로, `count`에 1을 넣어준다.&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;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 id를 반환해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`UnionFind.getParent(id)`&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758614995153&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  getParent(id) {
    if (this.parent[id] === id) {
      return id;
    }

    return (this.parent[id] = this.getParent(this.parent[id]));
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;인자로 id를 받고, 해당 id의 루트 부모를 찾아주는 함수&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본 Union Find의 함수와 똑같이 구현하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`UnionFind.union(id1, id2)`&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1758615052926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  union(id1, id2) {
    const rootId1 = this.getParent(id1);
    const rootId2 = this.getParent(id2);

    if (rootId1 === rootId2) {
      return this.count[rootId1];
    }

    if (this.count[rootId1] &amp;lt; this.count[rootId2]) {
      this.parent[rootId1] = rootId2;
      this.count[rootId2] += this.count[rootId1];
    } else {
      this.parent[rootId2] = rootId1;
      this.count[rootId1] += this.count[rootId2];
    }

    return this.count[this.getParent(id1)];
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;합칠 id 두 개를 인자로 받아, 하나로 합쳐주는 함수&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;주의할 점은 두 id의 부모가 같을 때&lt;/span&gt;&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미 부모가 같으면 합쳐져있다는 의미이므로, 한 쪽의 수를 더하는 행위를 할 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 아무 부모의 수를 반환해주면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그 외에는 대소비교를 해서 한쪽에 합쳐주면된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758616860796&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution() {
  const result = [];

  for (let testCase = 0; testCase &amp;lt; T; testCase++) {
    const F = +input.shift();
    const uf = new UnionFind();

    for (let i = 0; i &amp;lt; F; i++) {
      const [user1, user2] = input.shift().split(' ');

      const user1Id = uf.getId(user1);
      const user2Id = uf.getId(user2);

      const count = uf.union(user1Id, user2Id);

      result.push(count);
    }
  }

  console.log(result.join('\n'));
}

solution();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;메인 함수에서는 위에서 만든 클래스를 잘 활용해 답을 구해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;주의할 것은 테스트케이스가 여러개이기 때문에 초기화를 잘 해줘야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>4195번</category>
      <category>js</category>
      <category>백준</category>
      <category>친구 네트워크</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/788</guid>
      <comments>https://jun-coding.tistory.com/788#entry788comment</comments>
      <pubDate>Tue, 23 Sep 2025 17:42:00 +0900</pubDate>
    </item>
    <item>
      <title>2025 FEConf 후기</title>
      <link>https://jun-coding.tistory.com/787</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2025년 FEConf에 참가한 개인적인 후기입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단히 어떤 내용들이 있었고, 개인적인 느낌을 적다보니 사진과 조금의 발표자료가 포함되어 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초상권, 발표내용을 업로드하는데 문제가 있을 경우,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;댓글 남겨주시면 삭제하겠습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-49 001.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FBZlA/btsQBGpKLPq/f0wdh6Dawg1bP90I4Gjm20/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FBZlA/btsQBGpKLPq/f0wdh6Dawg1bP90I4Gjm20/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FBZlA/btsQBGpKLPq/f0wdh6Dawg1bP90I4Gjm20/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFBZlA%2FbtsQBGpKLPq%2Ff0wdh6Dawg1bP90I4Gjm20%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-49 001.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;늦었지만, FEConf 후기를 올려보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그동안 규모가 작은 밋업이나 컨퍼런스는 가봤지만, 이런 대규모 컨퍼런스는 처음이라 신기하기도 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프론트엔드 개발을 주로 하는 사람으로써, 프론트엔드만을 주제로 한 컨퍼런스라 기대되기도 했다.&lt;/span&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 widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-49 002.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J1e7z/btsQHQSFjyI/IHfpnGuaCxxB5jVfKOdErK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J1e7z/btsQHQSFjyI/IHfpnGuaCxxB5jVfKOdErK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J1e7z/btsQHQSFjyI/IHfpnGuaCxxB5jVfKOdErK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ1e7z%2FbtsQHQSFjyI%2FIHfpnGuaCxxB5jVfKOdErK%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-49 002.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;세션이 진행되는 홀도 좁지 않았는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;늦지 않았음에도 빨리 안가면 앉을 자리도 없을 정도였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만 의자에 음료나 본인 짐을 두고 자리를 오래 비우는 사람들이 많았는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;음료는 가지고 들어갈 수 없었고, 짐을 두고 자리를 오래 비우지 말라는 스태프들의 말이 있었는데 하나도 안지켜진 것 같았다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결국, 앞 줄에서 자리있냐고 다섯 번 정도는 물어보면서 점점 뒤로 와서 맨 뒤에 앉게됐다 ㅎ,,,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자리가 없어서 뒤에서 서서 보는 사람들도 많았는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;잘 안보여서 빠르게 자리 선점하는 것이 좋을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 003.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1Xj4o/btsQGCVx9Nm/oF8ylWldv1byfwZImQn6qk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1Xj4o/btsQGCVx9Nm/oF8ylWldv1byfwZImQn6qk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1Xj4o/btsQGCVx9Nm/oF8ylWldv1byfwZImQn6qk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1Xj4o%2FbtsQGCVx9Nm%2FoF8ylWldv1byfwZImQn6qk%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 003.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 세션으로 &lt;b&gt;&quot;'memo'를 지울 결심&quot;&lt;/b&gt; 이라는 세션을 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Memoization도 메모리를 사용하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;매 렌더링마다 의존성 배열을 비교하기 때문에 런타임 오버헤드가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 Memoization이 React Compiler를 거치면 코드가 어떻게 변하는지에 대해 알아보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컴파일 과정, React Compiler의 한계와 문제에 대해서도 알아보았다.&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;font-family: 'Nanum Gothic';&quot;&gt;사실 프로젝트를 거치면서 Memoization을 많이 써본적은 아직은 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;불필요한 리렌더링을 줄여주기 때문에 좋은거 아닌가? 라는 생각이 항상 들었지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;과연 지금 상황에서 Memoization을 굳이 써야할지,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;쓴다고 해서 극적인 효과가 날지도 미지수 였어서 확실하지 않으면 굳이 쓰진 않았던 것 같다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이런 고민들이 있어서 이 세션을 선택해서 들었는데, 좋은 선택이었던 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&quot;앞으로는 수동 메모이제이션에서 해방된 흐름에 집중해야 한다.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;를 마무리로 좋은 인사이트를 얻는 세션이었다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 005.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOHsNp/btsQGDNUrwH/gF7pkvlnk8KWz4wjH3aq8K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOHsNp/btsQGDNUrwH/gF7pkvlnk8KWz4wjH3aq8K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOHsNp/btsQGDNUrwH/gF7pkvlnk8KWz4wjH3aq8K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOHsNp%2FbtsQGDNUrwH%2FgF7pkvlnk8KWz4wjH3aq8K%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 005.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로는 &lt;b&gt;&quot;모두를 위한 웹 접근성 무엇이고, 어떻게 하나요?&quot;&lt;/b&gt;라는 주제의 세션을 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 접근성을 위한 HTML Attribute들은 알고 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스크린 리더를 지원하는 aria 속성들이었는데, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;당시에 생각날때만 잠깐 추가했었지 처음부터 웹 접근성을 신경쓰면서 했던 적은 없던것 같았다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&quot;때론 심미성 보다, 접근성 고려가 우선이다.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 소주제가 확 와닿았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UI를 고려하다 보면 어떻게 깔끔하게 할지, 어떻게 예쁘게 디자인할지만 생각하게 된다.&lt;/span&gt;&lt;/p&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/cDA2F0/btsQH1AdFM8/VL2F1qjJHCM5kut8czo0nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDA2F0/btsQH1AdFM8/VL2F1qjJHCM5kut8czo0nK/img.png&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;1200&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.785%; margin-right: 10px;&quot; data-widthpercent=&quot;47.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDA2F0/btsQH1AdFM8/VL2F1qjJHCM5kut8czo0nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDA2F0%2FbtsQH1AdFM8%2FVL2F1qjJHCM5kut8czo0nK%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;604&quot; height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o8512/btsQIAoOD88/RKZmUdJwccmjwnV5nOKnk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o8512/btsQIAoOD88/RKZmUdJwccmjwnV5nOKnk1/img.png&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;1200&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.0522%;&quot; data-widthpercent=&quot;52.66&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o8512/btsQIAoOD88/RKZmUdJwccmjwnV5nOKnk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo8512%2FbtsQIAoOD88%2FRKZmUdJwccmjwnV5nOKnk1%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;672&quot; height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;왼쪽 - 코레일 앱 '코레일 톡' 예매화면, 오른쪽 - 리뉴얼 된 웹서비스 예매 화면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왼쪽이 코레일 앱 '코레일 톡' 예매화면이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오른쪽이 리뉴얼 된 웹서비스 예매화면이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;열차 항목을 티켓 형태로 디자인을 리뉴얼하면서 &lt;u&gt;화면에 표시되는 개수가 6개에서 3개로,&amp;nbsp; 절반 줄어들었다.&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이게 뜻하는 것은, 동일한 정보를 얻기 위해 더 많은 스크롤과 탐색이 필요하다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러므로 탐색에 할애하는 시간이 증가되고, 여러 선택지를 같이 비교하기가 어려워진다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이처럼 디자인은 오른쪽이 예뻐보일 수 있지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사용자 입장에서 생각했을 때는 오히려 전의 디자인이 더 편하다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 내용이 여태까지 생각했던 디자인의 개념을 바꿔놓게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나는 UX를 향상시키는 디자인이, 예쁘게 디자인하면서 편해야한다. 라고만 생각했지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떨 때는 예쁜 디자인은 후순위의 고려사항일수도 있다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 006.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c92Zi3/btsQI68Ox4F/20YAfHoIA7LMauAiqfqUE1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c92Zi3/btsQI68Ox4F/20YAfHoIA7LMauAiqfqUE1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c92Zi3/btsQI68Ox4F/20YAfHoIA7LMauAiqfqUE1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc92Zi3%2FbtsQI68Ox4F%2F20YAfHoIA7LMauAiqfqUE1%2Fimg.jpg&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;3000&quot; height=&quot;4000&quot; data-filename=&quot;KakaoTalk_Photo_2025-09-16-17-44-50 006.jpeg&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로는, 라이트닝 톡으로 &lt;b&gt;&quot;지속 가능한 개발&quot;&lt;/b&gt; 관련 세션을 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라이트닝 톡은 짧은 시간(20분 정도?)동안 가벼운 주제로 여러 연사자들이 릴레이 형식으로 진행된다.&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;font-family: 'Nanum Gothic';&quot;&gt;주제가 '지속 가능한 개발'이기도 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기억상으로 시니어분이 나오셔서 어떠한 개발 방법론에 대해 얘기해주실줄 알았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 의외로 '건강'을 강조하는게 뜬금없어서 웃기면서도 공감이 가는 내용이었다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;아무래도 개발자들은 앉아있는 시간이 길고, 모니터를 오래 본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 눈건강, 목건강, 허리건강을 걱정하는 사람들도 많을 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;건강해야 계속 개발한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이게 진정한 지속 가능한 개발이라고 말하시는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음엔 약간 웃겼지만 완전 공감되는 내용이었다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-09-19 오후 6.39.04.png&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;637&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boi6CO/btsQHRYJZau/77ygYjLLwxgzfQNBVzTK00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boi6CO/btsQHRYJZau/77ygYjLLwxgzfQNBVzTK00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boi6CO/btsQHRYJZau/77ygYjLLwxgzfQNBVzTK00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fboi6CO%2FbtsQHRYJZau%2F77ygYjLLwxgzfQNBVzTK00%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;1134&quot; height=&quot;637&quot; data-filename=&quot;스크린샷 2025-09-19 오후 6.39.04.png&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;637&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로는 &lt;b&gt;&quot;Tanstack Query 너머를 향해! - 쿼리를 라우트까지 전파시키기&quot;&lt;/b&gt;라는 주제의 세션을 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때는 사진찍는걸 깜빡해서 못찍었다...&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;React Server Component(RSC)와 Tanstack Query가 함께하는 법에 대한 세션이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;RSC와 Tanstack Query를 같이 사용하려면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;queryClient만 설정해주는 것이 아니라 prefetch도 해주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 이유는, 서버에서 미리 데이터를 가져와(dehydrate) 클라이언트로 전달하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트 컴포넌트에서 즉시 캐시된 데이터를 사용해 초기에 바로 렌더링이 가능하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그렇게 되면 하위 컴포넌트에서 쿼리를 사용할 수 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;하지만, 하위 컴포넌트가 멀어진다면 불필요한 prefetch가 남을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이럴 때 서버 컴포넌트를 같이 두면 지우는 것도 동시라서 해결되는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러면 또 RSC가 쌓일 수록 병렬화가 어려워진다...&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;font-family: 'Nanum Gothic';&quot;&gt;그래서 대안으로 개발중인 것이 있다고 하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;10월 중에 오픈소스로 전환예정이라고 하니 기대된다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무래도 React로 개발하면서 Tanstack Query는 이제는 뗄 수 없게 되어버려서 더 기대된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에 소개한 세션들뿐만 아니라 다른 홀에서 동시간대에 진행한 세션들도 많았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시간이 겹치고, 내 흥미가 좀 더 돋는쪽으로 가서 들은것이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 세션들도 주제는 물론 좋은 주제들이 많아서 아쉬웠다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;세션을 참가하면서 여러 인사이트를 얻을 수 있었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;전체적으로 프론트엔드 관련 새로운 라이브러리나 흐름이 계속해서 나올수록&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오히려 기본에 충실해야 한다&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;font-family: 'Nanum Gothic';&quot;&gt;그냥 좋다고 사용하지말고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왜 써야하는지, 혹은 굳이 써야할까? 라는 고민을 가져야 하는 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 React로 하다가 Next.js가 유행처럼 번져갈 때 내가 딱 이상태였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js 굳이 써야하나? React 만으로 충분한데?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js도 알아갈수록 SEO, 최적화 등 좋은 기능들도 많이 있지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오히려 눈을 끈건 편한 라우팅이었다 ㅋㅋㅋ&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 좋은 기능들이 많아도 이해를 못하면 제 때 못써먹는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여튼, 여러모로 느낀점이 많고 의욕도 생겼던 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 FEConf도 기대되고, 시간되면 무조건 참여할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;-끝-&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT</category>
      <category>feconf</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/787</guid>
      <comments>https://jun-coding.tistory.com/787#entry787comment</comments>
      <pubDate>Fri, 19 Sep 2025 19:12:28 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 16935번 / 배열 돌리기 3</title>
      <link>https://jun-coding.tistory.com/786</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1758008448520&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');

const [N, M, R] = input.shift().split(' ').map(Number);
const opList = input.pop().split(' ').map(Number);
let arr = input.map((row) =&amp;gt; row.split(' ').map(Number));

/**
 * 1. 배열을 상하 반전시키는 함수이다.
 */
function flipUD() {
  const totalRow = arr.length;
  const result = [];

  for (let i = totalRow - 1; i &amp;gt;= 0; i--) {
    result.push([...arr[i]]);
  }

  arr = result;
}

/**
 * 2. 배열을 좌우 반전시키는 함수이다.
 */
function flipLR() {
  const totalRow = arr.length;
  const result = [];

  for (let i = 0; i &amp;lt; totalRow; i++) {
    result.push([...arr[i]].reverse());
  }

  arr = result;
}

/**
 * 3. 오른쪽으로 90도 회전시키는 함수이다.
 */
function rotateRight() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const result = [];

  for (let j = 0; j &amp;lt; totalCol; j++) {
    const row = [];
    for (let i = totalRow - 1; i &amp;gt;= 0; i--) {
      row.push(arr[i][j]);
    }
    result.push(row);
  }

  arr = result;
}

/**
 * 4. 왼쪽으로 90도 회전시키는 함수이다.
 */
function rotateLeft() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const result = [];

  for (let j = totalCol - 1; j &amp;gt;= 0; j--) {
    const row = [];
    for (let i = 0; i &amp;lt; totalRow; i++) {
      row.push(arr[i][j]);
    }
    result.push(row);
  }

  arr = result;
}

/**
 * 5, 6번 연산을 수행하려면 배열을 크기가 N/2&amp;times;M/2인 4개의 부분 배열로 나눠야 한다.
 *
 * 5. 1번 그룹의 부분 배열을 2번 그룹 위치로, 2번을 3번으로, 3번을 4번으로, 4번을 1번으로 이동시키는 함수이다.
 */
function rotateQuadrantsClockwise() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const rowHalf = totalRow / 2;
  const colHalf = totalCol / 2;
  const result = Array.from({ length: totalRow }, () =&amp;gt;
    Array.from({ length: totalCol })
  );

  // 1번 그룹 -&amp;gt; 2번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i][j + colHalf] = arr[i][j];
    }
  }

  // 2번 그룹 -&amp;gt; 3번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; totalRow / 2; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i + rowHalf][j] = arr[i][j];
    }
  }

  // 3번 그룹 -&amp;gt; 4번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i][j - colHalf] = arr[i][j];
    }
  }

  // 4번 그룹 -&amp;gt; 1번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i - rowHalf][j] = arr[i][j];
    }
  }

  arr = result;
}

/**
 * 6. 1번 그룹의 부분 배열을 4번 그룹 위치로, 4번을 3번으로, 3번을 2번으로, 2번을 1번으로 이동시키는 함수이다.
 */
function rotateQuadrantsCounterClockwise() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const rowHalf = totalRow / 2;
  const colHalf = totalCol / 2;
  const result = Array.from({ length: totalRow }, () =&amp;gt;
    Array.from({ length: totalCol })
  );

  // 1번 그룹 -&amp;gt; 4번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i + rowHalf][j] = arr[i][j];
    }
  }

  // 2번 그룹 -&amp;gt; 1번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i][j - colHalf] = arr[i][j];
    }
  }

  // 3번 그룹 -&amp;gt; 2번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i - rowHalf][j] = arr[i][j];
    }
  }

  // 4번 그룹 -&amp;gt; 3번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i][j + colHalf] = arr[i][j];
    }
  }

  arr = result;
}

/**
 * 결과를 출력하는 함수이다.
 */
function printResult() {
  const result = arr.map((row) =&amp;gt; row.join(' ')).join('\n');

  console.log(result);
}

function solution() {
  opList.forEach((op) =&amp;gt; {
    switch (op) {
      case 1:
        flipUD();
        break;
      case 2:
        flipLR();
        break;
      case 3:
        rotateRight();
        break;
      case 4:
        rotateLeft();
        break;
      case 5:
        rotateQuadrantsClockwise();
        break;
      case 6:
        rotateQuadrantsCounterClockwise();
        break;
      default:
        break;
    }
  });

  printResult();
}

solution();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정말 문제 그대로 구현하면 되는 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, 주어지는 배열이 정사각형이 아닐 수 있으므로 인덱스를 다루는데 조심해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;회전하면 행의 개수와 열의 개수가 달라질 수도 있기 때문이다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`flipUD()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758008558837&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 1. 배열을 상하 반전시키는 함수이다.
 */
function flipUD() {
  const totalRow = arr.length;
  const result = [];

  for (let i = totalRow - 1; i &amp;gt;= 0; i--) {
    result.push([...arr[i]]);
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 1번 연산인 배열을 상하 반전시키는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존 배열의 마지막 행부터 거꾸로 새로운 배열에 넣어주었다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`flipLR()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758008620555&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 2. 배열을 좌우 반전시키는 함수이다.
 */
function flipLR() {
  const totalRow = arr.length;
  const result = [];

  for (let i = 0; i &amp;lt; totalRow; i++) {
    result.push([...arr[i]].reverse());
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2번 연산인 배열을 좌우 반전시키는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 주의할 것은 &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;reverse() 함수는 원본 배열을 바꾸기 때문에&lt;/span&gt;,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;전개 연산자를 이용해 얕은 복사를 해준 후, 반전시켜주었다.&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;font-family: 'Nanum Gothic';&quot;&gt;물론, 연산 후의 배열로 원본 배열을 대체하기 때문에 상관은 없지만&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중간에 한 번 꼬이면 힘들어지기 때문에 방어적으로 코드를 작성하였다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`rotateRight()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758008841247&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 3. 오른쪽으로 90도 회전시키는 함수이다.
 */
function rotateRight() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const result = [];

  for (let j = 0; j &amp;lt; totalCol; j++) {
    const row = [];
    for (let i = totalRow - 1; i &amp;gt;= 0; i--) {
      row.push(arr[i][j]);
    }
    result.push(row);
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3번 연산인 배열을 오른쪽으로 90도 회전시키는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;앞으로 계속 나오겠지만, `N`과 `M`이 입력에도 주어졌음에도 `totalRow`랑 `totalCol`을 따로 선언해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;배열이 정사각형이 아닐 경우, 이전 연산에 의해서 회전하면서 행과 열이 바뀔 수 있기 때문이다.&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;font-family: 'Nanum Gothic';&quot;&gt;오른쪽으로 90도 회전하게 되면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 번째 열이 첫 번째 행에 오게 되므로, 그 방향을 생각하면서 구현하면 된다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`rotateLeft()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758009588734&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 4. 왼쪽으로 90도 회전시키는 함수이다.
 */
function rotateLeft() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const result = [];

  for (let j = totalCol - 1; j &amp;gt;= 0; j--) {
    const row = [];
    for (let i = 0; i &amp;lt; totalRow; i++) {
      row.push(arr[i][j]);
    }
    result.push(row);
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4번 연산인 배열을 왼쪽으로 90도 회전시키는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막 열이 첫 번째 행에 오게 되므로, 그 방향을 생각하면서 구현하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`rotateRight()` 연산을 구현했으면 똑같은 방법으로 구현하면 되서 어렵지 않다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`rotateQuadrantsClockwise()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758009685714&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 5, 6번 연산을 수행하려면 배열을 크기가 N/2&amp;times;M/2인 4개의 부분 배열로 나눠야 한다.
 *
 * 5. 1번 그룹의 부분 배열을 2번 그룹 위치로, 2번을 3번으로, 3번을 4번으로, 4번을 1번으로 이동시키는 함수이다.
 */
function rotateQuadrantsClockwise() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const rowHalf = totalRow / 2;
  const colHalf = totalCol / 2;
  const result = Array.from({ length: totalRow }, () =&amp;gt;
    Array.from({ length: totalCol })
  );

  // 1번 그룹 -&amp;gt; 2번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i][j + colHalf] = arr[i][j];
    }
  }

  // 2번 그룹 -&amp;gt; 3번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; totalRow / 2; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i + rowHalf][j] = arr[i][j];
    }
  }

  // 3번 그룹 -&amp;gt; 4번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i][j - colHalf] = arr[i][j];
    }
  }

  // 4번 그룹 -&amp;gt; 1번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i - rowHalf][j] = arr[i][j];
    }
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5번 연산인 시계 방향으로 각 그룹을 회전하는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 그대로 네 그룹으로 나눈 뒤, 각 그룹을 따로따로 새로운 배열에 값을 넣어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인덱스만 조심하면 크게 어려울 것 없다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`rotateQuadrantsCounterClockwise()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758011077857&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 6. 1번 그룹의 부분 배열을 4번 그룹 위치로, 4번을 3번으로, 3번을 2번으로, 2번을 1번으로 이동시키는 함수이다.
 */
function rotateQuadrantsCounterClockwise() {
  const totalRow = arr.length;
  const totalCol = arr[0].length;
  const rowHalf = totalRow / 2;
  const colHalf = totalCol / 2;
  const result = Array.from({ length: totalRow }, () =&amp;gt;
    Array.from({ length: totalCol })
  );

  // 1번 그룹 -&amp;gt; 4번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i + rowHalf][j] = arr[i][j];
    }
  }

  // 2번 그룹 -&amp;gt; 1번 그룹 위치로 이동
  for (let i = 0; i &amp;lt; rowHalf; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i][j - colHalf] = arr[i][j];
    }
  }

  // 3번 그룹 -&amp;gt; 2번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = colHalf; j &amp;lt; totalCol; j++) {
      result[i - rowHalf][j] = arr[i][j];
    }
  }

  // 4번 그룹 -&amp;gt; 3번 그룹 위치로 이동
  for (let i = rowHalf; i &amp;lt; totalRow; i++) {
    for (let j = 0; j &amp;lt; colHalf; j++) {
      result[i][j + colHalf] = arr[i][j];
    }
  }

  arr = result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6번 연산인 반시계 방향으로 각 그룹을 회전시키는 연산이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5번 연산을 구현했다면, 똑같은 형태로 구현이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`printResult()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758011135816&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 결과를 출력하는 함수이다.
 */
function printResult() {
  const result = arr.map((row) =&amp;gt; row.join(' ')).join('\n');

  console.log(result);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결과를 출력하는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열을 순회하면서 출력해줘도 되지만, 한 문자열로 만든뒤 한번에 출력한 이유가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`console.log()`도 함수이기 때문에, 연산 비용이 존재한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실제로 출력해야 할 값이 많은 문제에서 따로따로 출력할 경우 시간초과가 발생하는 경우가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러기에 한 문자열로 만든 뒤 출력하는 것을 추천한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758011233082&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution() {
  opList.forEach((op) =&amp;gt; {
    switch (op) {
      case 1:
        flipUD();
        break;
      case 2:
        flipLR();
        break;
      case 3:
        rotateRight();
        break;
      case 4:
        rotateLeft();
        break;
      case 5:
        rotateQuadrantsClockwise();
        break;
      case 6:
        rotateQuadrantsCounterClockwise();
        break;
      default:
        break;
    }
  });

  printResult();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;메인 함수인 solution 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 번호에 맞는 연산 함수를 호출해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 `printResult()` 함수를 호출해 결과를 출력해주면 완성!&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>16935번</category>
      <category>js</category>
      <category>배열 돌리기 3</category>
      <category>백준</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/786</guid>
      <comments>https://jun-coding.tistory.com/786#entry786comment</comments>
      <pubDate>Tue, 16 Sep 2025 17:28:14 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 3190번 / 뱀 / JS</title>
      <link>https://jun-coding.tistory.com/785</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1757999934688&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');

let N, K, L;
const snakeDirInfo = [];
let snakeDirInfoIndex = 0;

const APPLE = 1;
const EMPTY = 0;
const SNAKE = -1;
let board;

// 상, 우, 하, 좌
const dr = [-1, 0, 1, 0];
const dc = [0, 1, 0, -1];

function init() {
  N = +input.shift();
  K = +input.shift();

  board = Array.from({ length: N }, () =&amp;gt;
    Array.from({ length: N }, () =&amp;gt; EMPTY)
  );

  for (let i = 0; i &amp;lt; K; i++) {
    const [row, col] = input.shift().split(' ').map(Number);
    board[row - 1][col - 1] = APPLE;
  }

  L = +input.shift();

  for (let i = 0; i &amp;lt; L; i++) {
    const [X, C] = input.shift().split(' ');
    snakeDirInfo.push([+X, C]);
  }
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; N;
}

function play() {
  const queue = [[0, 0]];
  let curDir = 1; // 뱀은 처음에 오른쪽을 향한다.
  let seconds = 0;

  board[0][0] = SNAKE;

  while (true) {
    seconds++;

    const [headRow, headCol] = queue.at(-1);
    const [tailRow, tailCol] = queue[0];
    const [nr, nc] = [headRow + dr[curDir], headCol + dc[curDir]];

    // 벽에 부딪히면 게임을 종료한다.
    if (!isValid(nr, nc)) {
      return seconds;
    }

    // 뱀이 자기 몸에 부딪히면 게임을 종료한다.
    if (board[nr][nc] === SNAKE) {
      return seconds;
    } else if (board[nr][nc] === APPLE) {
      // 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
      board[nr][nc] = SNAKE;
    } else {
      // 만약 이동한 칸에 사과가 없다면, 몸 길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸 길이는 변하지 않는다.
      board[nr][nc] = SNAKE;
      board[tailRow][tailCol] = EMPTY;
      queue.shift();
    }

    queue.push([nr, nc]);

    // 방향 전환 정보가 있으면 방향 전환한다.
    if (snakeDirInfoIndex &amp;lt; snakeDirInfo.length) {
      const [X, C] = snakeDirInfo[snakeDirInfoIndex];

      // 방향 전환 시간이 되면 방향 전환한다.
      if (X === seconds) {
        if (C === 'L') {
          // 왼쪽으로 방향 전환한다.
          curDir = curDir - 1 &amp;lt; 0 ? 3 : curDir - 1;
        } else if (C === 'D') {
          // 오른쪽으로 방향 전환한다.
          curDir = (curDir + 1) % 4;
        }
        // 다음 방향 전환 정보 인덱스를 증가시킨다.
        snakeDirInfoIndex++;
      }
    }
  }
}

function solution() {
  init();
  const seconds = play();

  console.log(seconds);
}

solution();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일반적인 구현 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구현하다보니 코드가 길어져서 함수를 분리해서 작성했다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;변수들&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758000063954&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs.readFileSync(filePath).toString().trim().split('\n');

let N, K, L;
const snakeDirInfo = [];
let snakeDirInfoIndex = 0;

const APPLE = 1;
const EMPTY = 0;
const SNAKE = -1;
let board;

// 상, 우, 하, 좌
const dr = [-1, 0, 1, 0];
const dc = [0, 1, 0, -1];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;N: 보드의 크기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;K: 사과의 개수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;L: 뱀의 방향 변환 횟수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;snakeDirInfo: 뱀의 방향 전환 정보를 담는 배열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;snakeDirInfoIndex: snakeDirInfo 배열에서 현재 어느 방향 전환 정보를 참조하고 있는지 확인하는 인덱스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;APPLE, EMPTY, SNAKE: 각각 board에 사과, 빈 공간, 뱀인지 상태를 나타낼 변수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;board: 보드의 상태를 나타내는 2차원 배열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;dr, dc: 사방으로 이동하는 정보&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`init()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758000360485&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function init() {
  N = +input.shift();
  K = +input.shift();

  board = Array.from({ length: N }, () =&amp;gt;
    Array.from({ length: N }, () =&amp;gt; EMPTY)
  );

  for (let i = 0; i &amp;lt; K; i++) {
    const [row, col] = input.shift().split(' ').map(Number);
    board[row - 1][col - 1] = APPLE;
  }

  L = +input.shift();

  for (let i = 0; i &amp;lt; L; i++) {
    const [X, C] = input.shift().split(' ');
    snakeDirInfo.push([+X, C]);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 필요한 정보들을 문제의 입력에 맞게 초기화하는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`board`는 일단 빈 칸으로 모두 초기화해준 뒤, 주어진 사과 위치에 맞춰서 값을 초기화해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제는 좌상단이 1행 1열로 주어지지만, 배열은 0행 0열로 시작하므로 1씩 빼주어야 하는것에 주의하자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그 다음으로는 X는 숫자지만, 입력받을 때 문자열로 되기 때문에 숫자로 바꿔서 저장해주자.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`isValid()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758000789445&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; N;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열을 다루게 된다면 꼭 구현하게 되는 범위 체크 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;많이 사용하는 함수니, 본인 스타일대로 구현하면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;사실 예전엔 명확히 하기 위해 다음과 같이 구현했었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1758000931157&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function isValid(row, col) {
  if (row &amp;lt; 0 || row &amp;gt;= N) {
    return false;
  }
  if (col &amp;lt; 0 || col &amp;gt;= N) {
    return false;
  }

  return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나중엔 빠르게 짜고 싶어서 한줄로 구현했지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 알고리즘에 익숙하지 않는 초보자라면 명확히 나타내주는게 좋은 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;알고리즘이라 그렇지, 만약에 프로젝트에서 유틸함수를 구현한다고 하면 위와 같이 구현할 것 같다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`play()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758001046164&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function play() {
  const queue = [[0, 0]];
  let curDir = 1; // 뱀은 처음에 오른쪽을 향한다.
  let seconds = 0;

  board[0][0] = SNAKE;

  while (true) {
    seconds++;

    const [headRow, headCol] = queue.at(-1);
    const [tailRow, tailCol] = queue[0];
    const [nr, nc] = [headRow + dr[curDir], headCol + dc[curDir]];

    // 벽에 부딪히면 게임을 종료한다.
    if (!isValid(nr, nc)) {
      return seconds;
    }

    // 뱀이 자기 몸에 부딪히면 게임을 종료한다.
    if (board[nr][nc] === SNAKE) {
      return seconds;
    } else if (board[nr][nc] === APPLE) {
      // 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
      board[nr][nc] = SNAKE;
    } else {
      // 만약 이동한 칸에 사과가 없다면, 몸 길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸 길이는 변하지 않는다.
      board[nr][nc] = SNAKE;
      board[tailRow][tailCol] = EMPTY;
      queue.shift();
    }

    queue.push([nr, nc]);

    // 방향 전환 정보가 있으면 방향 전환한다.
    if (snakeDirInfoIndex &amp;lt; snakeDirInfo.length) {
      const [X, C] = snakeDirInfo[snakeDirInfoIndex];

      // 방향 전환 시간이 되면 방향 전환한다.
      if (X === seconds) {
        if (C === 'L') {
          // 왼쪽으로 방향 전환한다.
          curDir = curDir - 1 &amp;lt; 0 ? 3 : curDir - 1;
        } else if (C === 'D') {
          // 오른쪽으로 방향 전환한다.
          curDir = (curDir + 1) % 4;
        }
        // 다음 방향 전환 정보 인덱스를 증가시킨다.
        snakeDirInfoIndex++;
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;메인 로직인 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;핵심 아이디어는, &lt;b&gt;queue에 뱀이 있는 좌표를 모두 넣어주는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에 뱀은 0행 0열에서 시작하므로 queue에 [0, 0]을 넣어주고 시작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 뒤로는 문제대로 쭉 구현해주면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;주의할 것은 방향전환 할 때이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제에서 방향 전환은 X초가 끝난 후에 한다고 나와있기 때문에 마지막에 해주어야 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 어이없이 헤맸던게 있는데...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왼쪽 방향전환이 'L'이라서 Left의 첫번째 알파벳이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오른쪽이 당연히 'R'인줄 알고 'R'로 문제를 풀다가 계속 답이 틀렸다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오른쪽은 'R'이 아니라 'D'입니다!!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1758001786100&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution() {
  init();
  const seconds = play();

  console.log(seconds);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;함수를 분리해놔서 메인 함수는 깔끔하게 구성할 수 있었다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>3190번</category>
      <category>js</category>
      <category>백준</category>
      <category>뱀</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/785</guid>
      <comments>https://jun-coding.tistory.com/785#entry785comment</comments>
      <pubDate>Tue, 16 Sep 2025 14:50:18 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 단속카메라 / JS</title>
      <link>https://jun-coding.tistory.com/784</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42884&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42884&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757664063454&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42884&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cFG8CQ/hyZJiFiyjO/KHwUuMBmz6OoGmX75wz6eK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/WcJfv/hyZIOltQWU/rKr6Vne6BGZfrMTEJAYhX1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42884&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42884&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cFG8CQ/hyZJiFiyjO/KHwUuMBmz6OoGmX75wz6eK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/WcJfv/hyZIOltQWU/rKr6Vne6BGZfrMTEJAYhX1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제분석&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 문제는 전형적인 &lt;b&gt;구간 스케줄링&lt;/b&gt; 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 구간이 주어졌을 때, 모든 구간을 커버하는 최소한의 점을 찾는 것과 같다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;직관적인 접근법&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;차량들의 경로를 구간으로 생각한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;겹치는 구간들은 하나의 카메라로 처리가 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;겹치지 않는 구간들은 각각 별도의 카메라가 필요하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;핵심 아이디어:&lt;/b&gt; 진출 기점을 기준으로 정렬한 후, greedy하게 카메라 위치를 선택한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757664086635&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(routes) {
  routes.sort((a, b) =&amp;gt; a[1] - b[1]);
  let cameraCount = 0;
  let cameraPosition = -30001;

  for (const [from, to] of routes) {
    if (from &amp;gt; cameraPosition) {
      cameraPosition = to;
      cameraCount++;
    }
  }

  return cameraCount;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;왜 진출 기점 기준일까?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;해당 구간을 반드시 커버해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;진출 지점에 카메라를 두면, 이후 구간들과의 겹침을 최대화한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>단속카메라</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/784</guid>
      <comments>https://jun-coding.tistory.com/784#entry784comment</comments>
      <pubDate>Fri, 12 Sep 2025 17:06:08 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 정수 삼각형 / JS</title>
      <link>https://jun-coding.tistory.com/783</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43105&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43105&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757513795415&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43105&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cCttbE/hyZIZ1bCXy/jDot3YNvg92AGykDtezv01/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bOE2KG/hyZI2Xb46M/N5KkTy8NuMVfcNljuFB0Z0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43105&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43105&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cCttbE/hyZIZ1bCXy/jDot3YNvg92AGykDtezv01/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bOE2KG/hyZI2Xb46M/N5KkTy8NuMVfcNljuFB0Z0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1757513838366&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(triangle) {
  const height = triangle.length;
  const dp = Array.from({ length: height }, (_, i) =&amp;gt; Array(i + 1));
  dp[0][0] = triangle[0][0];

  for (let i = 1; i &amp;lt; height; i++) {
    for (let j = 0; j &amp;lt; triangle[i].length; j++) {
      dp[i][j] =
        Math.max(dp[i - 1][j - 1] ?? 0, dp[i - 1][j] ?? 0) + triangle[i][j];
    }
  }

  return Math.max(...dp[height - 1]);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 자체는 간단하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주어진 triangle 배열과 똑같은 형태의 배열을 선언해주고 dp로 풀었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;dp로 이전 행의 좌, 우를 비교해서 더 큰 값에 현재 위치의 값을 더해주면 된다.&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;font-family: 'Nanum Gothic';&quot;&gt;여기서, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;각 행의 가장 왼쪽과 오른쪽에 있는 값들은 각각 이전 행의 왼쪽과 오른쪽은 범위를 벗어나게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;따라서 범위를 벗어나게 될 경우의 처리가 중요하다.&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;font-family: 'Nanum Gothic';&quot;&gt;여기서 '널 병합 연산자(??)'를 사용하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;'널 병합 연산자'는 왼쪽 피연산자가 `null`또는 `undefined`일 때 오른쪽 피연산자를 반환하고,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그렇지 않으면 왼쪽 피연산자를 반환하는 논리 연산자이다.&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;font-family: 'Nanum Gothic';&quot;&gt;배열의 범위를 벗어난 인덱스를 참조할 경우, `undefined`가 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 널 병합 연산자를 통해서 그럴 경우엔 0으로 임시 값을 주는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(삼각형 주변에 0 padding을 둘러싼 효과라고 생각하면 편할 것 같다.)&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;font-family: 'Nanum Gothic';&quot;&gt;물론 falsy 값을 잡아내는 그냥 `or(||)`연산자를 사용해도 되지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 문제에서는 정확히 `undefined`의 값만 판별하면 되므로 '??'를 사용하였다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>정수 삼각형</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/783</guid>
      <comments>https://jun-coding.tistory.com/783#entry783comment</comments>
      <pubDate>Wed, 10 Sep 2025 23:32:45 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 2 / 가장 큰 수 / JS</title>
      <link>https://jun-coding.tistory.com/782</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42746&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42746&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757425820456&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42746&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/btkrN2/hyZJcL8k2H/KuJdeio5PxFgxAjyEcQznk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/c5f3p2/hyZIVc7hhi/OcldYKRJgOm0KBhENJzc0k/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42746&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42746&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/btkrN2/hyZJcL8k2H/KuJdeio5PxFgxAjyEcQznk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/c5f3p2/hyZIVc7hhi/OcldYKRJgOm0KBhENJzc0k/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1757425843515&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(numbers) {
  const result = numbers
    .map(String)
    .sort((a, b) =&amp;gt; (b + a).localeCompare(a + b))
    .join('');

  return result[0] === '0' ? '0' : result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이는 정말 간단하고, 특히 sort 부분에는 정말 다양한 풀이가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, 여기서는 localeCompare를 사용했는데, 그 이유는 다음과 같다.&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;font-family: 'Nanum Gothic';&quot;&gt;기본적으로 sort() 메서드는 반환값이 음수, 0, 양수인지에 따라 정렬이 달라지게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리가 보통 숫자 배열을 정렬할 때 다음과 같이 많이 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757425948602&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;numbers.sort((a, b) =&amp;gt; a - b);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 numbers 배열이 [3,4,1,5,8] 라고 할 때, 결과는 [1,3,4,5,8]과 같이 오름차순으로 정렬된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 순회에서 3과 4를 비교해서 (3 - 4)를 하면 음수가 나오기 때문에 3이 4보다 작다고 판단해서 그대로 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음 순회는 (4 - 1)을 해서 양수기 때문에 앞에 있는 4가 1보다 크다고 판단해서 자리가 바뀌게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;기본적으로 sort() 메서드는 문자열 비교&lt;/b&gt;&lt;/span&gt;를 하기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문자열 연산이 아니라 숫자 크기 비교를 위해서 뺄셈 연산으로 크기 비교를 해주는 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;하지만, 이 문제는 숫자를 더하는 것이 아니라 '붙여서' 비교를 해야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 문자열로 모두 바꾼 뒤에, (앞 + 뒤)와 (뒤 + 앞)을 붙여서 비교를 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이때 단순히 '&amp;gt;'와 같은 부등호를 사용하게 되면 true나 false값이 나오기 때문에 제대로 된 비교가 안된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왜냐하면 sort는 양수, 음수로 정렬을 판단하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;따라서 `localeCompare()`를 사용하면 반환값이 음수, 0, 양수 중 하나이기 때문에 제대로 된 정렬이 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 2</category>
      <category>programmers</category>
      <category>가장 큰 수</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/782</guid>
      <comments>https://jun-coding.tistory.com/782#entry782comment</comments>
      <pubDate>Tue, 9 Sep 2025 23:01:36 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 2 / 양궁대회 / JS</title>
      <link>https://jun-coding.tistory.com/781</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/92342&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/92342&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757317621051&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/92342&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/oQVA7/hyZGmpCmDp/kvBUQZkjDSBenlU8A3dNMK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/qtH7b/hyZIZfe1Dx/9xFgGCKkp26XYe9W1NzAb0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/92342&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/92342&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/oQVA7/hyZGmpCmDp/kvBUQZkjDSBenlU8A3dNMK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/qtH7b/hyZIZfe1Dx/9xFgGCKkp26XYe9W1NzAb0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 분석&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 문제는 고려할 것이 많기 때문에, 문제를 잘 읽어야 헷갈리지 않고 풀 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 많이 맞춘쪽이 해당 점수를 가져간다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;여러발 맞춰도 맞춘만큼 가져가는 것이 아닌, 해당 점수 한 번만 가져간다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;똑같이 맞췄다면 어피치가 해당 점수를 가져간다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;'최대 점수'가 아닌, '최대 점수 차이'를 가지는 결과를 구해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'최대 점수 차이'를 가지는 방법이 여러개라면, 낮은 점수를 많이 맞춘 방법을 반환한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에 보라색으로 된 것을 놓치거나, 헷갈릴 수 있으니 주의하면서 문제를 풀어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1757317906218&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, info) {
  const apeachInfo = [...info];
  const lionInfo = Array.from({ length: 11 }, () =&amp;gt; 0);
  let result = [-1];
  let maxDiff = -Infinity;

  function getTotalScore() {
    let apeachTotalScore = 0;
    let lionTotalScore = 0;

    for (let i = 0; i &amp;lt; 11; i++) {
      const curScore = 10 - i;

      if (lionInfo[i] &amp;gt; apeachInfo[i]) {
        lionTotalScore += curScore;
      } else if (apeachInfo[i] &amp;gt; 0) {
        apeachTotalScore += curScore;
      }
    }

    return { apeachTotalScore, lionTotalScore };
  }

  function isMoreLowerScore(arr1, arr2) {
    for (let i = 10; i &amp;gt;= 0; i--) {
      if (arr1[i] !== arr2[i]) {
        return arr1[i] &amp;gt; arr2[i];
      }
    }

    return false;
  }

  function dfs(scoreIndex, remainArrows, lionInfo) {
    if (scoreIndex === 11) {
      lionInfo[10] = remainArrows;

      const { apeachTotalScore, lionTotalScore } = getTotalScore();
      const diff = lionTotalScore - apeachTotalScore;

      if (
        diff &amp;gt; 0 &amp;amp;&amp;amp;
        (diff &amp;gt; maxDiff ||
          (diff === maxDiff &amp;amp;&amp;amp; isMoreLowerScore(lionInfo, result)))
      ) {
        maxDiff = diff;
        result = [...lionInfo];
      }

      return;
    }

    // 현재 점수를 포기하는 경우
    dfs(scoreIndex + 1, remainArrows, lionInfo);

    // 현재 점수를 가져가는 경우
    const needArrows = apeachInfo[scoreIndex] + 1;

    // 남은 화살이 필요한 화살만큼 있을경우
    if (remainArrows &amp;gt;= needArrows) {
      lionInfo[scoreIndex] = needArrows;
      dfs(scoreIndex + 1, remainArrows - needArrows, lionInfo);
      lionInfo[scoreIndex] = 0;
    }
  }

  dfs(0, n, lionInfo);

  return result;
}&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`getTotalScore()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757317940426&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function getTotalScore() {
    let apeachTotalScore = 0;
    let lionTotalScore = 0;

    for (let i = 0; i &amp;lt; 11; i++) {
      const curScore = 10 - i;

      if (lionInfo[i] &amp;gt; apeachInfo[i]) {
        lionTotalScore += curScore;
      } else if (apeachInfo[i] &amp;gt; 0) {
        apeachTotalScore += curScore;
      }
    }

    return { apeachTotalScore, lionTotalScore };
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어피치와 라이언의 총 점수를 구하는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 라이언이 어피치보다 더 많이 맞췄으면 라이언이 해당 점수를 가져간다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그렇지 않고, 어피치가 라이언과 똑같이 맞췄거나 더 많이 맞췄을 경우에는 어피치가 점수를 가져간다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘다 0개로 맞추지 않았을 경우에는 둘다 점수를 얻지 않으므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;else if에 0보다 클 때의 조건을 넣어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`isMoreLowerScore(arr1, arr2)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757340612896&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function isMoreLowerScore(arr1, arr2) {
    for (let i = 10; i &amp;gt;= 0; i--) {
      if (arr1[i] !== arr2[i]) {
        return arr1[i] &amp;gt; arr2[i];
      }
    }

    return false;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&quot;라이언이 가장 큰 점수 차이로 우승할 수 있는 방법이 여러 가지 일 경우, 가장 낮은 점수를 더 많이 맞힌 경우를 return 해주세요.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라는 조건이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 배열은 10점, 9점, 8점, ... , 0점이 0, 1, 2, ... 10의 인덱스를 가지므로 역순으로 순회한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 arr1과 arr2가 과녁의 맞춘 화살의 개수가 다를 경우, arr1이 더 많이 맞췄다면 true를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모두 arr2가 더 많이 맞췄다면 false를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`dfs(scoreIndex, remainArrows, lionInfo)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757340840956&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  function dfs(scoreIndex, remainArrows, lionInfo) {
    if (scoreIndex === 11) {
      lionInfo[10] = remainArrows;

      const { apeachTotalScore, lionTotalScore } = getTotalScore();
      const diff = lionTotalScore - apeachTotalScore;

      if (
        diff &amp;gt; 0 &amp;amp;&amp;amp;
        (diff &amp;gt; maxDiff ||
          (diff === maxDiff &amp;amp;&amp;amp; isMoreLowerScore(lionInfo, result)))
      ) {
        maxDiff = diff;
        result = [...lionInfo];
      }

      return;
    }

    // 현재 점수를 포기하는 경우
    dfs(scoreIndex + 1, remainArrows, lionInfo);

    // 현재 점수를 가져가는 경우
    const needArrows = apeachInfo[scoreIndex] + 1;

    // 남은 화살이 필요한 화살만큼 있을경우
    if (remainArrows &amp;gt;= needArrows) {
      lionInfo[scoreIndex] = needArrows;
      dfs(scoreIndex + 1, remainArrows - needArrows, lionInfo);
      lionInfo[scoreIndex] = 0;
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;dfs로 풀이를 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 배열 끝까지 도달했을 경우, 즉 scoreIndex가 11일 경우에 남은 화살을 전부 0점으로 설정해준다.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 위에서 구현한 getTotalScore() 함수를 통해서 라이언과 어피치의 점수차를 구해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;점수차가 현재까지 구한 최대 점수차보다 크거나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최대 점수차와 같지만 더 낮은 점수를 많이 맞춘 경우에는 답을 교체해준다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 다음 dfs로 넘어가는 경우에는 두 가지 경우가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 점수를 얻거나, 얻지 않는 경우.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 점수를 가져가지 않는 경우에는 단순히 인덱스만 하나 더해주고 다음 재귀로 넘어가면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 점수를 가져가는 경우에는 남은 화살이 어피치를 이기기 위해 필요한 화살만큼 있을 경우에는,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;남아있는 화살에서 필요한 화살만큼 빼준 후에 다음 재귀로 넘어가면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 다음으로 넘어가는 재귀가 답이 아닐 수도 있기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;재귀가 끝나고 다시 돌아왔을 때는 0으로 다시 초기화해준다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 2</category>
      <category>programmers</category>
      <category>양궁대회</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/781</guid>
      <comments>https://jun-coding.tistory.com/781#entry781comment</comments>
      <pubDate>Mon, 8 Sep 2025 23:42:50 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 2 / 전력망을 둘로 나누기 / JS</title>
      <link>https://jun-coding.tistory.com/780</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/86971&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/86971&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1757039949164&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/86971&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/q8itK/hyZITyTNn2/FR5dKi3xpT0yYmek03nIS1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bCOcjA/hyZIRVoWIY/DIukKUDuYNUUKCVnRCP0U1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/86971&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/86971&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/q8itK/hyZITyTNn2/FR5dKi3xpT0yYmek03nIS1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/bCOcjA/hyZIRVoWIY/DIukKUDuYNUUKCVnRCP0U1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mlgTc/btsQmydVFnk/QD64RI2EKg75SFL4mXpiY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mlgTc/btsQmydVFnk/QD64RI2EKg75SFL4mXpiY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mlgTc/btsQmydVFnk/QD64RI2EKg75SFL4mXpiY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmlgTc%2FbtsQmydVFnk%2FQD64RI2EKg75SFL4mXpiY0%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;549&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1757039990646&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 인접리스트를 초기화하는 함수이다.
 *
 * @param {number[][]} wires 전선 정보
 * @returns {Map&amp;lt;number, Set&amp;lt;number&amp;gt;&amp;gt;} 인접리스트
 */
function initAdjList(wires) {
  const adjList = new Map();

  wires.forEach(([tower1, tower2]) =&amp;gt; {
    if (adjList.has(tower1)) {
      adjList.get(tower1).add(tower2);
    } else {
      adjList.set(tower1, new Set([tower2]));
    }

    if (adjList.has(tower2)) {
      adjList.get(tower2).add(tower1);
    } else {
      adjList.set(tower2, new Set([tower1]));
    }
  });

  return adjList;
}

/**
 * bfs를 이용해 한 쪽 송전탑의 개수를 구하는 함수이다.
 *
 * @param {number} n 송전탑의 개수
 * @param {Map&amp;lt;number, Set&amp;lt;number&amp;gt;&amp;gt;} adjList 인접리스트
 * @returns 두 전력망으로 나누었을 때, 한 쪽의 송전탑의 개수
 */
function bfs(n, adjList) {
  // 임의로 1번 송전탑에서 시작한다.
  const queue = [1];
  const visited = Array.from({ length: n + 1 }, () =&amp;gt; false);
  let count = 1;

  visited[1] = true;

  while (queue.length &amp;gt; 0) {
    const curTower = queue.shift();

    for (const nextTower of adjList.get(curTower)) {
      if (visited[nextTower]) {
        continue;
      }

      visited[nextTower] = true;
      queue.push(nextTower);
      count++;
    }
  }

  return count;
}

function solution(n, wires) {
  const adjList = initAdjList(wires);
  let result = Infinity;

  for (const [tower1, tower2] of wires) {
    // tower1과 tower2에 연결된 전선을 끊어준다.
    adjList.get(tower1).delete(tower2);
    adjList.get(tower2).delete(tower1);
    const count1 = bfs(n, adjList);
    const count2 = n - count1;
    // 위에서 끊어준 전선을 다시 이어준다.
    adjList.get(tower1).add(tower2);
    adjList.get(tower2).add(tower1);

    const diff = Math.abs(count1 - count2);
    result = Math.min(result, diff);
  }

  return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;핵심 로직은 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;모든 전선을 하나씩 끊어보면서 나뉘어진 송전탑의 개수를 세주었다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래프는 인접리스트로 구현해주었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수정, 삭제가 용이하도록 Map과 Set 자료구조를 이용해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`initAdjList(wires)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757040125019&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 인접리스트를 초기화하는 함수이다.
 *
 * @param {number[][]} wires 전선 정보
 * @returns {Map&amp;lt;number, Set&amp;lt;number&amp;gt;&amp;gt;} 인접리스트
 */
function initAdjList(wires) {
  const adjList = new Map();

  wires.forEach(([tower1, tower2]) =&amp;gt; {
    if (adjList.has(tower1)) {
      adjList.get(tower1).add(tower2);
    } else {
      adjList.set(tower1, new Set([tower2]));
    }

    if (adjList.has(tower2)) {
      adjList.get(tower2).add(tower1);
    } else {
      adjList.set(tower2, new Set([tower1]));
    }
  });

  return adjList;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인접리스트를 초기화하는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Map 자료구조를 이용해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;key는 송전탑, value는 key와 이어진 송전탑들을 Set 자료구조로 저장해주었다.&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;font-family: 'Nanum Gothic';&quot;&gt;Set을 사용한 이유는,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;delete()로 전선을 끊고, add()로 다시 전선을 붙이기 용이하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`bfs(n, adjList)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757040317096&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * bfs를 이용해 한 쪽 송전탑의 개수를 구하는 함수이다.
 *
 * @param {number} n 송전탑의 개수
 * @param {Map&amp;lt;number, Set&amp;lt;number&amp;gt;&amp;gt;} adjList 인접리스트
 * @returns 두 전력망으로 나누었을 때, 한 쪽의 송전탑의 개수
 */
function bfs(n, adjList) {
  // 임의로 1번 송전탑에서 시작한다.
  const queue = [1];
  const visited = Array.from({ length: n + 1 }, () =&amp;gt; false);
  let count = 1;

  visited[1] = true;

  while (queue.length &amp;gt; 0) {
    const curTower = queue.shift();

    for (const nextTower of adjList.get(curTower)) {
      if (visited[nextTower]) {
        continue;
      }

      visited[nextTower] = true;
      queue.push(nextTower);
      count++;
    }
  }

  return count;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나뉘어진 전력망에서 연결된 송전탑의 개수는 bfs로 구해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 시작은 임의로 1번 송전탑에서 시작했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어차피 이어진 송전탑은 다 탐색하기 때문에 아무 송전탑에서 시작해도 상관은 없다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution(n, wires)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1757040444354&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, wires) {
  const adjList = initAdjList(wires);
  let result = Infinity;

  for (const [tower1, tower2] of wires) {
    // tower1과 tower2에 연결된 전선을 끊어준다.
    adjList.get(tower1).delete(tower2);
    adjList.get(tower2).delete(tower1);
    const count1 = bfs(n, adjList);
    const count2 = n - count1;
    // 위에서 끊어준 전선을 다시 이어준다.
    adjList.get(tower1).add(tower2);
    adjList.get(tower2).add(tower1);

    const diff = Math.abs(count1 - count2);
    result = Math.min(result, diff);
  }

  return result;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 전선을 순회하면서, 하나씩 끊어보면서 개수를 세준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주의할 것은 &lt;b&gt;다음 전선을 끊을 때는 이전에 끊었던 전선을 다시 붙여주어야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;bfs로 한 쪽 전력망의 송전탑 개수를 구해줬다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;총 송전탑의 개수에서 빼면 다른 쪽 전력망의 송전탑 개수를 구할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 2</category>
      <category>programmers</category>
      <category>전력망을 둘로 나누기</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/780</guid>
      <comments>https://jun-coding.tistory.com/780#entry780comment</comments>
      <pubDate>Fri, 5 Sep 2025 11:49:58 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 경주로 건설 / JS</title>
      <link>https://jun-coding.tistory.com/779</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/67259&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1756990351301&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/CXGPl/hyZHaanCzD/5uKl3rZsGwWP5SkdKMkxbK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/GDlqw/hyZINrQIfq/kS9rYNeBZ0jzBeXhA4QTP1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/67259&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/CXGPl/hyZHaanCzD/5uKl3rZsGwWP5SkdKMkxbK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/GDlqw/hyZINrQIfq/kS9rYNeBZ0jzBeXhA4QTP1/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제분석&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c27gRx/btsQkh5Hv1f/zaNHTBhyErsjvki97ANZqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c27gRx/btsQkh5Hv1f/zaNHTBhyErsjvki97ANZqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c27gRx/btsQkh5Hv1f/zaNHTBhyErsjvki97ANZqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc27gRx%2FbtsQkh5Hv1f%2FzaNHTBhyErsjvki97ANZqk%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;1000&quot; height=&quot;1000&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;직선도로에서는 100의 비용이 들고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코너에서는 500의 비용이 든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;처음에 헷갈려서 틀렸었는데, '코너를 만드는데 드는 비용'이 500이므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코너를 만들고 앞으로 한 칸 나아가려면 총 600의 비용이 든다.&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;font-family: 'Noto Sans Light';&quot;&gt;또한, 어느 방향에서 왔는지에 따라 같은 칸이라도 비용이 다르게 들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;따라서 일반적인 방문처리를 하는 bfs로는 풀이가 불가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1756994435540&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const EMPTY = 0;
const WALL = 1;

const STRAIGHT_COST = 100;
// 코너를 건설하는 값 + 앞으로 한 칸 나아가는 값
const CORNER_COST = 500 + STRAIGHT_COST;

// 상, 우, 하, 좌
const dr = [-1, 0, 1, 0];
const dc = [0, 1, 0, -1];

let N;

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; N;
}

function bfs(board) {
  // [행, 열, 방향, 금액]
  const queue = [];
  const visited = Array.from({ length: N }, () =&amp;gt;
    Array.from({ length: N }, () =&amp;gt; Array(4).fill(Infinity))
  );

  if (board[1][0] === EMPTY) {
    queue.push([1, 0, 2, STRAIGHT_COST]);
    visited[1][0][2] = STRAIGHT_COST;
  }
  if (board[0][1] === EMPTY) {
    queue.push([0, 1, 1, STRAIGHT_COST]);
    visited[0][1][1] = STRAIGHT_COST;
  }

  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curDir, curCost] = queue.shift();

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      // 배열 범위를 벗어날 경우 스킵한다.
      if (!isValid(nr, nc)) {
        continue;
      }
      // 벽일 경우 스킵한다.
      if (board[nr][nc] === WALL) {
        continue;
      }

      // 이전과 다른 방향일 경우, 코너이기 때문에 비용이 증가한다.
      const newCost =
        curDir === d ? curCost + STRAIGHT_COST : curCost + CORNER_COST;

      // 이미 더 적은 비용으로 방문한적이 있다면 스킵한다.
      if (visited[nr][nc][d] &amp;lt;= newCost) {
        continue;
      }

      visited[nr][nc][d] = newCost;
      queue.push([nr, nc, d, newCost]);
    }
  }

  let minCost = Math.min(...visited[N - 1][N - 1]);
  return minCost;
}

function solution(board) {
  N = board.length;

  let minCost = bfs(board);
  return minCost;
}&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;`isValid(row, col)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1756994518390&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; N;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 있는 행 또는 열이 배열의 범위를 벗어나지 않았는지 판단하는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;`bfs(board)`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1756994979779&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function bfs(board) {
  // [행, 열, 방향, 금액]
  const queue = [];
  const visited = Array.from({ length: N }, () =&amp;gt;
    Array.from({ length: N }, () =&amp;gt; Array(4).fill(Infinity))
  );

  if (board[1][0] === EMPTY) {
    queue.push([1, 0, 2, STRAIGHT_COST]);
    visited[1][0][2] = STRAIGHT_COST;
  }
  if (board[0][1] === EMPTY) {
    queue.push([0, 1, 1, STRAIGHT_COST]);
    visited[0][1][1] = STRAIGHT_COST;
  }

  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curDir, curCost] = queue.shift();

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      // 배열 범위를 벗어날 경우 스킵한다.
      if (!isValid(nr, nc)) {
        continue;
      }
      // 벽일 경우 스킵한다.
      if (board[nr][nc] === WALL) {
        continue;
      }

      // 이전과 다른 방향일 경우, 코너이기 때문에 비용이 증가한다.
      const newCost =
        curDir === d ? curCost + STRAIGHT_COST : curCost + CORNER_COST;

      // 이미 더 적은 비용으로 방문한적이 있다면 스킵한다.
      if (visited[nr][nc][d] &amp;lt;= newCost) {
        continue;
      }

      visited[nr][nc][d] = newCost;
      queue.push([nr, nc, d, newCost]);
    }
  }

  let minCost = Math.min(...visited[N - 1][N - 1]);
  return minCost;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;bfs로 얻은 결과를 반환해주는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드가 한 번에 보기 어려우므로 쪼개서 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756995036099&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// [행, 열, 방향, 금액]
const queue = [];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;bfs의 기본 시작은 큐를 만들어주고, 방문 처리할 배열을 만들어주는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;큐에는 [행, 열, 방향, 금액]을 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기서 방향은 간단히 방향 배열의 인덱스로 판단해준다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;(상: 0, 우: 1, 하: 2, 좌: 3)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1756995203125&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 상, 우, 하, 좌
const dr = [-1, 0, 1, 0];
const dc = [0, 1, 0, -1];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756995339363&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const visited = Array.from({ length: N }, () =&amp;gt;
  Array.from({ length: N }, () =&amp;gt; Array(4).fill(Infinity))
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다만, 여기서 방문 처리할 배열은 기본 2차원이 아닌 &lt;b&gt;3차원&lt;/b&gt;으로 만들어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 칸에 도달하면, 몇 번의 코너를 거쳤는지에 따라 총 가격이 다르게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;따라서 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;현재 칸의 어느 방향에서 왔는지를 각 4칸(상, 우, 하, 좌)에 저장&lt;/b&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;pre id=&quot;code_1756995401389&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  if (board[1][0] === EMPTY) {
    queue.push([1, 0, 2, STRAIGHT_COST]);
    visited[1][0][2] = STRAIGHT_COST;
  }
  if (board[0][1] === EMPTY) {
    queue.push([0, 1, 1, STRAIGHT_COST]);
    visited[0][1][1] = STRAIGHT_COST;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다음으로, 첫 시작을 넣어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;처음 시작은 무조건 [0][0]에서 한다고 문제에 나와있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그러면, 다음으로 갈 수 있는 칸은 바로 아래 칸이나 오른쪽 칸이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;무조건 갈 수 있는건 아니고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해당 칸이 벽으로 막혀있지 않은지, 즉 빈 칸인 경우에만 큐에 넣어주고 방문처리를 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756995531636&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curDir, curCost] = queue.shift();

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      // 배열 범위를 벗어날 경우 스킵한다.
      if (!isValid(nr, nc)) {
        continue;
      }
      // 벽일 경우 스킵한다.
      if (board[nr][nc] === WALL) {
        continue;
      }

      // 이전과 다른 방향일 경우, 코너이기 때문에 비용이 증가한다.
      const newCost =
        curDir === d ? curCost + STRAIGHT_COST : curCost + CORNER_COST;

      // 이미 더 적은 비용으로 방문한적이 있다면 스킵한다.
      if (visited[nr][nc][d] &amp;lt;= newCost) {
        continue;
      }

      visited[nr][nc][d] = newCost;
      queue.push([nr, nc, d, newCost]);
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;bfs의 핵심 로직이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다른건 다 같지만, 마지막 조건 검사 부분이 일반적인 bfs와 다르다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Noto Sans Light';&quot;&gt;만약 현재 진행중이던 방향과 다른 방향이라면,&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Noto Sans Light';&quot;&gt;코너를 돌았다는 뜻이므로, 해당 경우에만 코너 값을 더해준다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 이미 더 적은 비용으로 방문한적이 있다면 스킵한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1756995605580&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let minCost = Math.min(...visited[N - 1][N - 1]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로, 도착지점의 4칸중에서 최소값을 찾아서 반환해주면 된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>경주로 건설</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/779</guid>
      <comments>https://jun-coding.tistory.com/779#entry779comment</comments>
      <pubDate>Thu, 4 Sep 2025 23:20:45 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 네트워크 / JS</title>
      <link>https://jun-coding.tistory.com/778</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43162&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/43162&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1756821044522&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43162&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/EebJK/hyZG06iy9Z/dAdDmH3ZccdanWhaYhrIJk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/7jOHn/hyZGkLaXcT/aRYCgck8rEWiP5FxtEwNXK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43162&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/43162&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/EebJK/hyZG06iy9Z/dAdDmH3ZccdanWhaYhrIJk/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/7jOHn/hyZGkLaXcT/aRYCgck8rEWiP5FxtEwNXK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1756821404031&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, computers) {
  const visited = Array.from({ length: n }, () =&amp;gt; false);
  let network = 0;

  for (let i = 0; i &amp;lt; n; i++) {
    // 아직 방문하지 않았다면 dfs로 네트워크를 탐색한다.
    if (!visited[i]) {
      dfs(i);
      network++;
    }
  }

  function dfs(cur) {
    for (let i = 0; i &amp;lt; n; i++) {
      if (visited[i]) {
        continue;
      }
      // 이어져 있지 않다면 건너뛴다.
      if (computers[cur][i] === 0) {
        continue;
      }

      visited[i] = true;
      dfs(i);
    }
  }

  return network;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제는 간단히 말하면 이어져있는 그룹이 몇개인지 세는 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Level3 이라기엔 상당히 쉬운 문제이다.&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;font-family: 'Nanum Gothic';&quot;&gt;dfs로 현재의 컴퓨터와 이어져 있는 컴퓨터는 모두 방문처리를 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 dfs를 마치면 하나의 네트워크가 형성되게 된다.&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;font-family: 'Nanum Gothic';&quot;&gt;아직 네트워크가 형성되지 않은 컴퓨터는 방문처리가 되어있지 않았을 것이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;방문처리 되어있지 않은 컴퓨터에서 다시 dfs를 이용해 네트워크를 형성해주면 된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>네트워크</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/778</guid>
      <comments>https://jun-coding.tistory.com/778#entry778comment</comments>
      <pubDate>Tue, 2 Sep 2025 22:59:59 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 섬 연결하기 / JS</title>
      <link>https://jun-coding.tistory.com/777</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42861&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42861&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1756714751568&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42861&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/85gP5/hyZGaIaZxt/yNAEBFRqYB9RkuIc40m821/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eVbNo/hyZGjE6NYp/u5uEZhSpcDRLk6GVuEtOBK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42861&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42861&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/85gP5/hyZGaIaZxt/yNAEBFRqYB9RkuIc40m821/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eVbNo/hyZGjE6NYp/u5uEZhSpcDRLk6GVuEtOBK/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제한사항&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같은 고려해볼만한 제한사항이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;섬의 개수 n은 1 이상 100 이하입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약, 섬의 개수가 100을 넘어서 1,000 혹은 그 이상이라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단한 kruscal 알고리즘 만으로는 풀이가 어려울 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제는 '시간복잡도' 때문이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;kruscal 알고리즘에 사용되는 알고리즘인 union-find 알고리즘에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;부모노드를 찾기 위해, 계속해서 거슬러 올라가야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최악의 경우 여러 노드가 일렬로 연결되는데, 시간복잡도가 커지게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때, 'rank' 라는 개념을 도입해서 최적화를 진행하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;깊이가 작은 노드 집합을 깊이가 큰 노드 집합에 붙이게 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이 문제는 이런 최적화까지는 하지 않아도,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;범위가 작기 때문에 충분히 통과가 가능하니 다른 문제에서 설명하도록 하겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;풀이&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1756716358157&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findParent(parent, n) {
  if (n === parent[n]) {
    return n;
  }

  parent[n] = findParent(parent, parent[n]);
  return parent[n];
}

function unionParent(parent, x, y) {
  const a = findParent(parent, x);
  const b = findParent(parent, y);

  if (a &amp;lt; b) {
    parent[a] = b;
  } else {
    parent[b] = a;
  }

  return parent;
}

function solution(n, costs) {
  const sortedCosts = [...costs].sort((a, b) =&amp;gt; a[2] - b[2]);
  const parent = Array.from({ length: n }, (_, i) =&amp;gt; i);

  let minCost = 0;

  for (const [x, y, cost] of sortedCosts) {
    const rootX = findParent(parent, x);
    const rootY = findParent(parent, y);

    if (rootX !== rootY) {
      unionParent(parent, rootX, rootY);

      minCost += cost;
    }
  }

  return minCost;
}&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`findParent()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1756716564493&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function findParent(parent, n) {
  if (n === parent[n]) {
    return n;
  }

  parent[n] = findParent(parent, parent[n]);
  return parent[n];
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`findParent()` 함수는 union-find 알고리즘에서 루트 노드를 찾는 함수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`n`이 자기 자신을 부모로 가리키고 있다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 노드가 해당 집합의 '루트'가 된다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`unionParent()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1756716592361&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function unionParent(parent, x, y) {
  const a = findParent(parent, x);
  const b = findParent(parent, y);

  if (a &amp;lt; b) {
    parent[a] = b;
  } else {
    parent[b] = a;
  }

  return parent;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`unionParent()` 함수는 union-find 알고리즘에서 두 개의 서로 다른 집합을 하나로 합치는 역할을 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, 위에서 구현한 `findParent()` 함수로 두 노드의 루트 노드를 찾는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두 번째로, &lt;b&gt;인덱스가 더 큰 노드를 부모로 선택&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순한 union 연산 구현으로, 최적화 할 시에 'rank' 개념을 도입해서 최적화가 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution()`&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1756716798555&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function solution(n, costs) {
  const sortedCosts = [...costs].sort((a, b) =&amp;gt; a[2] - b[2]);
  const parent = Array.from({ length: n }, (_, i) =&amp;gt; i);

  let minCost = 0;

  for (const [x, y, cost] of sortedCosts) {
    const rootX = findParent(parent, x);
    const rootY = findParent(parent, y);

    if (rootX !== rootY) {
      unionParent(parent, rootX, rootY);

      minCost += cost;
    }
  }

  return minCost;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 간선의 cost 기준으로 오름차순으로 정렬해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 저렴한 비용을 가진 간선부터 검토하기 위해서이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;두 번째로, 자기 자신을 부모로 가지도록 초기화한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;세 번째로, 사이클을 검사한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두 노드의 루트를 비교해서 다를 경우에 union 연산을 수행하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 루트가 같다면, 같은 집합에 속해있다는 것이므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간선을 추가하면 사이클이 형성된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;기존에 cost 기준 오름차순으로 정렬을 했고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이클이 형성되는지를 확인하기 때문에 cost를 더해주면 최소 비용을 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/777</guid>
      <comments>https://jun-coding.tistory.com/777#entry777comment</comments>
      <pubDate>Mon, 1 Sep 2025 17:59:21 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 3 / 표 편집 / JS</title>
      <link>https://jun-coding.tistory.com/775</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81303&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/81303&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1755500888523&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;프로그래머스&quot; data-og-description=&quot;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81303&quot; data-og-url=&quot;https://programmers.co.kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/y9ous/hyZzJKQiPo/buhn8nvcrOuJu3tpWK3yok/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eMoyi/hyZyfKkhoA/7rMzAdoYDEKCOgFLPHMBe0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81303&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/81303&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/y9ous/hyZzJKQiPo/buhn8nvcrOuJu3tpWK3yok/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960,https://scrap.kakaocdn.net/dn/eMoyi/hyZyfKkhoA/7rMzAdoYDEKCOgFLPHMBe0/img.png?width=1920&amp;amp;height=960&amp;amp;face=0_0_1920_960');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;프로그래머스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 시간에는 Programmers의 Level 3,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'표 편집' 문제에 대해 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kPz67/btsPXV8VoRr/4Oth5d0cvm7ydLD8L6Nah0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kPz67/btsPXV8VoRr/4Oth5d0cvm7ydLD8L6Nah0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kPz67/btsPXV8VoRr/4Oth5d0cvm7ydLD8L6Nah0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkPz67%2FbtsPXV8VoRr%2F4Oth5d0cvm7ydLD8L6Nah0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 문제에 대해 간략히 설명드리고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제한사항을 살펴본 뒤,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제를 해결해보면서 마무리하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2xrv5/btsPYHCxEXp/NqgpQYWCwyagdCnSX5fjkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2xrv5/btsPYHCxEXp/NqgpQYWCwyagdCnSX5fjkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2xrv5/btsPYHCxEXp/NqgpQYWCwyagdCnSX5fjkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2xrv5%2FbtsPYHCxEXp%2FNqgpQYWCwyagdCnSX5fjkk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제에는 총 네 종류의 명령이 주어질 수 있습니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;첫 번째, 'U' 명령을 수행하면, X칸 위에 있는 행을 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;두 번째, 'D' 명령을 수행하면, X칸 아래에 있는 행을 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;세 번째, 'C' 명령을 수행하면, 현재 선택된 행을 삭제한 후, 바로 아래 행을 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단, 삭제된 행이 가장 마지막 행인 경우에는 바로 윗 행을 선택합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 네 번째, 'Z' 명령을 수행하면, 가장 최근에 삭제된 행을 원래대로 복구합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단, 현재 선택된 행은 바뀌지 않습니다.&lt;/span&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pm6bE/btsPVIpam6c/kzHDnUe0yTnvyiqfjsOVf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pm6bE/btsPVIpam6c/kzHDnUe0yTnvyiqfjsOVf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pm6bE/btsPVIpam6c/kzHDnUe0yTnvyiqfjsOVf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpm6bE%2FbtsPVIpam6c%2FkzHDnUe0yTnvyiqfjsOVf0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제에 나와 있는 예시를 하나씩 볼까요?&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;왼쪽의 표에서 'D 2'를 수행할 경우 오른쪽의 그림처럼 4행이 선택됩니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVOQ5X/btsPYHbvtGV/EQ9JCZKW7Ge58HA4uWpDgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVOQ5X/btsPYHbvtGV/EQ9JCZKW7Ge58HA4uWpDgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVOQ5X/btsPYHbvtGV/EQ9JCZKW7Ge58HA4uWpDgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVOQ5X%2FbtsPYHbvtGV%2FEQ9JCZKW7Ge58HA4uWpDgK%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음에 'C'를 수행하면 선택된 행을 삭제하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;바로 아래 행이었던 '네오'가 적힌 행을 선택합니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;4행이 삭제되면서 아래 있던 행들이 하나씩 밀려 올라오고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수정된 표에서 다시 4행을 선택하는 것과 동일하죠.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKgLam/btsPXEzEzB6/C9rYilhxgSCMOGoBBG3EIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKgLam/btsPXEzEzB6/C9rYilhxgSCMOGoBBG3EIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKgLam/btsPXEzEzB6/C9rYilhxgSCMOGoBBG3EIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKgLam%2FbtsPXEzEzB6%2FC9rYilhxgSCMOGoBBG3EIk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로, 'U 3'을 수행한 다음,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'C'를 수행한 후의 표 상태는 오른쪽 그림과 같습니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFtdCg/btsPXBpmcwY/KMu0PopE7xlSuGY0GUytHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFtdCg/btsPXBpmcwY/KMu0PopE7xlSuGY0GUytHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFtdCg/btsPXBpmcwY/KMu0PopE7xlSuGY0GUytHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFtdCg%2FbtsPXBpmcwY%2FKMu0PopE7xlSuGY0GUytHk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로 'D 4'를 수행한 다음 'C'를 수행한 후의 표 상태는 오른쪽 그림과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;5행이 표의 마지막 행이므로, 이 경우에는 바로 윗 행을 선택하는 점에 주의해주세요!&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/babNcN/btsPVbE6ZE0/R4TWH3j73YDHs8zgMgfiA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/babNcN/btsPVbE6ZE0/R4TWH3j73YDHs8zgMgfiA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/babNcN/btsPVbE6ZE0/R4TWH3j73YDHs8zgMgfiA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbabNcN%2FbtsPVbE6ZE0%2FR4TWH3j73YDHs8zgMgfiA1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로 'U 2'를 수행하면 현재 선택된 행은 2행이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 상태에서 'Z'를 수행할 경우 가장 최근에 제거된 '라이언'이 적힌 행이 원래대로 복구됩니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d50nZw/btsPXSYDhkO/6eGTdyuH5bFsGWGDckixs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d50nZw/btsPXSYDhkO/6eGTdyuH5bFsGWGDckixs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d50nZw/btsPXSYDhkO/6eGTdyuH5bFsGWGDckixs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd50nZw%2FbtsPXSYDhkO%2F6eGTdyuH5bFsGWGDckixs0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 다시 한번 'Z'를 수행하면 그 다음으로 최근에 제거된 '콘'이 적힌 행이 원래대로 복구됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이때, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;현재 선택된 행은 바뀌지 않는다는 점에 주의해주세요!&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOQXD1/btsPZmrmOHh/zIuwZgKlDMshnVkDUACUy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOQXD1/btsPZmrmOHh/zIuwZgKlDMshnVkDUACUy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOQXD1/btsPZmrmOHh/zIuwZgKlDMshnVkDUACUy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOQXD1%2FbtsPZmrmOHh%2FzIuwZgKlDMshnVkDUACUy1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최종 표의 상태와 처음 주어진 표의 상태를 비교해서 삭제되지 않은 행은 'O',&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제된 행은 'X'로 표시하면 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제 스택에 남아있는 '프로도'를 아직 되돌리지 않았으니 'X'로 표시되는 것이죠.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5W89m/btsPXAjE9eQ/BCCGlAhczUBaLMkTGLvHO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5W89m/btsPXAjE9eQ/BCCGlAhczUBaLMkTGLvHO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5W89m/btsPXAjE9eQ/BCCGlAhczUBaLMkTGLvHO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5W89m%2FbtsPXAjE9eQ%2FBCCGlAhczUBaLMkTGLvHO0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 이해를 완료하셨을까요?&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이제, 매개변수로 처음 표의 행 개수인 n,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에 선택된 행의 위치인 k,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;수행한 명령어들이 담긴 문자열 배열인 cmd가 주어질 때,&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;font-family: 'Nanum Gothic';&quot;&gt;모든 명령어를 수행한 후 표의 상태와&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음 주어진 표의 상태를 비교하여&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제되지 않은 행은 'O',&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제된 행은 'X'로 표시하여 문자열 형태로 반환해주는 함수를 완성해주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제한사항&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEIZMw/btsPYM4XBYq/YzkCW7yscXeFHRaQjkSNo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEIZMw/btsPYM4XBYq/YzkCW7yscXeFHRaQjkSNo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEIZMw/btsPYM4XBYq/YzkCW7yscXeFHRaQjkSNo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEIZMw%2FbtsPYM4XBYq%2FYzkCW7yscXeFHRaQjkSNo0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제가 복잡할수록 제한사항도 꼼꼼히 잘 봐주셔야 합니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 문제를 풀다가 시간초과가 날 경우&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제한사항에 있는 범위를 고려하지 못한 코드일 확률이 높기 때문입니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그럼 제한사항을 하나씩 볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 행의 개수는 최대 100만, cmd의 개수는 최대 20만인 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 행의 삭제를 배열 메서드인 `splice()`나 `shift()`를 이용한다면 어떻게 될까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제된 빈자리를 채우기 위해 뒤에 있는 요소들을 앞으로 한 칸씩 이동시켜야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;O(N)의 시간 복잡도를 가지게 되겠죠.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vSjVL/btsPXIB2NgV/F4hzHuaMRV2XRaX5ArTbm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vSjVL/btsPXIB2NgV/F4hzHuaMRV2XRaX5ArTbm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vSjVL/btsPXIB2NgV/F4hzHuaMRV2XRaX5ArTbm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvSjVL%2FbtsPXIB2NgV%2FF4hzHuaMRV2XRaX5ArTbm0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 문제 설명에서 봤듯이, '이름' 열은 딱히 필요하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'몇 번째'의 행을 조작하는지가 중요했죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 '이름'같은 데이터의 값보다,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;순서를 중요하게 고려해야 한다는 것을 알 수 있습니다.&lt;/span&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yeHAe/btsPXojzvDg/GMEyjM1sU66S3w9bQBW8T0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yeHAe/btsPXojzvDg/GMEyjM1sU66S3w9bQBW8T0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yeHAe/btsPXojzvDg/GMEyjM1sU66S3w9bQBW8T0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyeHAe%2FbtsPXojzvDg%2FGMEyjM1sU66S3w9bQBW8T0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;행동이 불가능하거나, 조건을 고려해야 하는 명령들은 주어지지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를 통해, 특수 케이스에 대한 처리는 신경을 크게 쓰지 않아도 되겠죠.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이렇게 모든 제한사항을 살펴보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 배열로 처리가 불가능할 것 같은데, 어떤 자료구조를 써야할까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중간 요소를 삭제하고, 삭제된 요소를 다시 원래 자리로 되돌리는데 좋은 자료구조가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;바로 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;'연결 리스트'&lt;/b&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;해결방법&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결리스트&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Ogb3/btsPZaq8IuW/8biOtMEXFGI3MCurFn4fO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Ogb3/btsPZaq8IuW/8biOtMEXFGI3MCurFn4fO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Ogb3/btsPZaq8IuW/8biOtMEXFGI3MCurFn4fO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Ogb3%2FbtsPZaq8IuW%2F8biOtMEXFGI3MCurFn4fO1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'왜' 연결리스트를 사용해야 하는지 알아보기에 앞서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결리스트가 무엇인지 간단하게 먼저 살펴볼게요.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;연결리스트는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약, 중간에 있는 데이터를 삭제하고 싶다면 어떻게 할까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어 2번 노드를 지운다고 생각해볼게요.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEyFCx/btsPYLLIRbZ/KlBEZEZOW9w3LAu0G5PlI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEyFCx/btsPYLLIRbZ/KlBEZEZOW9w3LAu0G5PlI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEyFCx/btsPYLLIRbZ/KlBEZEZOW9w3LAu0G5PlI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEyFCx%2FbtsPYLLIRbZ%2FKlBEZEZOW9w3LAu0G5PlI1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;보시는 것과 같이,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 1번에서 2번으로 연결되어 있던 포인터를&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3번으로 연결해주기만 하면 됩니다.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 2번 노드의 전과 후는 null로 해주면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결이 끊어지므로 삭제된 것과 같은 효과를 줄 수 있죠.&lt;/span&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btdocF/btsPZOnu8M3/sCJPvdsb1L2ktaTwLcyEz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btdocF/btsPZOnu8M3/sCJPvdsb1L2ktaTwLcyEz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btdocF/btsPZOnu8M3/sCJPvdsb1L2ktaTwLcyEz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtdocF%2FbtsPZOnu8M3%2FsCJPvdsb1L2ktaTwLcyEz1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제는 표에 관한 문제니까,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;노드는 각 행,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결리스트는 표 전체라고 보면 됩니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;자, 그럼 이제 코드를 구현해볼까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`Row`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bt8T5e/btsPVhMbIvx/x2ixXnKpUoIyuEeEpqjog1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bt8T5e/btsPVhMbIvx/x2ixXnKpUoIyuEeEpqjog1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bt8T5e/btsPVhMbIvx/x2ixXnKpUoIyuEeEpqjog1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbt8T5e%2FbtsPVhMbIvx%2Fx2ixXnKpUoIyuEeEpqjog1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 각 행을 나타내는 자료구조를 만들어줄게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`Row`라는 클래스로 나타내줄건데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몇 번째인지 나타내는 `index`와&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 행과 다음 행을 나타내는 포인터 변수인 `prev`와 `next`를 선언해줍니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`Table`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVEAoS/btsPXzkMp9Q/eMU3iGEiac2TLEt0HIgEf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVEAoS/btsPXzkMp9Q/eMU3iGEiac2TLEt0HIgEf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVEAoS/btsPXzkMp9Q/eMU3iGEiac2TLEt0HIgEf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVEAoS%2FbtsPXzkMp9Q%2FeMU3iGEiac2TLEt0HIgEf0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로 표 전체를 나타내는 자료구조인 Table 클래스입니다.&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;font-family: 'Nanum Gothic';&quot;&gt;각 행을 저장할 배열인 `rows`와&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 위치를 나타내는 `cursor`,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제된 행들을 저장하는 `deletedStack` 변수를 선언해줍니다.&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;font-family: 'Nanum Gothic';&quot;&gt;그런 다음에, 표를 초기화해줘야겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제에서 매개변수로 행의 개수인 `n`과,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 위치를 나타내는 `k`를 받으니 그 변수를 이용해서 표를 초기화해주는 함수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`initTable()` 함수를 만들어보겠습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `initTable()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wlq8U/btsPXqVWvCy/iN0HKpj4K4icV4sb2GTBnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wlq8U/btsPXqVWvCy/iN0HKpj4K4icV4sb2GTBnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wlq8U/btsPXqVWvCy/iN0HKpj4K4icV4sb2GTBnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWlq8U%2FbtsPXqVWvCy%2FiN0HKpj4K4icV4sb2GTBnK%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`initTable()` 함수는 앞서 말씀드렸다시피,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;행의 개수를 나타내는 `n`과,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 위치인 `k`를 매개변수로 받아요.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dzqdbH/btsPVHw4nHP/glPQGnDsqUp2pnZ6VUyXP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dzqdbH/btsPVHw4nHP/glPQGnDsqUp2pnZ6VUyXP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dzqdbH/btsPVHw4nHP/glPQGnDsqUp2pnZ6VUyXP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdzqdbH%2FbtsPVHw4nHP%2FglPQGnDsqUp2pnZ6VUyXP1%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 반복문을 통해 `n`개의 `Row`를 생성해주죠.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`Row`를 생성했지만, 서로 연결해주지 않았죠?&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwEyFh/btsPVmtah29/5xRdtnK3Kqb4NGQcNaAR31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwEyFh/btsPVmtah29/5xRdtnK3Kqb4NGQcNaAR31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwEyFh/btsPVmtah29/5xRdtnK3Kqb4NGQcNaAR31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwEyFh%2FbtsPVmtah29%2F5xRdtnK3Kqb4NGQcNaAR31%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다시 한번 반복문을 통해 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 `Row`의 `prev`와 `next`를 연결해줄게요.&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;font-family: 'Nanum Gothic';&quot;&gt;인덱스가 0보다 클 때는 현재 `Row`의 `prev`를 '이전 Row'와 연결해줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인덱스가 0인경우에는 `prev`가 없으니까 null인 상태에서 굳이 연결해줄 필요가 없겠죠.&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;font-family: 'Nanum Gothic';&quot;&gt;마찬가지로, 인덱스가 n - 1보다 작을 때는 현재 `Row`의 `next`를 '다음 Row'랑 연결해줄게요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기도 마지막 행은 `next`가 없으니까 null로 그대로 두면 됩니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rjhax/btsPWqoligk/DrzOlkELtKYst0d4KpyRe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rjhax/btsPWqoligk/DrzOlkELtKYst0d4KpyRe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rjhax/btsPWqoligk/DrzOlkELtKYst0d4KpyRe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRjhax%2FbtsPWqoligk%2FDrzOlkELtKYst0d4KpyRe0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로, 현재 커서를 매개변수로 받은 `k`번째 `Row`로 할당해주면 됩니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7nDLK/btsPXxmVrPE/5xJdrqKBdaun2n3TVgrE1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7nDLK/btsPXxmVrPE/5xJdrqKBdaun2n3TVgrE1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7nDLK/btsPXxmVrPE/5xJdrqKBdaun2n3TVgrE1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7nDLK%2FbtsPXxmVrPE%2F5xJdrqKBdaun2n3TVgrE1k%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 `n`이 3이고, `k`가 1이라면 왼쪽 그림과 같겠죠?&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;font-family: 'Nanum Gothic';&quot;&gt;이렇게 기본적인 구조는 갖춰졌으니,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 명령을 수행하는 함수도 만들어야 합니다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;X칸 위에 있는 행을 선택하는 `up()`함수,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;X칸 아래에 있는 행을 선택하는 `down()`함수,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;선택된 행을 삭제하는 `remove()` 함수,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;행을 원래대로 복구하는 `restore()` 함수를 차례대로 만들어볼게요.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `up()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F49SI/btsPWV2Yt6k/BQAvsOKAgAAk7K6rItkFvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F49SI/btsPWV2Yt6k/BQAvsOKAgAAk7K6rItkFvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F49SI/btsPWV2Yt6k/BQAvsOKAgAAk7K6rItkFvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF49SI%2FbtsPWV2Yt6k%2FBQAvsOKAgAAk7K6rItkFvK%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, `up()` 함수입니다.&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;font-family: 'Nanum Gothic';&quot;&gt;`moveCount`는 몇 칸 움직일지 받기 위한 매개변수입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위로 움직여야 하기 때문에 `moveCount` 만큼 `prev`로 계속 거슬러 올라가면 되겠죠?&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;font-family: 'Nanum Gothic';&quot;&gt;거슬러 올라가면서 `cursor`를 `prev`로 계속 갱신해줍니다.&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 초기에 왼쪽 그림처럼 `cursor`가 4행에 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`moveCount`가 2라면,&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnRUsr/btsPW0pl5v4/dvEyRQSS15EFet24bbSPV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnRUsr/btsPW0pl5v4/dvEyRQSS15EFet24bbSPV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnRUsr/btsPW0pl5v4/dvEyRQSS15EFet24bbSPV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnRUsr%2FbtsPW0pl5v4%2FdvEyRQSS15EFet24bbSPV0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4행의 `prev`인 3행으로 거슬러 올라가고,&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RLVkG/btsPVlOz0o4/kwQARMsowKK5ft9qYRHt8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RLVkG/btsPVlOz0o4/kwQARMsowKK5ft9qYRHt8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RLVkG/btsPVlOz0o4/kwQARMsowKK5ft9qYRHt8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRLVkG%2FbtsPVlOz0o4%2FkwQARMsowKK5ft9qYRHt8K%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3행의 `prev`인 2행으로 거슬러 올라가서 최종적으로 왼쪽의 그림과 같은 상황이 될거에요.&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;font-family: 'Nanum Gothic';&quot;&gt;그럼 밑으로 가는 함수인 `down()`도 어떻게 구현해야 할지 감이 오시나요?&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `down()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/89ocX/btsPZt4RY5V/RzVL3f9TQabHMUrVu8Q0rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/89ocX/btsPZt4RY5V/RzVL3f9TQabHMUrVu8Q0rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/89ocX/btsPZt4RY5V/RzVL3f9TQabHMUrVu8Q0rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F89ocX%2FbtsPZt4RY5V%2FRzVL3f9TQabHMUrVu8Q0rK%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`down()`은 다음 행으로 가야하니, `prev`대신 `next`를 사용해서 해주면 됩니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `remove()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clv3nY/btsPXQfrGhs/fOSAjm8xTbfliDdDOMoqAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clv3nY/btsPXQfrGhs/fOSAjm8xTbfliDdDOMoqAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clv3nY/btsPXQfrGhs/fOSAjm8xTbfliDdDOMoqAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclv3nY%2FbtsPXQfrGhs%2FfOSAjm8xTbfliDdDOMoqAk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로, 선택된 행을 삭제하는 함수인 `remove()` 함수를 살펴볼게요.&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, 삭제할 행을 `deletedRow`라는 변수에 저장해줄게요.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NQ6Sc/btsPZb4zTiQ/3ZjdQsDWgt6iujLIkeKR80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NQ6Sc/btsPZb4zTiQ/3ZjdQsDWgt6iujLIkeKR80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NQ6Sc/btsPZb4zTiQ/3ZjdQsDWgt6iujLIkeKR80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNQ6Sc%2FbtsPZb4zTiQ%2F3ZjdQsDWgt6iujLIkeKR80%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로, 삭제 스택에 현재 행을 넣어줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때, 중요한것은 삭제할 행의 `prev`와 `next`도 같이 저장해줘야 한다는 것이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Row 클래스의 `prev`와 `next` 속성으로 접근할 수 있는데 왜 따로 또 저장할까요?&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ1uF6/btsPWqBUDwe/poI4SownKM2emAcPX2Mdq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ1uF6/btsPWqBUDwe/poI4SownKM2emAcPX2Mdq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ1uF6/btsPWqBUDwe/poI4SownKM2emAcPX2Mdq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ1uF6%2FbtsPWqBUDwe%2FpoI4SownKM2emAcPX2Mdq0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;행이 삭제된다면, 연결을 재조정 해주어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 과정에서 연결이 끊어지게 되는데, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원래 연결되어 있던 `prev`와 `next`를 나중에 복구할 때 참조하기 위함입니다.&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/APslL/btsPXx1zbC5/OjEynyD4Tk2AL5ZL2A00o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/APslL/btsPXx1zbC5/OjEynyD4Tk2AL5ZL2A00o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/APslL/btsPXx1zbC5/OjEynyD4Tk2AL5ZL2A00o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAPslL%2FbtsPXx1zbC5%2FOjEynyD4Tk2AL5ZL2A00o0%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결을 재조정 해주었다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막행이 아니라면 다음행으로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막행이라면 이전행으로 커서를 옮겨줍니다.&lt;/span&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `restore()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blLbRM/btsPV13GND6/vDnKFAeqAsvSEB7mFqgSLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blLbRM/btsPV13GND6/vDnKFAeqAsvSEB7mFqgSLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blLbRM/btsPV13GND6/vDnKFAeqAsvSEB7mFqgSLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblLbRM%2FbtsPV13GND6%2FvDnKFAeqAsvSEB7mFqgSLk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 삭제된 행을 복구하는 `restore()` 함수입니다.&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;font-family: 'Nanum Gothic';&quot;&gt;'가장 최근에 삭제된 행'을 복구하는 것이니,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`deletedStack`의 맨 위에 있는 것을 `pop()` 해주면 되겠죠?&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ulhsg/btsPXVukilC/Ub9j1mmn5tkJ7VSAv7XM81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ulhsg/btsPXVukilC/Ub9j1mmn5tkJ7VSAv7XM81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ulhsg/btsPXVukilC/Ub9j1mmn5tkJ7VSAv7XM81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUlhsg%2FbtsPXVukilC%2FUb9j1mmn5tkJ7VSAv7XM81%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로, 우리가 스택에 넣을 때 같이 저장했던 prevRow와 nextRow를 이용해서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;연결을 복구해주면 됩니다.&lt;/span&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table - `getResult()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYLQN/btsPXVA61Qh/UpZI0Zfys6NXc6ZXitxmhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYLQN/btsPXVA61Qh/UpZI0Zfys6NXc6ZXitxmhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYLQN/btsPXVA61Qh/UpZI0Zfys6NXc6ZXitxmhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYLQN%2FbtsPXVA61Qh%2FUpZI0Zfys6NXc6ZXitxmhk%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결과를 얻는 함수는 이렇게 간단하게 구현해주면 되겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아직 `deletedStack`에 남아있는 행은&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;삭제된 후, 복구되지 않은 행이기 때문에 해당 행만 'X'로 바꿔주시면 됩니다.&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;font-family: 'Nanum Gothic';&quot;&gt;이렇게 구현에 필요한 모든 함수를 완성했습니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 입력에 맞게 결과를 구해볼까요?&lt;/span&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`solution()`&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yJtnD/btsPZfMAGov/CdiiEMjF01l93NJTeDPQpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yJtnD/btsPZfMAGov/CdiiEMjF01l93NJTeDPQpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yJtnD/btsPZfMAGov/CdiiEMjF01l93NJTeDPQpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyJtnD%2FbtsPZfMAGov%2FCdiiEMjF01l93NJTeDPQpK%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;3840&quot; height=&quot;2160&quot; data-origin-width=&quot;3840&quot; data-origin-height=&quot;2160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Table 클래스의 인스턴스를 생성해준 뒤,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반복문으로 각 명령에 맞게 `switch`로 분기처리를 해주면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;몇 칸 이동할지 나타내는 변수는 `parseInt()`로 정수로 변환한 뒤에 넘겨주는걸 잊지마세요!&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;font-family: 'Nanum Gothic';&quot;&gt;이상 프로그래머스 Level3.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'표 편집' 문제 자바스크립트 풀이였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;감사합니다!&lt;/span&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;전체 코드&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1755595463357&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Row {
  constructor(index) {
    this.index = index;
    this.prev = null;
    this.next = null;
  }
}

class Table {
  constructor(n, k) {
    this.rows = [];
    this.cursor = null;
    this.deletedStack = [];
    this.initTable(n, k);
  }

  initTable(n, k) {
    for (let i = 0; i &amp;lt; n; i++) {
      this.rows[i] = new Row(i);
    }

    for (let i = 0; i &amp;lt; n; i++) {
      if (i &amp;gt; 0) this.rows[i].prev = this.rows[i - 1];
      if (i &amp;lt; n - 1) this.rows[i].next = this.rows[i + 1];
    }

    this.cursor = this.rows[k];
  }

  up(moveCount) {
    for (let i = 0; i &amp;lt; moveCount; i++) {
      this.cursor = this.cursor.prev;
    }
  }

  down(moveCount) {
    for (let i = 0; i &amp;lt; moveCount; i++) {
      this.cursor = this.cursor.next;
    }
  }

  remove() {
    const deletedRow = this.cursor;

    // 삭제할 때 prev/next 정보를 저장해두기
    this.deletedStack.push({
      row: deletedRow,
      prevRow: deletedRow.prev,
      nextRow: deletedRow.next,
    });

    // 연결 끊기
    if (deletedRow.prev) {
      deletedRow.prev.next = deletedRow.next;
    }
    if (deletedRow.next) {
      deletedRow.next.prev = deletedRow.prev;
    }

    // 커서 이동
    if (deletedRow.next) {
      this.cursor = deletedRow.next;
    } else {
      this.cursor = deletedRow.prev;
    }
  }

  restore() {
    if (this.deletedStack.length === 0) return;

    const { row: restoredRow, prevRow, nextRow } = this.deletedStack.pop();

    // 저장된 연결 정보로 즉시 복구 (O(1))
    restoredRow.prev = prevRow;
    restoredRow.next = nextRow;

    if (prevRow) {
      prevRow.next = restoredRow;
    }
    if (nextRow) {
      nextRow.prev = restoredRow;
    }
  }

  getResult() {
    const result = new Array(this.rows.length).fill('O');

    for (const { row } of this.deletedStack) {
      result[row.index] = 'X';
    }

    return result.join('');
  }
}

/**
 * 표 편집
 * @description 표에서 행을 선택, 삭제, 복구하는 명령어들을 수행한 후 최종 표의 상태를 구하는 함수
 * @param {number} n 표의 행 개수
 * @param {number} k 처음 선택된 행의 위치
 * @param {string[]} cmd 수행할 명령어 배열
 * @returns {string} 최종 표의 상태 ('O': 존재, 'X': 삭제)
 * @constraints
 * - 표의 행 개수 n은 5 이상 1,000,000 이하입니다.
 * - 처음 선택된 행의 위치 k는 0 이상 n-1 이하입니다.
 * - 명령어 배열 cmd의 길이는 1 이상 200,000 이하입니다.
 * - 명령어는 &quot;U X&quot;, &quot;D X&quot;, &quot;C&quot;, &quot;Z&quot; 형태입니다.
 */
function solution(n, k, cmd) {
  const table = new Table(n, k);

  for (let i = 0; i &amp;lt; cmd.length; i++) {
    const [command, x] = cmd[i].split(' ');

    switch (command) {
      case 'U':
        table.up(parseInt(x));
        break;
      case 'D':
        table.down(parseInt(x));
        break;
      case 'C':
        table.remove();
        break;
      case 'Z':
        table.restore();
        break;
    }
  }

  const result = table.getResult();
  return result;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>표 편집</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/775</guid>
      <comments>https://jun-coding.tistory.com/775#entry775comment</comments>
      <pubDate>Tue, 19 Aug 2025 18:24:56 +0900</pubDate>
    </item>
    <item>
      <title>Next.js 15 / Image Component</title>
      <link>https://jun-coding.tistory.com/774</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js의 장점이 '간편한 라우팅'과, '이미지 및 폰트 최적화'라고 많이 들어봤을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 최적화 할 때, React랑은 다르게 `&amp;lt;Image&amp;gt;` 컴포넌트를 사용하는데, 어떻게 다른지 궁금하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;되게 많은 prop들이 있지만, 실제로 사용해본 것들 먼저 천천히 정리해보려 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, Image 컴포넌트에 대해 가볍게 설명하자면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Image 컴포넌트는 HTML의 `&amp;lt;img&amp;gt;`를 확장하여 &lt;b&gt;자동 이미지 최적화&lt;/b&gt; 기능을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원본 이미지를 직접 사용하는 것이 아니라, Next.js 서버를 거쳐서 &lt;b&gt;최적화된&lt;/b&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Props&lt;/span&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 488px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Prop&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;타입&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;src&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;src=&quot;/profile.png&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 경로&lt;b&gt;(필수)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;alt&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;alt=&quot;저자 사진&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대체 텍스트&lt;b&gt;(필수)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;width&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;width={500}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Integer (px)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 가로 픽셀값&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;height&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;height={500}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Integer (px)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 세로 픽셀값&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;fill&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;fill={true}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Boolean&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;부모 요소 채우기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;loader&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;loader={imageLoader}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Function&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;커스텀 로더 함수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 35px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 35px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;sizes&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 35px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;sizes=&quot;(max-width:768px) 100vw, 33vw&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 35px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 35px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반응형 이미지 크기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;quality&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;quality={80}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Integer (1-100)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 품질 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;priority&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;priority={true}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Boolean&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우선 로딩&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;placeholder&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;placeholder=&quot;blur&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;블러 등 플레이스홀더&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;style&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;style={{objectFit: &quot;contain&quot;}}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Object&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인라인 CSS 스타일&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;onLoad&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;onLoad={event =&amp;gt; done()}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Function&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로드 완료 콜백&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;onError&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;onError={event =&amp;gt; fail()}&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Function&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로드 실패 콜백&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;loading&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;loading=&quot;lazy&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로딩 방식&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;blurDataURL&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;blurDataURL=&quot;image/...&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;블러 이미지 데이터&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.5349%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;overrideSrc&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 44.9999%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;overrideSrc=&quot;/seo.png&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.4652%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;String&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;src 직접 오버라이드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`src`&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;외부 URL은 remotePatterns 설정이 필요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정적 import가 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1755074009399&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import profile from './profile.png'
 
export default function Page() {
  return &amp;lt;Image src={profile} /&amp;gt;
}&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`alt`&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹 접근성을 위한 스크린 리더가 읽을 수 있는 대체 텍스트이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순 장식용 이미지라면 `alt=&quot;&quot;`로 비워둔다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`width` and `height`&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지의 원본 크기를 의미하며, 단위는 px이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지의 실제 렌더링 사이즈를 결정하지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js는 이 정보를 사용해 이미지 비율을 파악하여, &lt;br /&gt;이미지 로딩 시에 빈 공간을 미리 확보하고 레이아웃 시프트를 방지한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반드시&lt;b&gt; 함께 지정해야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지가 정적으로 import 된 경우나 `fill` prop을 사용하는 경우에는 명시적으로 지정하지 않아도 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;[ 중요한 점 ]&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 이미지가 원격 URL에서 오거나 동적으로 로드된다면, `width`와 `height`를 수동으로 지정한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`fill` prop은 이미지가 부모 컨테이너의 크기에 맞춰 늘어나며,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때는 부모 컨테이너에 `position: relative`등의 스타일이 필요하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저는 `width`와 `height`를 보고 이미지 공간을 미리 설정하므로,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명확한 크기를 설정하여 시각적 안정성을 확보하는 것이 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1755075384981&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Image from 'next/image'

// 정적 import한 이미지 예시
import profile from './profile.png'

export default function Page() {
  return (
    &amp;lt;Image
      src={profile}
      alt=&quot;프로필 사진&quot;
      // width, height는 profile 객체에 자동 포함되어 있으므로 따로 지정 안 해도 됨
    /&amp;gt;
  )
}

// 원격 이미지 예시 (width, height 직접 지정 필요)
export function RemoteImage() {
  return (
    &amp;lt;Image
      src=&quot;https://example.com/photo.jpg&quot;
      alt=&quot;원격 이미지&quot;
      width={800}
      height={600}
    /&amp;gt;
  )
}

// fill을 사용하는 경우 (부모 요소에 position: relative 필요)
export function FillImage() {
  return (
    &amp;lt;div style={{ position: 'relative', width: '400px', height: '300px' }}&amp;gt;
      &amp;lt;Image
        src=&quot;/bg.jpg&quot;
        alt=&quot;배경 이미지&quot;
        fill
        style={{ objectFit: 'cover' }}
      /&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`priority`&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`true`로 설정하면, 해당 이미지를 &lt;b&gt;즉시 우선적으로 미리 로드&lt;/b&gt;하도록 브라우저에 지시한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`priority={true}`인 이미지는 &lt;b&gt;lazy loading이 비활성화&lt;/b&gt;되고, 페이지 초기 렌더링 시 빠르게 표시된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;페이지에서 처음 화면에 보여지는 이미지에 사용하는 것이 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;페이지의 &lt;b&gt;Largest Contentful Paint(LCP)&lt;/b&gt; 요소에 해당하는 이미지에 지정하여 초기 로딩 성능을 개선한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중요한 주요 배너, 로고, 히어로 이미지 등 즉시 사용자에게 보여져야 하는 이미지에 적합하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-13 오후 6.56.37.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eDn3by/btsPRwPeVYw/uorgakmpSvTip68ykt3IZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eDn3by/btsPRwPeVYw/uorgakmpSvTip68ykt3IZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eDn3by/btsPRwPeVYw/uorgakmpSvTip68ykt3IZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeDn3by%2FbtsPRwPeVYw%2FuorgakmpSvTip68ykt3IZk%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;988&quot; height=&quot;134&quot; data-filename=&quot;스크린샷 2025-08-13 오후 6.56.37.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;134&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 개발자도구에서 위와 같은 경고 문구가 떴다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;해당 이미지 컴포넌트에 priority를 설정해주면 된다.&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;font-family: 'Nanum Gothic'; background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;* Largest Contentful Paint(LCP)란?&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;LCP는 웹 페이지에서 사용자가 보는 화면(뷰포트) 안에 렌더링되는 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 큰 콘텐츠 요소가 화면에 나타나는 시간을 측정하는 성능 지표이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주로 큰 이미지, 배너, 텍스트 블록 같은 페이지의 주요 콘텐츠가 얼마나 빨리 로드되고 표시되는지를 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;LCP는 사용자 경험 측면에서 매우 중요하고, SEO 순위에도 영향을 미치는 중요한 지표로 보고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;뷰표트 밖에 있거나 사용자가 스크롤하기 전까지 보이지 않는 콘텐츠는 LCP에 포함되지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`loading`&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`lazy`: 이미지를 뷰포트에 근접했을 때 로드한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`eager`: 이미지를 즉시 로드한다. 주로 페이지 첫 화면에 보여지는 중요한 이미지에 쓰인다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/774</guid>
      <comments>https://jun-coding.tistory.com/774#entry774comment</comments>
      <pubDate>Wed, 13 Aug 2025 18:48:11 +0900</pubDate>
    </item>
    <item>
      <title>Next.js 15 / CSS Modules</title>
      <link>https://jun-coding.tistory.com/773</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;평소에는 Tailwind CSS를 사용하다가, 한번도 써보지 않았던 CSS Modules를 접하게 되어 정리해보려 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;Tailwind CSS는 Next.js를 설치할 때 터미널에서 선택하면 자동으로 설치되기도 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/getting-started/css#recommendations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Next.js 문서&lt;/a&gt;에서도 여러가지 CSS 적용 방법중에 볼드체로 권장되는 방법이기도 하다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1755064003519&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;Getting Started: CSS | Next.js&quot; data-og-description=&quot;Learn about the different ways to add CSS to your application, including Tailwind CSS, CSS Modules, Global CSS, and more.&quot; data-og-host=&quot;nextjs.org&quot; data-og-source-url=&quot;https://nextjs.org/docs/app/getting-started/css#recommendations&quot; data-og-url=&quot;https://nextjs.org/docs/app/getting-started/css#recommendations&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9RxuI/hyZuv72pRV/Y4wDr3c1EyKsxvXAmsPZWK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bk5Wki/hyZuB1rqgA/XsLuav1FXBMKGnkIIU54gk/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628&quot;&gt;&lt;a href=&quot;https://nextjs.org/docs/app/getting-started/css#recommendations&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nextjs.org/docs/app/getting-started/css#recommendations&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9RxuI/hyZuv72pRV/Y4wDr3c1EyKsxvXAmsPZWK/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628,https://scrap.kakaocdn.net/dn/bk5Wki/hyZuB1rqgA/XsLuav1FXBMKGnkIIU54gk/img.png?width=1200&amp;amp;height=628&amp;amp;face=0_0_1200_628');&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;Getting Started: CSS | Next.js&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn about the different ways to add CSS to your application, including Tailwind CSS, CSS Modules, Global CSS, and more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nextjs.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(무엇보다 한 번 사용하게 되면서 다른건 보지도 않게 되었다...)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, Tailwind CSS를 사용하면서 길어진 className으로 컴포넌트 코드가 조금 지저분해 보인다는 단점이 있기는 하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 CSS 문법에 익숙하다면, 그냥 CSS Modules를 사용하는 것도 나쁘지 않다고 생각한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS Module&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS Module은 CSS를 로컬 범위로 한정하여 고유한 클래스 이름을 생성한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이를 통해 &lt;b&gt;서로 다른 파일에서 같은 클래스 이름을 사용해도 충돌을 걱정하지 않아도 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문법은 일반 CSS와 같고, 사용방법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755064352355&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* app/blog/blog.module.css */
.blog {
  padding: 24px;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1755064391362&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/blog/page.tsx
import styles from './blog.module.css'
 
export default function Page() {
  return &amp;lt;main className={styles.blog}&amp;gt;&amp;lt;/main&amp;gt;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위의 결과를 브라우저의 개발자 도구에서 확인해보면 아래와 같은 결과를 얻는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지정한 클래스명인 'blog'가 붙고, 그 뒤에 '-module', &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 해시값이 붙는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 다른 CSS Module에서 blog 클래스명을 사용하더라도 중복 걱정을 할 필요가 없는것이다.&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;스크린샷 2025-08-13 오후 2.55.41.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;485&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6KIHA/btsPQvJNLgu/dcEE6vJTTsuyJP3LxYJjFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6KIHA/btsPQvJNLgu/dcEE6vJTTsuyJP3LxYJjFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6KIHA/btsPQvJNLgu/dcEE6vJTTsuyJP3LxYJjFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6KIHA%2FbtsPQvJNLgu%2FdcEE6vJTTsuyJP3LxYJjFk%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;996&quot; height=&quot;485&quot; data-filename=&quot;스크린샷 2025-08-13 오후 2.55.41.png&quot; data-origin-width=&quot;996&quot; data-origin-height=&quot;485&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Ordering and Merging&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js는 프로덕션 빌드 시 CSS를 자동으로 chunking 하여 최적화한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;CSS의 적용 순서&lt;/b&gt;는 코드에서 해당 스타일을 &lt;b&gt;import한 순서&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: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;여기서 헷갈리면 안된다!!&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;적용 순서가 import한 순서에 따라 결정된다는 말은,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 여러 CSS 파일을 import 했는데 한 클래스에 대해 겹치는 스타일링이 있다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결국 가장 마지막에 import한 CSS가 적용된다는 것이다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;헷갈린다면, 겹치는 CSS는 가장 마지막에 import 한거로 덮어씌워진다고 생각하면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&quot;CSS를 적용한 태그랑 가까울수록 우선순위가 크다&quot;&lt;/span&gt;라고 생각해도 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Recommendations&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS import는 가급적 한 곳의 파일(layout.js/ts)에서 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;전역 스타일과 Tailwind CSS 스타일은 앱의 루트에서 import&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;스타일링은 대부분 Tailwind CSS 사용&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;유틸리티 클래스로 미리 정해진 스타일이기 때문에 공통적인 패턴으로 사용 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Tailwind CSS로 부족하면 CSS Modules 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS Modules는 `&amp;lt;name&amp;gt;.module.css` 네이밍 권장&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중복 스타일은 공용 컴포넌트로 추출&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ESLint의 `sort-imports` 등 import 순서를 강제로 바꾸는 도구는 비활성화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS chunking 제어는 `next.config.js/ts`의 `cssChunking` 옵션 활용 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Developments vs. Production&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발 환경에서는 &lt;b&gt;Fash Refresh&lt;/b&gt;로 CSS 업데이트가 즉시 반영&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로덕션 환경에서는 CSS가 &lt;b&gt;여러 개의 minified되고 code-split된&lt;/b&gt; `.css` 파일로 병합되어,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라우트 별 최소 CSS만 로딩&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;프로덕션 빌드에서는 JS가 꺼져 있어도 CSS가 로드됨&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(위에서 말했듯이, 개발 모드는 Fash Refresh 때문에 JS 필요)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CSS 순서는 개발과 프로덕션 환경에서 다를 수 있으므로 반드시 `next build`로 최종 CSS 적용 순서 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/773</guid>
      <comments>https://jun-coding.tistory.com/773#entry773comment</comments>
      <pubDate>Wed, 13 Aug 2025 15:14:49 +0900</pubDate>
    </item>
    <item>
      <title>Next.js 15 / File system conventions - layout.js(ts)</title>
      <link>https://jun-coding.tistory.com/772</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js의 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;'File system convention'&lt;/b&gt;&lt;/span&gt;은 프로젝트 폴더와 파일의 구조만으로&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라우팅 및 주요 기능이 자동으로 결정되는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특히 &lt;b&gt;Next.js 15.4.6 App Router&lt;/b&gt; 기준으로 20개가 넘는 컨벤션들이 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;공식문서를 보고 하나씩 정리해보려 한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, Next.js를 설치하게 되면 기본적으로 세팅이 되있기도 한 `layout.js`이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`layout` 파일은 레이아웃을 정의하기 위해 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 페이지에서 공통적으로 사용되는 레이아웃은 가장 상위인 `app` 디렉터리에 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Reference&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Props&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`children` (필수)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃 컴포넌트는 &lt;b&gt;`children` prop을 반드시 가져야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;렌더링 되는동안, `children`은 레이아웃이 감싸고 있는 경로에 대한 자식들로 채워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 자식들은 보통 자식 레이아웃이나, 컴포넌트로 채워지지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;loading.js나 error.js 같은 특별한 파일 일수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`params` (선택)&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`params`는 동적 라우팅 파라미터 객체를 담은 &lt;b&gt;Promise&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 경로가 `app/dashboard/[team]/layout.js`이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;URL이 `/dashboard/1`이라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`params`는 `Promise&amp;lt;{ team: '1' }&amp;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;font-family: 'Nanum Gothic';&quot;&gt;`params`는 Promise이므로 &lt;b&gt;`async/await` 또는 React의 `use` 함수를 사용해 값을 접근&lt;/b&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Root Layout&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`app` 디렉터리는 &lt;b&gt;반드시&lt;/b&gt; &lt;b&gt;루트 레이아웃이 있어야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일반적으로, `app/layout.js`가 루트 레이아웃이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754990864683&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    &amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;{children}&amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  )
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;루트 레이아웃은 반드시 `&amp;lt;html&amp;gt;`과 `&amp;lt;body&amp;gt;` 태그를 정의해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고, &lt;b&gt;메타데이터는 직접 작성하지 말고, Metatdata API를 사용&lt;/b&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754990984173&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import './globals.css';

export const metadata = {
  title: '제목',
  description: '설명',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    &amp;lt;html&amp;gt;
      &amp;lt;body&amp;gt;{children}&amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  );
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라우트 그룹을 사용하면 여러 개의 루트 레이아웃을 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, 서로 다른 루트 레이아웃 간 이동은 전체 페이지 새로고침을 발생시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, `/cart`(app/(shop)/layout.js)에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`blog`(app/(marketing)/layout.js)로 이동하면 새로고침이 발생한다.&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;font-family: 'Nanum Gothic';&quot;&gt;또한, 루트 레이아웃은 동적 세그먼트 하위에 있을 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, `app/[lang]/layout.js`를 국제화(i8n)에 사용 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주의 사항&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Request Object&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네비게이션 시 &lt;b&gt;레이아웃은 캐싱&lt;/b&gt;되어 불필요한 서버 요청이 발생하지 않게 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃은 다시 렌더링되지 않으므로 성능이 향상된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 레이아웃에서는 &lt;b&gt;원본 Request 객체&lt;/b&gt;에 접근할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대신 Server Component 및 서버 함수에서 &lt;b&gt;`headers`&lt;/b&gt;와 &lt;b&gt;`cookies`&lt;/b&gt; API를 사용해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754991489510&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { cookies } from 'next/headers'
 
export default async function Layout({ children }) {
  const cookieStore = await cookies()
  const theme = cookieStore.get('theme')
  return '...'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Query Params&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃은 네비게이션 시 리렌더링되지 않으므로 쿼리 파라미터가 갱신되지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 최신 쿼리 값을 얻고 싶다면,&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;페이지 컴포넌트에서 &lt;b&gt;`searchParams`&lt;/b&gt; prop을 사용하거나,&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Client Component에서 &lt;b&gt;`useSearchParams`&lt;/b&gt; 훅을 사용해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754991636239&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function Search() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  return '...'
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1754991644234&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Search from '@/app/ui/search'
 
export default function Layout({ children }) {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Search /&amp;gt;
      {children}
    &amp;lt;/&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Pathname&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃은 네비게이션 시 리렌더링되지 않으므로 최신 pathname에 접근할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최신 경로를 사용하려면 Client Component에서 &lt;b&gt;`usePathname`&lt;/b&gt;훅을 사용해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1754991964360&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;'use client'
 
import { usePathname } from 'next/navigation'
 
// Simplified breadcrumbs logic
export default function Breadcrumbs() {
  const pathname = usePathname()
  const segments = pathname.split('/')
 
  return (
    &amp;lt;nav&amp;gt;
      {segments.map((segment, index) =&amp;gt; (
        &amp;lt;span key={index}&amp;gt;
          {' &amp;gt; '}
          {segment}
        &amp;lt;/span&amp;gt;
      ))}
    &amp;lt;/nav&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1754991971620&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Breadcrumbs } from '@/app/ui/Breadcrumbs'
 
export default function Layout({ children }) {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Breadcrumbs /&amp;gt;
      &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
    &amp;lt;/&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Fetching Data&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃은 `children`에 데이터를 전달할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, 동일한 데이터를 여러 라우트에서 가져와야 할 경우에는&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;React의 &lt;b&gt;`cache`&lt;/b&gt;를 사용해 중복을 제거하거나,&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js의 &lt;b&gt;`fetch`&lt;/b&gt;를 사용해 자동으로 요청을 중복을 제거할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래와 같은 유저 데이터를 받아오는 함수가 있다고 할 때,&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754992197810&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export async function getUser(id: string) {
  const res = await fetch(`https://.../users/${id}`)
  return res.json()
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;layout은 기본적으로 서버 컴포넌트이기 때문에 직접 fetch 또는 다른 데이터 조회 코드를 직접 호출할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755003641962&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/dashboard/layout.tsx
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
 
export default async function Layout({ children }) {
  const user = await getUser('1')
 
  return (
    &amp;lt;&amp;gt;
      &amp;lt;nav&amp;gt;
        {/* ... */}
        &amp;lt;UserName user={user.name} /&amp;gt;
      &amp;lt;/nav&amp;gt;
      {children}
    &amp;lt;/&amp;gt;
  )
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위의 layout에 children에 들어가는 page 컴포넌트에서 다시 한번 똑같은 데이터를 요청해도,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;fetch를 사용할 경우, 같은 요청은 캐싱되어있기 때문에 성능 이슈가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755003649723&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/dashboard/page.tsx
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
 
export default async function Page() {
  const user = await getUser('1')
 
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Welcome {user.name}&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Accessing child segments&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레이아웃 컴포넌트는 자신을 감싸는 segment는 알 수 있어도, 자식 segment 정보까지는 알 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하위 segment를 사용하려면 Client Component에서 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;`useSelectedLayoutSegment`&lt;/b&gt; 또는 &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;`useSelectedLayoutSegments`&lt;/b&gt; 훅을 사용해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래 코드에서 `useSelectedLayoutSegment()` 훅은&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;URL 경로에서 상위 레이아웃 바로 아래 레벨의 활성화된 경로&lt;/b&gt;를 문자열로 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어 URL이 `/blog/hello-world`라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;부모인 `blog` 바로 아래 segment인 `hello-world`를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755006135062&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/ui/nav-link.tsx
'use client'
 
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
 
export default function NavLink({
  slug,
  children,
}: {
  slug: string
  children: React.ReactNode
}) {
  const segment = useSelectedLayoutSegment()
  const isActive = slug === segment
 
  return (
    &amp;lt;Link
      href={`/blog/${slug}`}
      // Change style depending on whether the link is active
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    &amp;gt;
      {children}
    &amp;lt;/Link&amp;gt;
  )
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 만약에 아래 코드에서 `post.slug`가 'hello-world'라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`/blog/hello-world`로 접속했을 때, 위의 NavLink의 isActive가 true가 되면서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;bold로 스타일링 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1755009274905&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// app/blog/layout.tsx
import { NavLink } from './nav-link'
import getPosts from './get-posts'
 
export default async function Layout({
  children,
}: {
  children: React.ReactNode
}) {
  const featuredPosts = await getPosts()
  return (
    &amp;lt;div&amp;gt;
      {featuredPosts.map((post) =&amp;gt; (
        &amp;lt;div key={post.id}&amp;gt;
          &amp;lt;NavLink slug={post.slug}&amp;gt;{post.title}&amp;lt;/NavLink&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
      &amp;lt;div&amp;gt;{children}&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/772</guid>
      <comments>https://jun-coding.tistory.com/772#entry772comment</comments>
      <pubDate>Tue, 12 Aug 2025 23:41:35 +0900</pubDate>
    </item>
    <item>
      <title>Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 2</title>
      <link>https://jun-coding.tistory.com/771</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 코드를 구현하기전에 끝내야 할 모든 설정들을 완료했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/770&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.08.08 - [Web/Next.js] - Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754602399317&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;Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 1&quot; data-og-description=&quot;개요사이드 프로젝트 진행중에 '카카오 로그인' 기능을 추가하고자 했다.Next.js를 사용하는것도 처음이고,Supbase로 OAuth를 이용해 카카오 로그인 기능을 구현하는 것도 처음이었다.시행착오를 거&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/770&quot; data-og-url=&quot;https://jun-coding.tistory.com/770&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/egpkps/hyZuGgqtST/ON7RroaRO4tTZz5lScXAYK/img.png?width=800&amp;amp;height=459&amp;amp;face=0_0_800_459,https://scrap.kakaocdn.net/dn/7NaQX/hyZuB0vdjJ/WRSqhmSCsxpXvZsmIHW2nK/img.png?width=800&amp;amp;height=459&amp;amp;face=0_0_800_459,https://scrap.kakaocdn.net/dn/bZezcs/hyZuDquJGu/TtyBwYhdCa5Vx8awUC64s0/img.png?width=2032&amp;amp;height=1167&amp;amp;face=0_0_2032_1167&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/770&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/770&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/egpkps/hyZuGgqtST/ON7RroaRO4tTZz5lScXAYK/img.png?width=800&amp;amp;height=459&amp;amp;face=0_0_800_459,https://scrap.kakaocdn.net/dn/7NaQX/hyZuB0vdjJ/WRSqhmSCsxpXvZsmIHW2nK/img.png?width=800&amp;amp;height=459&amp;amp;face=0_0_800_459,https://scrap.kakaocdn.net/dn/bZezcs/hyZuDquJGu/TtyBwYhdCa5Vx8awUC64s0/img.png?width=2032&amp;amp;height=1167&amp;amp;face=0_0_2032_1167');&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;Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요사이드 프로젝트 진행중에 '카카오 로그인' 기능을 추가하고자 했다.Next.js를 사용하는것도 처음이고,Supbase로 OAuth를 이용해 카카오 로그인 기능을 구현하는 것도 처음이었다.시행착오를 거&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 공식문서를 따라서 구현해보면서 카카오 로그인 기능을 구현해보려 한다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754602484924&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;Login with Kakao | Supabase Docs&quot; data-og-description=&quot;Add Kakao OAuth to your Supabase project&quot; data-og-host=&quot;supabase.com&quot; data-og-source-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao?queryGroups=environment&amp;amp;environment=server#add-login-code-to-your-client-app&quot; data-og-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f4xVz/hyZuJ5kdvv/bZ4GNY5cROZh20mPkYm6l0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ZgmD2/hyZuzayRcY/HB0J5WOCwOLtSVyixZcek0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/JmsMW/hyZuJ5kdkj/bA49XBgzBrkM4xVwd3oAKK/img.png?width=3452&amp;amp;height=1842&amp;amp;face=0_0_3452_1842&quot;&gt;&lt;a href=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao?queryGroups=environment&amp;amp;environment=server#add-login-code-to-your-client-app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao?queryGroups=environment&amp;amp;environment=server#add-login-code-to-your-client-app&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f4xVz/hyZuJ5kdvv/bZ4GNY5cROZh20mPkYm6l0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ZgmD2/hyZuzayRcY/HB0J5WOCwOLtSVyixZcek0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/JmsMW/hyZuJ5kdkj/bA49XBgzBrkM4xVwd3oAKK/img.png?width=3452&amp;amp;height=1842&amp;amp;face=0_0_3452_1842');&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;Login with Kakao | Supabase Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Add Kakao OAuth to your Supabase project&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;supabase.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;UI는 최대한 간단하게 하고, 기능 완성만 해볼것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그인 코드 추가하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;공식문서를 보면 다음과 같은 문구가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 서버 사이드 렌더링(SSR)이나 쿠키 기반의 인증 방식을 사용하지 않는다면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`@supabase/supabase-js`에 있는 `createClient`를 바로 사용하면 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 SSR을 사용한다면, Supbase 클라이언트를 만드는데에 SSR 가이드를 참고해라.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서 말한 SSR 가이드로 들어가보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(Supabase를 이미 Next.js에 설정한 사람들은 가볍게 보면 될 것 같다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=environment&amp;amp;environment=server&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=environment&amp;amp;environment=server&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754602701049&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;Creating a Supabase client for SSR | Supabase Docs&quot; data-og-description=&quot;Configure your Supabase client to use cookies&quot; data-og-host=&quot;supabase.com&quot; data-og-source-url=&quot;https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=environment&amp;amp;environment=server&quot; data-og-url=&quot;https://supabase.com/docs/guides/auth/server-side/creating-a-client&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLenYl/hyZuB0vg8D/nZLpTG9m15HQ3XJyM4BdQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/uaaGv/hyZuzBC5HK/q1y5NyKSjNzu2zNP6Ly9I1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=environment&amp;amp;environment=server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://supabase.com/docs/guides/auth/server-side/creating-a-client?queryGroups=environment&amp;amp;environment=server&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLenYl/hyZuB0vg8D/nZLpTG9m15HQ3XJyM4BdQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/uaaGv/hyZuzBC5HK/q1y5NyKSjNzu2zNP6Ly9I1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Creating a Supabase client for SSR | Supabase Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Configure your Supabase client to use cookies&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;supabase.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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`middleware.ts`&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대부분의 예시 코드는 여기에 있는 'Connect'를 누르면 나오는 Next.js 설정 코드와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 &lt;b&gt;'middleware.ts' 파일을 추가로 보여주고 있다.&lt;/b&gt;&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;스크린샷 2025-08-08 오전 6.44.46.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRrzWb/btsPKnx9HrK/GPPK5o8pMyUbwDZ4dbpL5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRrzWb/btsPKnx9HrK/GPPK5o8pMyUbwDZ4dbpL5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRrzWb/btsPKnx9HrK/GPPK5o8pMyUbwDZ4dbpL5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRrzWb%2FbtsPKnx9HrK%2FGPPK5o8pMyUbwDZ4dbpL5K%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 6.44.46.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SSR 가이드에 보면 Middleware 예시 코드에 다음과 같이 설명이 되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js에서 서버 컴포넌트는 쿠키를 설정할 수 없기 때문에, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클라이언트가 쿠키 갱신을 다루기 위해 미들웨어가 필요하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;미들웨어는 Supabase에 접근이 필요하거나, &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Supabase Auth에 의해 보호받을 모든 라우트 전에 실행된다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 두 가지 코드가 주어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저 &lt;u&gt;&lt;b&gt;`middleware.ts`&lt;/b&gt;&lt;/u&gt; 파일의 코드다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666; font-family: 'Nanum Gothic';&quot;&gt;(프로젝트의 루트에 하나만 생성하는 것이 Next.js 공식 문서의 권장 방식이다.)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754604678705&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// middleware.ts
import { type NextRequest } from 'next/server'
import { updateSession } from '@/utils/supabase/middleware'

export async function middleware(request: NextRequest) {
  return await updateSession(request)
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     * Feel free to modify this pattern to include more paths.
     */
    '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 코드의 주석을 보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주석에 써있는 경로들을 &lt;b&gt;제외한&lt;/b&gt; 모든 경로에서 미들웨어를 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`_next/static`(Next.js 정적 파일)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`_next/image`(Next.js 이미지 최적화)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`favicon.icon`(파비콘)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 파일들(svg, png, jpg 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`@/utils/supabase/middleware.ts`&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 미들웨어의 구현부는 &lt;u&gt;&lt;b&gt;`@/utils/supabase/middleware.ts`&lt;/b&gt;&lt;/u&gt;에 다음과 작성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754605073197&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'

export async function updateSession(request: NextRequest) {
  let supabaseResponse = NextResponse.next({
    request,
  })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll()
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value, options }) =&amp;gt; request.cookies.set(name, value))
          supabaseResponse = NextResponse.next({
            request,
          })
          cookiesToSet.forEach(({ name, value, options }) =&amp;gt;
            supabaseResponse.cookies.set(name, value, options)
          )
        },
      },
    }
  )

  // IMPORTANT: Avoid writing any logic between createServerClient and
  // supabase.auth.getClaims(). A simple mistake could make it very hard to debug
  // issues with users being randomly logged out.

  // IMPORTANT: Don't remove getClaims()
  const { data } = await supabase.auth.getClaims()

  const user = data?.claims

  if (
    !user &amp;amp;&amp;amp;
    !request.nextUrl.pathname.startsWith('/login') &amp;amp;&amp;amp;
    !request.nextUrl.pathname.startsWith('/auth')
  ) {
    // no user, potentially respond by redirecting the user to the login page
    const url = request.nextUrl.clone()
    url.pathname = '/login'
    return NextResponse.redirect(url)
  }

  // IMPORTANT: You *must* return the supabaseResponse object as it is. If you're
  // creating a new response object with NextResponse.next() make sure to:
  // 1. Pass the request in it, like so:
  //    const myNewResponse = NextResponse.next({ request })
  // 2. Copy over the cookies, like so:
  //    myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
  // 3. Change the myNewResponse object to fit your needs, but avoid changing
  //    the cookies!
  // 4. Finally:
  //    return myNewResponse
  // If this is not done, you may be causing the browser and server to go out
  // of sync and terminate the user's session prematurely!

  return supabaseResponse
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 코드는 앞서 본 `middleware.ts`에서 호출되는 &lt;b&gt;`updateSession()`함수&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Supabase 인증 세션을 관리하는 핵심 로직이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;코드를 나눠서 살펴보자.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, &lt;b&gt;Supbase 서버 클라이언트를 생성&lt;/b&gt;하는 부분이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754605438063&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll()
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value, options }) =&amp;gt; request.cookies.set(name, value))
          supabaseResponse = NextResponse.next({
            request,
          })
          cookiesToSet.forEach(({ name, value, options }) =&amp;gt;
            supabaseResponse.cookies.set(name, value, options)
          )
        },
      },
    }
  )&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버 환경에서 Supabase와 통신할 클라이언트를 생성하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;쿠키를 통해 인증 토큰을 주고 받도록 설정해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;요청에서 `getAll()`로 모든 쿠키를 읽고,&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;`setAll()`로 요청과 응답 모두에 쿠키를 설정해준다.&lt;/u&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로는 &lt;b&gt;사용자 인증을 확인&lt;/b&gt;하는 부분이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754605672630&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { data } = await supabase.auth.getClaims()
const user = data?.claims&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 요청의 인증 토큰에서 사용자 정보를 추출해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;로그인 리다이렉트 로직&lt;/b&gt; 부분이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754605716656&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (
  !user &amp;amp;&amp;amp;
  !request.nextUrl.pathname.startsWith('/login') &amp;amp;&amp;amp;
  !request.nextUrl.pathname.startsWith('/auth')
) {
  const url = request.nextUrl.clone()
  url.pathname = '/login'
  return NextResponse.redirect(url)
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;if문에서 세션을 체크해서 사용자가 로그인되어 있는지 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 만약 로그인하지 않은 사용자가 보호된 페이지에 접근하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`/login` 페이지로 자동으로 리다이렉트 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`/login`이나 `/auth`로 시작하는 경로는 비회원도 접근해야 하기 때문에 리다이렉트 해주지 않는다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 주석에서 강조하는 것이 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;다음을 꼭 지켜줘야 한다.&lt;/b&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&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`createServerClient`와 `getClaims()` 사이에 다른 로직을 넣으면 안된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`supbaseResponse` 객체를 반드시 그대로 반환해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;쿠키를 임의로 수정하면 세션이 깨질 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;font-family: 'Nanum Gothic';&quot;&gt;결론적으로, 이 코드는 &lt;b&gt;'자동 로그인 보호 기능'&lt;/b&gt;을 구현하는 로직이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그인 로직 코드 작성하기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;유저가 로그인할 때, &lt;b&gt;`signInWithOAuth()`를 'kakao' provider로 설정하여 호출&lt;/b&gt;하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754611054859&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function signInWithKakao() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'kakao',
  })
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본 형식은 위와 같고, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;보통 로그인이 성공하면 어떤 페이지로 이동(리다이렉트)해야 하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 방법이 클라이언트에서 처리하는 것과 서버에서 처리하는 방식이 다르다.&lt;/span&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;font-family: 'Nanum Gothic';&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저(클라이언트)에서는 자동으로 OAuth provider의 인증 엔드포인트로 리다이렉트 되고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 후, 내가 설정한 엔드포인트로 리다이렉트 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754834492812&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function signInWithKakao() {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'kakao',
    options: {
      redirectTo: `http://example.com/auth/callback`,
    },
  })
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;내가 프로젝트에 작성한 코드로는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래 코드를 본인이 만든 카카오 로그인 버튼에 이벤트 리스너로 달아주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754834725727&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const handleKakaoLogin = async () =&amp;gt; {
    const supabase = createClient();
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: 'kakao',
      options: {
        redirectTo: `${window.location.origin}/auth/callback`,
      },
    });
  };&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서버에서는, OAuth provider의 인증 엔드포인트로의 리디렉션을 처리해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`signInWithOAuth()` 메서드는 리다이렉트 할 수 있는 url을 반환해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754834781783&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { data, error } = await supabase.auth.signInWithOAuth({
  provider,
  options: {
    redirectTo: 'http://example.com/auth/callback',
  },
})

if (data.url) {
  redirect(data.url) // use the redirect API for your server framework
}&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;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;callback 엔드포인트에서는, 인증 코드를 교환해서 사용자 세션을 저장해야 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;`app/auth/callback/route.ts`에 다음과 같은 코드를 만들면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754835016523&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NextResponse } from 'next/server'
// The client you created from the Server-Side Auth instructions
import { createClient } from '@/utils/supabase/server'

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url)
  const code = searchParams.get('code')
  // if &quot;next&quot; is in param, use it as the redirect URL
  // 만약 성공시에 '/gallery'로 이동하고 싶다면 마지막을 '/' 대신 '/gallery'로 바꿔준다.
  let next = searchParams.get('next') ?? '/'
  if (!next.startsWith('/')) {
    // if &quot;next&quot; is not a relative URL, use the default
    // 마찬가지로 여기도 '/gallery'로 바꿔준다.
    next = '/'
  }

  if (code) {
    const supabase = await createClient()
    const { error } = await supabase.auth.exchangeCodeForSession(code)
    if (!error) {
      const forwardedHost = request.headers.get('x-forwarded-host') // original origin before load balancer
      const isLocalEnv = process.env.NODE_ENV === 'development'
      if (isLocalEnv) {
        // we can be sure that there is no load balancer in between, so no need to watch for X-Forwarded-Host
        return NextResponse.redirect(`${origin}${next}`)
      } else if (forwardedHost) {
        return NextResponse.redirect(`https://${forwardedHost}${next}`)
      } else {
        return NextResponse.redirect(`${origin}${next}`)
      }
    }
  }

  // return the user to an error page with instructions
  return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이것을 마지막으로 완료!&lt;/span&gt;&lt;/p&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/771</guid>
      <comments>https://jun-coding.tistory.com/771#entry771comment</comments>
      <pubDate>Mon, 11 Aug 2025 00:31:10 +0900</pubDate>
    </item>
    <item>
      <title>Next.js 15 + Supabase로 Kakao 로그인 구현하기 - 1</title>
      <link>https://jun-coding.tistory.com/770</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이드 프로젝트 진행중에 &lt;b&gt;'카카오 로그인' 기능&lt;/b&gt;을 추가하고자 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Next.js를 사용하는것도 처음이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Supbase로 OAuth를 이용해 카카오 로그인 기능을 구현하는 것도 처음이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시행착오를 거치면서 어떻게 구현했는지 남기고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(Supabase에 프로젝트는 미리 생성했고, Supabase 사용법에 관련해서는 따로 다루지 않을 예정)&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;font-family: 'Nanum Gothic';&quot;&gt;일단, Supabase의 공식문서에 방법이 나와있어서 참고하면서 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic'; color: #666666;&quot;&gt;(쉽고 자세하게 나와있으니, 영어 읽는데 거부감이 없다면 공식문서를 보고하는걸 추천!)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://supabase.com/docs/guides/auth/social-login/auth-kakao&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754565787095&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;Login with Kakao | Supabase Docs&quot; data-og-description=&quot;Add Kakao OAuth to your Supabase project&quot; data-og-host=&quot;supabase.com&quot; data-og-source-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot; data-og-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iCVZa/hyZuI6ljq8/kkJRtpyNZYzy4z5hQZBrLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/N55dc/hyZuvMJEei/7NLLpBPprpE0JOAC0jubmk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RtByV/hyZuAHdqxs/1Akhx0UJXKuX0DcKXvRDdk/img.png?width=3452&amp;amp;height=1842&amp;amp;face=0_0_3452_1842&quot;&gt;&lt;a href=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://supabase.com/docs/guides/auth/social-login/auth-kakao&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iCVZa/hyZuI6ljq8/kkJRtpyNZYzy4z5hQZBrLK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/N55dc/hyZuvMJEei/7NLLpBPprpE0JOAC0jubmk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RtByV/hyZuAHdqxs/1Akhx0UJXKuX0DcKXvRDdk/img.png?width=3452&amp;amp;height=1842&amp;amp;face=0_0_3452_1842');&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;Login with Kakao | Supabase Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Add Kakao OAuth to your Supabase project&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;supabase.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;REST API 키 설정하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단 Kakao Developers에서 본인 카카오 계정으로 로그인 후, 키 생성을 해주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developers.kakao.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754565879794&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;Kakao Developers&quot; data-og-description=&quot;카카오 API를 활용하여 다양한 어플리케이션을 개발해 보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&quot; data-og-host=&quot;developers.kakao.com&quot; data-og-source-url=&quot;https://developers.kakao.com/&quot; data-og-url=&quot;https://developers.kakao.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/B1vyg/hyZuBzmuV6/FVA5RHQoub1NbLaXTqEsx1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/gw2RF/hyZuGglfYY/GmbE9Z3oRwZzVsLakQU6DK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/burH6B/hyZuECP8Q3/84Is0lLWhk5UidiiiqPlo0/img.png?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developers.kakao.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/B1vyg/hyZuBzmuV6/FVA5RHQoub1NbLaXTqEsx1/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/gw2RF/hyZuGglfYY/GmbE9Z3oRwZzVsLakQU6DK/img.png?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/burH6B/hyZuECP8Q3/84Is0lLWhk5UidiiiqPlo0/img.png?width=1200&amp;amp;height=800&amp;amp;face=0_0_1200_800');&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;Kakao Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;카카오 API를 활용하여 다양한 어플리케이션을 개발해 보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developers.kakao.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단 로그인 후에, 상단 네비게이션 바에 &lt;b&gt;'앱'&lt;/b&gt;을 눌러준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OHnwM/btsPIruGpoC/Jq4uAXz2g68VbBtyPksMqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OHnwM/btsPIruGpoC/Jq4uAXz2g68VbBtyPksMqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OHnwM/btsPIruGpoC/Jq4uAXz2g68VbBtyPksMqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOHnwM%2FbtsPIruGpoC%2FJq4uAXz2g68VbBtyPksMqK%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;2032&quot; height=&quot;1167&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 이런 화면이 뜰텐데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미 생성한 키가 있다면 아래와 같이 뜨게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;새로 만들것이기 때문에 &lt;b&gt;'앱 생성'&lt;/b&gt; 버튼을 눌러주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bho3f/btsPJb6uwJE/kYkkrCRPZzJJMiNiZolTi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bho3f/btsPJb6uwJE/kYkkrCRPZzJJMiNiZolTi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bho3f/btsPJb6uwJE/kYkkrCRPZzJJMiNiZolTi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBho3f%2FbtsPJb6uwJE%2FkYkkrCRPZzJJMiNiZolTi1%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;2032&quot; height=&quot;1167&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 다음과 같이 필수 정보들을 입력해줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이드 프로젝트이기 때문에 아무렇게나 입력해줘도 상관없지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 회사 서비스 목적이라면 정확하게 입력해주는게 좋을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-07 오후 8.45.14.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFBxVU/btsPJYlhAPw/22Y4UQxBLtAQiTt7oTgMvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFBxVU/btsPJYlhAPw/22Y4UQxBLtAQiTt7oTgMvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFBxVU/btsPJYlhAPw/22Y4UQxBLtAQiTt7oTgMvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFBxVU%2FbtsPJYlhAPw%2F22Y4UQxBLtAQiTt7oTgMvK%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-07 오후 8.45.14.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;생성이 완료되었다면 바로 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클릭해서 대시보드로 들어가자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOGco8/btsPK4LLyCj/6tHwLf6pbfn6OLt8wJEWN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOGco8/btsPK4LLyCj/6tHwLf6pbfn6OLt8wJEWN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOGco8/btsPK4LLyCj/6tHwLf6pbfn6OLt8wJEWN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOGco8%2FbtsPK4LLyCj%2F6tHwLf6pbfn6OLt8wJEWN1%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;2032&quot; height=&quot;1167&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좌측의 '앱'의 '일반'탭을 눌러서 밑으로 조금 내러보면 &lt;b&gt;'앱 키'&lt;/b&gt; 부분이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 나중에 API 키를 사용할 때, 'REST API' 키를 사용할 것이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;복사를 해놓거나 어디서 보는지 위치를 기억해놓으면 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-07 오후 8.51.53.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T1BcH/btsPJg7Ii94/UZRNxkgBf3Cpdkplu42r61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T1BcH/btsPJg7Ii94/UZRNxkgBf3Cpdkplu42r61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T1BcH/btsPJg7Ii94/UZRNxkgBf3Cpdkplu42r61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT1BcH%2FbtsPJg7Ii94%2FUZRNxkgBf3Cpdkplu42r61%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;1988&quot; height=&quot;1123&quot; data-filename=&quot;스크린샷 2025-08-07 오후 8.51.53.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1123&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Callback URL 설정하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음으로 &lt;b&gt;'callback URL'&lt;/b&gt;이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left; font-family: 'Nanum Gothic';&quot;&gt;이 'callback URL'은 카카오 로그인 화면에서 인증을 완료하면,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left; font-family: 'Nanum Gothic';&quot;&gt;카카오 인증 서버는 인증 결과를 지정된 callback URL로 전달하며 사용자를 리다이렉트 해준다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left; font-family: 'Nanum Gothic';&quot;&gt;즉,&amp;nbsp;&lt;u&gt;&lt;b&gt;&quot;사용자가 인증 후 다시 우리 서비스로 안전하게 돌아오는 경로&quot;&lt;/b&gt;&lt;/u&gt;를 의미하며,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left; font-family: 'Nanum Gothic';&quot;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단, Supabase에 있는 만들어둔 프로젝트의 대시보드로 이동해준 후,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이드 바의 &lt;b&gt;'Authentication'&lt;/b&gt;을 클릭해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-07 오후 9.43.28.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VVcCZ/btsPJwicYsu/pg3KuOhCbWtNcKket5ZI00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VVcCZ/btsPJwicYsu/pg3KuOhCbWtNcKket5ZI00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VVcCZ/btsPJwicYsu/pg3KuOhCbWtNcKket5ZI00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVVcCZ%2FbtsPJwicYsu%2Fpg3KuOhCbWtNcKket5ZI00%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-07 오후 9.43.28.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로, &lt;b&gt;'Sign In / Providers'&lt;/b&gt;를 클릭해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 1.49.21.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YoGNt/btsPJ46Gbov/j2fxKAUdW7oia2JGJKLO0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YoGNt/btsPJ46Gbov/j2fxKAUdW7oia2JGJKLO0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YoGNt/btsPJ46Gbov/j2fxKAUdW7oia2JGJKLO0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYoGNt%2FbtsPJ46Gbov%2Fj2fxKAUdW7oia2JGJKLO0k%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 1.49.21.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;조금 내려보면, 'Auth Providers'에서 'Kakao'가 있는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;활성화 하기 위해서 'Disabled'라고 적힌 버튼을 눌러주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 1.56.21.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PaOek/btsPJhMp3E6/M52S7TN7pn158Ze3EkT4Gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PaOek/btsPJhMp3E6/M52S7TN7pn158Ze3EkT4Gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PaOek/btsPJhMp3E6/M52S7TN7pn158Ze3EkT4Gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPaOek%2FbtsPJhMp3E6%2FM52S7TN7pn158Ze3EkT4Gk%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 1.56.21.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래와 같은 창이 뜨는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'Kakao enabled'로 토글 버튼을 on 해주고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'REST API Key'에 아까 복사해둔 것을 넣어주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.05.00.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8Gtlh/btsPLl7AbW5/kDbryNPKcjPi6gBnyrYFHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8Gtlh/btsPLl7AbW5/kDbryNPKcjPi6gBnyrYFHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8Gtlh/btsPLl7AbW5/kDbryNPKcjPi6gBnyrYFHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8Gtlh%2FbtsPLl7AbW5%2FkDbryNPKcjPi6gBnyrYFHk%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.05.00.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'Client Secret Code'와 'Callback URL'은 다시 Kakao Developers로 가서 설정해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'Callback URL'은 복사해두자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이드바의 '카카오 로그인'의 '일반'으로 들어와서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 상태를 'on' 해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.01.48.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfSi35/btsPLIVNMxr/g5NAtb6TOxyyHLnsQi28Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfSi35/btsPLIVNMxr/g5NAtb6TOxyyHLnsQi28Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfSi35/btsPLIVNMxr/g5NAtb6TOxyyHLnsQi28Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfSi35%2FbtsPLIVNMxr%2Fg5NAtb6TOxyyHLnsQi28Xk%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.01.48.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 조금 내려보면 '리다이렉트 URI 등록' 버튼이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.02.33.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3ML0G/btsPLMjogHi/QCSEeVRwxyZeBm1piEIBXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3ML0G/btsPLMjogHi/QCSEeVRwxyZeBm1piEIBXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3ML0G/btsPLMjogHi/QCSEeVRwxyZeBm1piEIBXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3ML0G%2FbtsPLMjogHi%2FQCSEeVRwxyZeBm1piEIBXK%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.02.33.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;눌러보면 다음과 같은 창이 뜨는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 아까 Supabase에서 복사한 'Callback URL'을 넣어주고 저장해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.06.41.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtMbeP/btsPJCJk4bo/uDX1jgAKNdmsf5kyDfc7n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtMbeP/btsPJCJk4bo/uDX1jgAKNdmsf5kyDfc7n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtMbeP/btsPJCJk4bo/uDX1jgAKNdmsf5kyDfc7n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtMbeP%2FbtsPJCJk4bo%2FuDX1jgAKNdmsf5kyDfc7n1%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.06.41.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Client Secret key 설정하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 밑에있는 'Client Secret'은 발급받은 후에 코드를 복사해주고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;꼭 &lt;b&gt;'사용함'&lt;/b&gt;으로 설정해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.09.10.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2SAV/btsPLXd7lTi/MfUUDmihrYVYVE8N3RKx2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2SAV/btsPLXd7lTi/MfUUDmihrYVYVE8N3RKx2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2SAV/btsPLXd7lTi/MfUUDmihrYVYVE8N3RKx2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2SAV%2FbtsPLXd7lTi%2FMfUUDmihrYVYVE8N3RKx2K%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.09.10.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래와 같이 다 입력해줬다면, 'Save'를 눌러 저장해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.10.49.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/enaygP/btsPLEZ9iAH/s0HKjGt6n9rpi8CukWNYxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/enaygP/btsPLEZ9iAH/s0HKjGt6n9rpi8CukWNYxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/enaygP/btsPLEZ9iAH/s0HKjGt6n9rpi8CukWNYxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FenaygP%2FbtsPLEZ9iAH%2Fs0HKjGt6n9rpi8CukWNYxK%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.10.49.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다시 Kakao Developers로 돌아오자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 카카오 로그인 한 사용자의 정보들이 필요하다면 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사용자의 동의를 얻어 사용할 수 있도록 설정해주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사이드바에서 &lt;b&gt;'카카오 로그인' &lt;/b&gt;탭의&lt;b&gt; '동의항목'&lt;/b&gt;을 클릭해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.17.59.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qQ5EF/btsPLkniLHv/63pdCdN2BzHbmHze1Elz00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qQ5EF/btsPLkniLHv/63pdCdN2BzHbmHze1Elz00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qQ5EF/btsPLkniLHv/63pdCdN2BzHbmHze1Elz00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqQ5EF%2FbtsPLkniLHv%2F63pdCdN2BzHbmHze1Elz00%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;1988&quot; height=&quot;1123&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.17.59.png&quot; data-origin-width=&quot;1988&quot; data-origin-height=&quot;1123&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 이렇게 개인정보 동의항목들을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 서비스에 맞게 사용할 것들을 설정해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시를 위해 닉네임 설정하는 것만 보여주면 다음과 같다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, 동의 단계를 설정해준다. (개발중인 서비스에 맞게 설정, &lt;b&gt;아래 '더보기'를 꼭 봐주세요!!&lt;/b&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나중에 개발할 때, 'account_email'이 동의되지 않았다고 에러가 났었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;근데, 처음에 'account_email'을 동의항목으로 설정하려면 &lt;b&gt;'추가 기능 신청'&lt;/b&gt;을 해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같은 페이지에 '추가 기능 신청' 버튼이 있으니, 해당 페이지에서 수행해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개인 개발 목적으로 선택 항목들은 다 적지 않고 빈 칸으로 제출했는데도 됐다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그렇다고 &lt;b&gt;바로 승인되는 것은 아니고&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;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.18.47.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFRWf4/btsPKQGQhjw/V7N939zk8IjXEkibpGI4K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFRWf4/btsPKQGQhjw/V7N939zk8IjXEkibpGI4K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFRWf4/btsPKQGQhjw/V7N939zk8IjXEkibpGI4K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFRWf4%2FbtsPKQGQhjw%2FV7N939zk8IjXEkibpGI4K0%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.18.47.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로 동의 목적을 적어주는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기에 적어주는 것은 우리가 회원가입할 때 체크하도록 뜨는것들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;동의 목적은 다음과 같이 적어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.19.09.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvCk9e/btsPKWNO7jG/Yldhjx9Pqm20rFfkcY7SEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvCk9e/btsPKWNO7jG/Yldhjx9Pqm20rFfkcY7SEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvCk9e/btsPKWNO7jG/Yldhjx9Pqm20rFfkcY7SEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvCk9e%2FbtsPKWNO7jG%2FYldhjx9Pqm20rFfkcY7SEK%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.19.09.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 설정을 마친 후, 하단의 '동의 화면 미리보기' 버튼을 클릭하면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떻게 뜨는지 확인할 수 있으니 확인해보자!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.27.17.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tAyga/btsPKRltzdM/6mN91xlrPWW7drSTxuXDT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tAyga/btsPKRltzdM/6mN91xlrPWW7drSTxuXDT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tAyga/btsPKRltzdM/6mN91xlrPWW7drSTxuXDT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtAyga%2FbtsPKRltzdM%2F6mN91xlrPWW7drSTxuXDT0%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;2032&quot; height=&quot;1167&quot; data-filename=&quot;스크린샷 2025-08-08 오전 2.27.17.png&quot; data-origin-width=&quot;2032&quot; data-origin-height=&quot;1167&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 세팅을 모두 마치고 로그인 코드를 작성하는 일만 남았다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금 다른 웹 사이트 전혀 도움받지 않고 공식문서만 보고 하는중인데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자세히 설명이 되어있어서 다행이다...&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;코드를 작성하는 것은 다음 포스팅에서 이어서 작성,,,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Web/Next.js</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/770</guid>
      <comments>https://jun-coding.tistory.com/770#entry770comment</comments>
      <pubDate>Fri, 8 Aug 2025 02:30:55 +0900</pubDate>
    </item>
    <item>
      <title>Docker로 MySQL 실행시켜보기 - 3</title>
      <link>https://jun-coding.tistory.com/769</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 볼륨 이용해서 컨테이너 생성하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번에는 MySQL에 대한 데이터 정보를 호스트의 일부 어떤 공간의 데이터로 저장해보려고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서, 터미널에서 데이터를 저장할 경로에 들어가야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 포스팅에서는 'dev'라는 폴더를 만들어서 사용할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고, 기존의 컨테이너들은 모두 삭제해주었다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그리고나서, 하위 폴더에 'docker-mysql'이라는 폴더를 또 만들어주었다.&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;스크린샷 2025-08-06 오후 8.27.06.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmf4Tp/btsPHJuY8Ug/DGXWGdfRduu6HHdVZr5Mek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmf4Tp/btsPHJuY8Ug/DGXWGdfRduu6HHdVZr5Mek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmf4Tp/btsPHJuY8Ug/DGXWGdfRduu6HHdVZr5Mek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmf4Tp%2FbtsPHJuY8Ug%2FDGXWGdfRduu6HHdVZr5Mek%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;2562&quot; height=&quot;562&quot; data-filename=&quot;스크린샷 2025-08-06 오후 8.27.06.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`pwd`를 입력하면 현재 경로가 나오는데, 복사해두자.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 다음 명령어로 볼륨을 만들어주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754479707923&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -e MYSQL_ROOT_PASSWORD=[비밀번호] -d -p 3306:3306 -v [데이터를 저장할 경로] mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 8.31.21.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/egRFSb/btsPHePA8Jl/od2xfKa7nX1BWkJTH0yKHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/egRFSb/btsPHePA8Jl/od2xfKa7nX1BWkJTH0yKHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/egRFSb/btsPHePA8Jl/od2xfKa7nX1BWkJTH0yKHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FegRFSb%2FbtsPHePA8Jl%2Fod2xfKa7nX1BWkJTH0yKHK%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;2848&quot; height=&quot;480&quot; data-filename=&quot;스크린샷 2025-08-06 오후 8.31.21.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-v` 이전까지는 전에 MySQL을 실행시켰을 때랑 같은 명령어이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-v`는 볼륨을 만들겠다는 명령어이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 뒤에 경로를 입력해준 후, 마지막에 이미지명인 'mysql'을 적어준다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, 위 경로에서 ':/var/lib/mysql'은 무엇일까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker Hub의 MySQL에 있는 문서를 보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql#where-to-store-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hub.docker.com/_/mysql#where-to-store-data&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754480128071&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;mysql - Official Image | Docker Hub&quot; data-og-description=&quot;Quick reference 9.4.0, 9.4, 9, innovation, latest, 9.4.0-oraclelinux9, 9.4-oraclelinux9, 9-oraclelinux9, innovation-oraclelinux9, oraclelinux9, 9.4.0-oracle, 9.4-oracle, 9-oracle, innovation-oracle, oracle⁠ 8.4.6, 8.4, 8, lts, 8.4.6-oraclelinux9, 8.4-ora&quot; data-og-host=&quot;hub.docker.com&quot; data-og-source-url=&quot;https://hub.docker.com/_/mysql#where-to-store-data&quot; data-og-url=&quot;https://hub.docker.com/_/mysql#where-to-store-data&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://hub.docker.com/_/mysql#where-to-store-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hub.docker.com/_/mysql#where-to-store-data&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;mysql - Official Image | Docker Hub&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Quick reference 9.4.0, 9.4, 9, innovation, latest, 9.4.0-oraclelinux9, 9.4-oraclelinux9, 9-oraclelinux9, innovation-oraclelinux9, oraclelinux9, 9.4.0-oracle, 9.4-oracle, 9-oracle, innovation-oracle, oracle⁠ 8.4.6, 8.4, 8, lts, 8.4.6-oraclelinux9, 8.4-ora&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hub.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 8.35.42.png&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEPcbA/btsPKgZjLzF/KN4RvkhaLKw6oYhSyh12t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEPcbA/btsPKgZjLzF/KN4RvkhaLKw6oYhSyh12t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEPcbA/btsPKgZjLzF/KN4RvkhaLKw6oYhSyh12t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEPcbA%2FbtsPKgZjLzF%2FKN4RvkhaLKw6oYhSyh12t1%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;4024&quot; height=&quot;2294&quot; data-filename=&quot;스크린샷 2025-08-06 오후 8.35.42.png&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'Where to Store Data'를 보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL의 데이터 파일은 컨테이너 안에 `/var/lib/mysql` 경로에 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;저장된다고 적혀있기 때문에 똑같이 설정해주었다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;즉, 호스트의 `mysql_data` 폴더를 컨테이너 내부 MySQL 데이터 폴더에 연결해서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 내부의 MySQL 데이터가 이 폴더에 저장되고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너가 삭제되어도 데이터는 호스트에 남아 유지되게 하는 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;정확히 말하면, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;컨테이너의 `/var/lib/mysql`에 저장되는 데이터가&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;호스트의 `mysql_data` 폴더에도 저장되는 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 이제 볼륨을 만들어줬으니 한 번 확인해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;mysql로 들어가서 'mydb'라는 데이터베이스를 만들어주자.&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;스크린샷 2025-08-06 오후 9.25.38.png&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;1532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ex4Bhw/btsPIJ9jpQC/uWyyko72aIk5KZumNrGn1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ex4Bhw/btsPIJ9jpQC/uWyyko72aIk5KZumNrGn1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ex4Bhw/btsPIJ9jpQC/uWyyko72aIk5KZumNrGn1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fex4Bhw%2FbtsPIJ9jpQC%2FuWyyko72aIk5KZumNrGn1K%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;2760&quot; height=&quot;1532&quot; data-filename=&quot;스크린샷 2025-08-06 오후 9.25.38.png&quot; data-origin-width=&quot;2760&quot; data-origin-height=&quot;1532&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정상적으로 확인된다면, 이제 나와서 컨테이너를 삭제해보자.&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;스크린샷 2025-08-06 오후 9.27.42.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RqzCu/btsPIrADrGe/ZKjLIn0FyxRfYTiafyyreK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RqzCu/btsPIrADrGe/ZKjLIn0FyxRfYTiafyyreK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RqzCu/btsPIrADrGe/ZKjLIn0FyxRfYTiafyyreK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRqzCu%2FbtsPIrADrGe%2FZKjLIn0FyxRfYTiafyyreK%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;2848&quot; height=&quot;708&quot; data-filename=&quot;스크린샷 2025-08-06 오후 9.27.42.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;708&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 다시 만들어줄것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약, 볼륨이 정상적으로 작동이 되었다면 똑같은 명령어로 컨테이너를 생성했을 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같이 'mydb' 데이터베이스가 그대로 남아있을 것이다.&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;스크린샷 2025-08-06 오후 9.30.12.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;1506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAWjAS/btsPIgzzQP9/V7lcduJP88L7QzfQWUiXDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAWjAS/btsPIgzzQP9/V7lcduJP88L7QzfQWUiXDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAWjAS/btsPIgzzQP9/V7lcduJP88L7QzfQWUiXDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAWjAS%2FbtsPIgzzQP9%2FV7lcduJP88L7QzfQWUiXDK%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;2848&quot; height=&quot;1506&quot; data-filename=&quot;스크린샷 2025-08-06 오후 9.30.12.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;1506&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 구조를 그림으로 보면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;695&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUyUc6/btsPJenDxeu/xtJlVYkRIhqeAJQKc0kgOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUyUc6/btsPJenDxeu/xtJlVYkRIhqeAJQKc0kgOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUyUc6/btsPJenDxeu/xtJlVYkRIhqeAJQKc0kgOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUyUc6%2FbtsPJenDxeu%2FxtJlVYkRIhqeAJQKc0kgOK%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;1280&quot; height=&quot;695&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;695&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주의할 점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 내부의 데이터와,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리가 지정한 호스트의 폴더와 데이터를 동기화해놨으니 폴더 내부를 보면 데이터 파일들이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 9.39.03.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFltIu/btsPIfm2ZBI/INMKYorcFukgXQb6UjnROK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFltIu/btsPIfm2ZBI/INMKYorcFukgXQb6UjnROK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFltIu/btsPIfm2ZBI/INMKYorcFukgXQb6UjnROK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFltIu%2FbtsPIfm2ZBI%2FINMKYorcFukgXQb6UjnROK%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;2848&quot; height=&quot;708&quot; data-filename=&quot;스크린샷 2025-08-06 오후 9.39.03.png&quot; data-origin-width=&quot;2848&quot; data-origin-height=&quot;708&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 데이터 파일들은 MySQL 내부에서 데이터베이스 뿐만 아니라,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL 설정 파일들도 같이 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;따라서 만약 이 데이터를 사용하도록 볼륨을 이용하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른 비밀번호를 가진 컨테이너를 만들었다고 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 이 폴더에는 이미 이전에 만들었던 비밀번호 설정도 저장되어 있기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;새로운 비밀번호로 접속되지 않는다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;따라서 비밀번호를 다르게 지정하고 싶다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL에 접속해서 내부에서 비밀번호를 바꾸는 방법과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;호스트에 있는 볼륨 폴더를 지우는 방법이 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/769</guid>
      <comments>https://jun-coding.tistory.com/769#entry769comment</comments>
      <pubDate>Wed, 6 Aug 2025 21:43:27 +0900</pubDate>
    </item>
    <item>
      <title>Docker로 MySQL 실행시켜보기 - 2</title>
      <link>https://jun-coding.tistory.com/768</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 했던 것처럼 MySQL 비밀번호를 설정해주고 run을 해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 bash로 컨테이너에 접속해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/767&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.08.06 - [Docker] - Docker로 MySQL 실행시켜보기 - 1&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754470465744&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;Docker로 MySQL 실행시켜보기 - 1&quot; data-og-description=&quot;MySQL 이미지 다운로드하기도커 컨테이너, 볼륨을 활용해서 MySQL을 한번 실행시켜보자.그 전에, 먼저 이미지를 다운받아줘야 한다.Docker Hub에 들어가서 MySQL 이미지를 먼저 검색해보자.https://hub.dock&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/767&quot; data-og-url=&quot;https://jun-coding.tistory.com/767&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/fyR1a/hyZrzQbmfX/f1sgjMQl2uusH5FHol7Ezk/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/sKUVg/hyZuHziCtW/q85h3fnxlLGqPkl0oipIg1/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/ik140/hyZvvFmIOi/xATbIwOQi0ouMtsY5LDjL1/img.png?width=4024&amp;amp;height=2294&amp;amp;face=0_0_4024_2294&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/767&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/767&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/fyR1a/hyZrzQbmfX/f1sgjMQl2uusH5FHol7Ezk/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/sKUVg/hyZuHziCtW/q85h3fnxlLGqPkl0oipIg1/img.png?width=800&amp;amp;height=456&amp;amp;face=0_0_800_456,https://scrap.kakaocdn.net/dn/ik140/hyZvvFmIOi/xATbIwOQi0ouMtsY5LDjL1/img.png?width=4024&amp;amp;height=2294&amp;amp;face=0_0_4024_2294');&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;Docker로 MySQL 실행시켜보기 - 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 이미지 다운로드하기도커 컨테이너, 볼륨을 활용해서 MySQL을 한번 실행시켜보자.그 전에, 먼저 이미지를 다운받아줘야 한다.Docker Hub에 들어가서 MySQL 이미지를 먼저 검색해보자.https://hub.dock&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.53.42.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGv14e/btsPJdvp2Z2/47oKLMY6iaRTz9dw68YOAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGv14e/btsPJdvp2Z2/47oKLMY6iaRTz9dw68YOAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGv14e/btsPJdvp2Z2/47oKLMY6iaRTz9dw68YOAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGv14e%2FbtsPJdvp2Z2%2F47oKLMY6iaRTz9dw68YOAk%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;2562&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.53.42.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;664&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너에 접속했으니, MySQL에 접속해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 접속할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754470526414&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.55.57.png&quot; data-origin-width=&quot;2474&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SVGIM/btsPKnqmTUY/xHhVW9kq4YDY58IDr4Piy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SVGIM/btsPKnqmTUY/xHhVW9kq4YDY58IDr4Piy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SVGIM/btsPKnqmTUY/xHhVW9kq4YDY58IDr4Piy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSVGIM%2FbtsPKnqmTUY%2FxHhVW9kq4YDY58IDr4Piy0%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;2474&quot; height=&quot;712&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.55.57.png&quot; data-origin-width=&quot;2474&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비밀번호를 입력하라고 뜨는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전에 설정해준 비밀번호를 입력해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비밀번호를 타이핑하는 동안에 보이지 않는 것이 정상이니,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;입력을 완료하고 엔터를 눌러주면 위 이미지와 같이 정상 연결이 된다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데이터베이스 조회하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL에 정상 연결이 되면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL 명령어를 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 데이터베이스를 조회해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754476505899&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;show databases;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.35.46.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d84NWs/btsPHLM4IDg/DJYTh7BrVm6lH8kMSFoSx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d84NWs/btsPHLM4IDg/DJYTh7BrVm6lH8kMSFoSx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d84NWs/btsPHLM4IDg/DJYTh7BrVm6lH8kMSFoSx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd84NWs%2FbtsPHLM4IDg%2FDJYTh7BrVm6lH8kMSFoSx0%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;2562&quot; height=&quot;698&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.35.46.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;698&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기에 'mydb'라는 새로운 데이터베이스도 만들어보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754476599204&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create database mydb;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.36.57.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLBkCB/btsPJCInMpL/nQrAlCSWZ66PjtHXIyKgQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLBkCB/btsPJCInMpL/nQrAlCSWZ66PjtHXIyKgQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLBkCB/btsPJCInMpL/nQrAlCSWZ66PjtHXIyKgQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLBkCB%2FbtsPJCInMpL%2FnQrAlCSWZ66PjtHXIyKgQk%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;2562&quot; height=&quot;1208&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.36.57.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 이렇게 이전에는 없었던 'mydb'라는 데이터베이스가 생성된 것을 볼 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;이제 MySQL에서 나와서 MySQL를 실행시키고 있는 컨테이너를 삭제해보자.&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;스크린샷 2025-08-06 오후 7.38.32.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ7nW5/btsPGluzN6D/fKX4W9yqG1YGwcuZRHbgD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ7nW5/btsPGluzN6D/fKX4W9yqG1YGwcuZRHbgD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ7nW5/btsPGluzN6D/fKX4W9yqG1YGwcuZRHbgD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ7nW5%2FbtsPGluzN6D%2FfKX4W9yqG1YGwcuZRHbgD1%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;2562&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.38.32.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;732&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런 다음, 새로운 MySQL 컨테이너를 띄우고, 접속해보자.&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;스크린샷 2025-08-06 오후 7.41.11.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsVweE/btsPIKmQG6o/vmf28e69iMtgeL2QEV9UHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsVweE/btsPIKmQG6o/vmf28e69iMtgeL2QEV9UHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsVweE/btsPIKmQG6o/vmf28e69iMtgeL2QEV9UHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsVweE%2FbtsPIKmQG6o%2Fvmf28e69iMtgeL2QEV9UHk%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;2562&quot; height=&quot;868&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.41.11.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;868&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;데이터베이스를 다시 조회해보면, 아까 만들었던 'mydb' 데이터베이스가 사라진 것을 볼 수 있다.&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;스크린샷 2025-08-06 오후 7.41.44.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxeFz/btsPJgZ5ugx/vcasjKUXYkkh8Mgy3QYLD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxeFz/btsPJgZ5ugx/vcasjKUXYkkh8Mgy3QYLD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxeFz/btsPJgZ5ugx/vcasjKUXYkkh8Mgy3QYLD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnxeFz%2FbtsPJgZ5ugx%2FvcasjKUXYkkh8Mgy3QYLD0%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;2562&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-08-06 오후 7.41.44.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이와 같이, 컨테이너를 삭제하면 같은 이미지를 사용했더라도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 컨테이너에 있던 데이터는 모두 사라지는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/768</guid>
      <comments>https://jun-coding.tistory.com/768#entry768comment</comments>
      <pubDate>Wed, 6 Aug 2025 19:43:10 +0900</pubDate>
    </item>
    <item>
      <title>Docker로 MySQL 실행시켜보기 - 1</title>
      <link>https://jun-coding.tistory.com/767</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL 이미지 다운로드하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 컨테이너, 볼륨을 활용해서 MySQL을 한번 실행시켜보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 전에, 먼저 이미지를 다운받아줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker Hub에 들어가서 MySQL 이미지를 먼저 검색해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://hub.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hub.docker.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754377654792&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;Docker Hub Container Image Library | App Containerization&quot; data-og-description=&quot;Software supply chain Secure Your Supply Chain with Docker Hardened Images Use Docker's enterprise-grade base images: secure, stable, and backed by SLAs for Ubuntu, Debian, Java, and more. Regularly scanned and maintained with CVE remediation and long-term&quot; data-og-host=&quot;hub.docker.com&quot; data-og-source-url=&quot;https://hub.docker.com/&quot; data-og-url=&quot;https://hub.docker.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DtS8O/hyZuEWCEhp/hSksooYE4fzN89mcu7i6ck/img.png?width=3372&amp;amp;height=1896&amp;amp;face=0_0_3372_1896,https://scrap.kakaocdn.net/dn/FvbWn/hyZuvZGg0K/OJFGr5NEwb0sOHQltB2gv0/img.png?width=1020&amp;amp;height=396&amp;amp;face=0_0_1020_396&quot;&gt;&lt;a href=&quot;https://hub.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hub.docker.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DtS8O/hyZuEWCEhp/hSksooYE4fzN89mcu7i6ck/img.png?width=3372&amp;amp;height=1896&amp;amp;face=0_0_3372_1896,https://scrap.kakaocdn.net/dn/FvbWn/hyZuvZGg0K/OJFGr5NEwb0sOHQltB2gv0/img.png?width=1020&amp;amp;height=396&amp;amp;face=0_0_1020_396');&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;Docker Hub Container Image Library | App Containerization&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Software supply chain Secure Your Supply Chain with Docker Hardened Images Use Docker's enterprise-grade base images: secure, stable, and backed by SLAs for Ubuntu, Debian, Java, and more. Regularly scanned and maintained with CVE remediation and long-term&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hub.docker.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;mysql을 검색하고나서, 빨간 박스의 mysql 이미지를 클릭해주자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgpX5b/btsPGoqvVJ8/mrasagzVjgkU5Ze4irnlbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgpX5b/btsPGoqvVJ8/mrasagzVjgkU5Ze4irnlbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgpX5b/btsPGoqvVJ8/mrasagzVjgkU5Ze4irnlbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgpX5b%2FbtsPGoqvVJ8%2FmrasagzVjgkU5Ze4irnlbK%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;4024&quot; height=&quot;2294&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클릭하면, mysql 이미지에 대한 설명이 나와있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;조금만 밑으로 내리면 다음과 같이 이 이미지를 어떻게 사용해야 하는지 가이드가 나와있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nx6Wt/btsPHh54Nzh/LA4A8QMMcLeDf14JXd9XHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nx6Wt/btsPHh54Nzh/LA4A8QMMcLeDf14JXd9XHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nx6Wt/btsPHh54Nzh/LA4A8QMMcLeDf14JXd9XHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnx6Wt%2FbtsPHh54Nzh%2FLA4A8QMMcLeDf14JXd9XHk%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;4024&quot; height=&quot;2294&quot; data-origin-width=&quot;4024&quot; data-origin-height=&quot;2294&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 이미지에서 명령어를 한번 봐보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754378045582&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 명령어를 보면, MySQL을 처음 생성할 때 비밀번호를 뭘로 설정할 건지 입력해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래야 이 이미지가 정상적으로 실행된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 비밀번호를 설정하지 않으면 어떻게 될까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같이 정상적으로 다운로드 받아졌지만 `run`명령어를 사용했음에도 실행되지 않았다.&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;스크린샷 2025-08-05 오후 4.16.51.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1004&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgLJgs/btsPHjJv5Q5/jKxKvSTnscWnI6QVh9a1w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgLJgs/btsPHjJv5Q5/jKxKvSTnscWnI6QVh9a1w0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgLJgs/btsPHjJv5Q5/jKxKvSTnscWnI6QVh9a1w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgLJgs%2FbtsPHjJv5Q5%2FjKxKvSTnscWnI6QVh9a1w0%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;1570&quot; height=&quot;1004&quot; data-filename=&quot;스크린샷 2025-08-05 오후 4.16.51.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1004&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서, `docker ps -a`로 모든 컨테이너를 조회해보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중단된 mysql 컨테이너를 볼 수 있다.&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;스크린샷 2025-08-05 오후 4.30.44.png&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UPCDR/btsPHlHlT29/Sx3pKpp3gifoDtg2TgQ6f0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UPCDR/btsPHlHlT29/Sx3pKpp3gifoDtg2TgQ6f0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UPCDR/btsPHlHlT29/Sx3pKpp3gifoDtg2TgQ6f0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUPCDR%2FbtsPHlHlT29%2FSx3pKpp3gifoDtg2TgQ6f0%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;2178&quot; height=&quot;494&quot; data-filename=&quot;스크린샷 2025-08-05 오후 4.30.44.png&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;494&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;디버깅 하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데 왜 종료됐는지 알 수 없기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 배웠던 로그를 활용해서 디버깅을 해 볼 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/764&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.31 - [Docker] - 컨테이너 로그 조회하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754398118827&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;컨테이너 로그 조회하기&quot; data-og-description=&quot;개요로그(log)는 굉장히 중요한 정보이다.흔히 디버깅 할 때, 디버깅 툴도 많이 이용하지만,간단히 디버깅 하기 위해서는 &amp;#96;console.log()&amp;#96; 같은 명령어도 많이 이용했다.지금 이 글을 작성하기 전까지&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/764&quot; data-og-url=&quot;https://jun-coding.tistory.com/764&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/9m4sM/hyZuECp5IC/XsZ4zzZaOVZCpgKeg5P4j1/img.png?width=800&amp;amp;height=139&amp;amp;face=0_0_800_139,https://scrap.kakaocdn.net/dn/cOUP7W/hyZqWrcS0H/lrepiS3CgsqK48kBsBhrbk/img.png?width=800&amp;amp;height=139&amp;amp;face=0_0_800_139,https://scrap.kakaocdn.net/dn/bhqJqu/hyZqVy4bRH/U4KZwuwekQszuKhqYcXbBK/img.png?width=2436&amp;amp;height=1446&amp;amp;face=0_0_2436_1446&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/764&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/764&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/9m4sM/hyZuECp5IC/XsZ4zzZaOVZCpgKeg5P4j1/img.png?width=800&amp;amp;height=139&amp;amp;face=0_0_800_139,https://scrap.kakaocdn.net/dn/cOUP7W/hyZqWrcS0H/lrepiS3CgsqK48kBsBhrbk/img.png?width=800&amp;amp;height=139&amp;amp;face=0_0_800_139,https://scrap.kakaocdn.net/dn/bhqJqu/hyZqVy4bRH/U4KZwuwekQszuKhqYcXbBK/img.png?width=2436&amp;amp;height=1446&amp;amp;face=0_0_2436_1446');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너 로그 조회하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요로그(log)는 굉장히 중요한 정보이다.흔히 디버깅 할 때, 디버깅 툴도 많이 이용하지만,간단히 디버깅 하기 위해서는 `console.log()` 같은 명령어도 많이 이용했다.지금 이 글을 작성하기 전까지&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre id=&quot;code_1754398222715&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PdA7x/btsPIGxakRx/LAzFrefXx9geZTEtg51aZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PdA7x/btsPIGxakRx/LAzFrefXx9geZTEtg51aZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PdA7x/btsPIGxakRx/LAzFrefXx9geZTEtg51aZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPdA7x%2FbtsPIGxakRx%2FLAzFrefXx9geZTEtg51aZk%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;2178&quot; height=&quot;834&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;834&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러 로그를 보면,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;Database is uninitialized and password option is not specified&quot;&lt;/b&gt;&lt;/span&gt; 라고 되어있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비밀번호 옵션이 정해지지 않아서 데이터베이스가 실행되지 않았다는 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 그 바로 뒤에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;You need to specify one of the following as an environment variable:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;- MYSQL_ROOT_PASSWORD&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;- MYSQL_ALLOW_EMPTY_PASSWORD&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;- MYSQL_RANDOM_ROOT_PASSWORD&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라고 나오는데, 이 중에서 하나의 환경 변수를 설정하라고 나온다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그래서 옵션을 설정해서 다시 실행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754459716998&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -e MYSQL_ROOT_PASSWORD=[비밀번호] -d -p 3306:3306 mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 2.57.49.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVP4Io/btsPIfNUqB4/ltECGsxCs4V5lSrVXhhiYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVP4Io/btsPIfNUqB4/ltECGsxCs4V5lSrVXhhiYk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVP4Io/btsPIfNUqB4/ltECGsxCs4V5lSrVXhhiYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVP4Io%2FbtsPIfNUqB4%2FltECGsxCs4V5lSrVXhhiYk%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;2562&quot; height=&quot;562&quot; data-filename=&quot;스크린샷 2025-08-06 오후 2.57.49.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 위와 같이 컨테이너가 잘 실행중인 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 &lt;b&gt;`-e` 옵션은 환경 변수를 설정하는 옵션이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`MYSQL_ROOT_PASSWORD` 라는 환경 변수를 읽어가서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음 환경 세팅을 할 때, 설정해준 비밀번호 값으로 MySQL을 세팅하도록 하는 것이다.&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;font-family: 'Nanum Gothic';&quot;&gt;환경 변수도 잘 설정이 되었는지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`docker exec -it` 명령어를 통해서 컨테이너에 들어가준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 다음 명령어로 설정한 환경변수를 조회해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1754460194970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo $MYSQL_ROOT_PASSWORD&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 3.01.46.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbeWCw/btsPKHWqvzq/ensbd5nyZz5w6hpPgADIp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbeWCw/btsPKHWqvzq/ensbd5nyZz5w6hpPgADIp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbeWCw/btsPKHWqvzq/ensbd5nyZz5w6hpPgADIp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbeWCw%2FbtsPKHWqvzq%2Fensbd5nyZz5w6hpPgADIp0%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;2562&quot; height=&quot;630&quot; data-filename=&quot;스크린샷 2025-08-06 오후 3.01.46.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;GUI로 연결 확인해보기(DBweaver 사용)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 확인까지 했으면, DB가 정상적으로 작동하는 것 처럼 보인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, 좀 더 확실히 하기 위해 GUI로 확인해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설치되어있는 MySQL Workbench나 여러 DB 툴 아무거나 사용해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서는 'DBeaver' 라는 툴을 사용해보겠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://dbeaver.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://dbeaver.io/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754466079342&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;DBeaver Community | Free Universal Database Tool&quot; data-og-description=&quot;DBeaver Universal Database Tool DBeaver Community is a free cross-platform database tool for developers, database administrators, analysts, and everyone working with data. It supports all popular SQL databases like MySQL, MariaDB, PostgreSQL, SQLite, Apach&quot; data-og-host=&quot;dbeaver.io&quot; data-og-source-url=&quot;https://dbeaver.io/&quot; data-og-url=&quot;https://dbeaver.io/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/VTQWD/hyZuIkFNmp/zuUDrkUuRXNCKsmWBUbT41/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220,https://scrap.kakaocdn.net/dn/be9dBE/hyZuJ4V8Zy/KfqUQInWH0AVUnY2y9IFdk/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220,https://scrap.kakaocdn.net/dn/hdJiK/hyZrxY9hlh/hVQLTxer8x3D6rQKgJDGN1/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220&quot;&gt;&lt;a href=&quot;https://dbeaver.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dbeaver.io/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/VTQWD/hyZuIkFNmp/zuUDrkUuRXNCKsmWBUbT41/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220,https://scrap.kakaocdn.net/dn/be9dBE/hyZuJ4V8Zy/KfqUQInWH0AVUnY2y9IFdk/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220,https://scrap.kakaocdn.net/dn/hdJiK/hyZrxY9hlh/hVQLTxer8x3D6rQKgJDGN1/img.png?width=450&amp;amp;height=220&amp;amp;face=0_0_450_220');&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;DBeaver Community | Free Universal Database Tool&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;DBeaver Universal Database Tool DBeaver Community is a free cross-platform database tool for developers, database administrators, analysts, and everyone working with data. It supports all popular SQL databases like MySQL, MariaDB, PostgreSQL, SQLite, Apach&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dbeaver.io&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;운영체제에 맞게 다운로드 했으면, 실행시켜주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행하고, 왼쪽 위에 DB를 추가할 수 있는 버튼이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2492&quot; data-origin-height=&quot;1696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnCFnk/btsPKnKCCiq/ILIXXqCcfXOMzG1fcJul9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnCFnk/btsPKnKCCiq/ILIXXqCcfXOMzG1fcJul9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnCFnk/btsPKnKCCiq/ILIXXqCcfXOMzG1fcJul9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnCFnk%2FbtsPKnKCCiq%2FILIXXqCcfXOMzG1fcJul9k%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;2492&quot; height=&quot;1696&quot; data-origin-width=&quot;2492&quot; data-origin-height=&quot;1696&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클릭해주면, 다음과 같은 여러 종류의 DB가 뜨는데&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL을 눌러주면 된다.&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;스크린샷 2025-08-06 오후 4.43.53.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XvKfc/btsPJVuc8hK/kFwC6aEInmnM9pzadNWb91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XvKfc/btsPJVuc8hK/kFwC6aEInmnM9pzadNWb91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XvKfc/btsPJVuc8hK/kFwC6aEInmnM9pzadNWb91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXvKfc%2FbtsPJVuc8hK%2FkFwC6aEInmnM9pzadNWb91%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;326&quot; height=&quot;372&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.43.53.png&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;728&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;MySQL의 기본 Username은 'root'로 설정되어 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Password 부분엔 설정해준 비밀번호를 눌러주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 하단의 'Test Connection'을 눌러주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.48.05.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmXXmt/btsPJftbXvL/5hGmR6qapayIjohVjdKpkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmXXmt/btsPJftbXvL/5hGmR6qapayIjohVjdKpkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmXXmt/btsPJftbXvL/5hGmR6qapayIjohVjdKpkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmXXmt%2FbtsPJftbXvL%2F5hGmR6qapayIjohVjdKpkk%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.48.05.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면, MySQL 드라이버가 없다고 다운로드 하라고 뜨는데 다운로드 해주자.&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;스크린샷 2025-08-06 오후 4.49.24.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GjEDt/btsPIHcoyAm/0o5z50p3UbDPs8R2QVk12k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GjEDt/btsPIHcoyAm/0o5z50p3UbDPs8R2QVk12k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GjEDt/btsPIHcoyAm/0o5z50p3UbDPs8R2QVk12k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGjEDt%2FbtsPIHcoyAm%2F0o5z50p3UbDPs8R2QVk12k%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.49.24.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다운로드가 완료된 뒤,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다시 'Test Connection'을 해주면 아래와 같은 에러가 뜰 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;'Public Key Retrieval is not allowed'&lt;/b&gt;&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;스크린샷 2025-08-06 오후 4.51.04.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/14Wzc/btsPJ1OJ7Yp/lrgOjJ27z2PB86aM4QghGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/14Wzc/btsPJ1OJ7Yp/lrgOjJ27z2PB86aM4QghGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/14Wzc/btsPJ1OJ7Yp/lrgOjJ27z2PB86aM4QghGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F14Wzc%2FbtsPJ1OJ7Yp%2FlrgOjJ27z2PB86aM4QghGK%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.51.04.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 에러는 MySQL 8.0 이상 버전에서 클라이언트, 즉 GUI 같은 툴로 DB 접속 시 나타나는 인증 방식 관련 에러이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 에러는 보안 강화를 위해서 기본 인증 방식이 변경되었기 때문에 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;해결법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 'Driver properties'에 들어간다.&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;스크린샷 2025-08-06 오후 4.53.27.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGaT7/btsPKV1pk9Z/HJV7jmhAag5yUtj6rCpjxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGaT7/btsPKV1pk9Z/HJV7jmhAag5yUtj6rCpjxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGaT7/btsPKV1pk9Z/HJV7jmhAag5yUtj6rCpjxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGaT7%2FbtsPKV1pk9Z%2FHJV7jmhAag5yUtj6rCpjxK%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.53.27.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;비어있는 부분에 우클릭을 해서 'Add new property'를 눌러주자.&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;스크린샷 2025-08-06 오후 4.54.51.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qd2BW/btsPKJth9uA/bBDGGFjg4mgfs24OLevhyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qd2BW/btsPKJth9uA/bBDGGFjg4mgfs24OLevhyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qd2BW/btsPKJth9uA/bBDGGFjg4mgfs24OLevhyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqd2BW%2FbtsPKJth9uA%2FbBDGGFjg4mgfs24OLevhyK%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.54.51.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음, 'allowPublicKeyRetrieval' 라는 property를 추가해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;값은 true로 설정해주자.&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;스크린샷 2025-08-06 오후 4.57.00.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQBBgx/btsPKgx7M4V/DImg8uDu1bxuPA1J6FuFt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQBBgx/btsPKgx7M4V/DImg8uDu1bxuPA1J6FuFt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQBBgx/btsPKgx7M4V/DImg8uDu1bxuPA1J6FuFt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQBBgx%2FbtsPKgx7M4V%2FDImg8uDu1bxuPA1J6FuFt0%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.57.00.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.57.24.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciR78G/btsPJii9mVc/ol5qjtMeak5RjwRfzYCJK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciR78G/btsPJii9mVc/ol5qjtMeak5RjwRfzYCJK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciR78G/btsPJii9mVc/ol5qjtMeak5RjwRfzYCJK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciR78G%2FbtsPJii9mVc%2Fol5qjtMeak5RjwRfzYCJK1%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.57.24.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 다시 'Test Connection'을 눌러주면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;드디어 Connected가 뜨면서 연결이 잘 된것을 확인할 수 있다!&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;스크린샷 2025-08-06 오후 4.59.00.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVrm6H/btsPJYdsaYr/YY0Wke3KKDgCqdlI4LinR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVrm6H/btsPJYdsaYr/YY0Wke3KKDgCqdlI4LinR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVrm6H/btsPJYdsaYr/YY0Wke3KKDgCqdlI4LinR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVrm6H%2FbtsPJYdsaYr%2FYY0Wke3KKDgCqdlI4LinR1%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 4.59.00.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;GUI로 연결 확인해보기 - 컨테이너 종료&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 실행시켰을 때 연결은 잘 확인했으니,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너가 종료되었을 때도 어떻게 되는지 확인해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 컨테이너를 종료시켜줌과 동시에 삭제까지 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.08.13.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Up5LQ/btsPJjbmWDo/GKqkNt1NWpaLDOreFQVL1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Up5LQ/btsPJjbmWDo/GKqkNt1NWpaLDOreFQVL1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Up5LQ/btsPJjbmWDo/GKqkNt1NWpaLDOreFQVL1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUp5LQ%2FbtsPJjbmWDo%2FGKqkNt1NWpaLDOreFQVL1k%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;2562&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.08.13.png&quot; data-origin-width=&quot;2562&quot; data-origin-height=&quot;664&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;DBweaver에서 다시 'Test Connection'을 해보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'Connection refused'가 뜨면서 연결이 실패하는 것을 볼 수 있다.&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;스크린샷 2025-08-06 오후 5.08.44.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxYtPh/btsPJtEMNzV/9xTEzsAkw7iAlT8b9EF0Uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxYtPh/btsPJtEMNzV/9xTEzsAkw7iAlT8b9EF0Uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxYtPh/btsPJtEMNzV/9xTEzsAkw7iAlT8b9EF0Uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxYtPh%2FbtsPJtEMNzV%2F9xTEzsAkw7iAlT8b9EF0Uk%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;2404&quot; height=&quot;1608&quot; data-filename=&quot;스크린샷 2025-08-06 오후 5.08.44.png&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;1608&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마무리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금까지의 과정을 그림으로 나타내면 아래와 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;705&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCNzw/btsPJdIVdCY/XX6M8zjVGDHvep3rEMigt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCNzw/btsPJdIVdCY/XX6M8zjVGDHvep3rEMigt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCNzw/btsPJdIVdCY/XX6M8zjVGDHvep3rEMigt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCNzw%2FbtsPJdIVdCY%2FXX6M8zjVGDHvep3rEMigt1%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;1280&quot; height=&quot;705&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;705&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;font-family: 'Nanum Gothic';&quot;&gt;하지만, 문제점이 하나 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 종료시키고 삭제하거나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;새로운 컨테이너로 갈아끼우면 컨테이너 안에 있던 데이터가 모두 유실된다는 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;따라서, 다음 포스팅부터는 '볼륨'을 통해서 이 문제를 해결해보도록 하겠다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/767</guid>
      <comments>https://jun-coding.tistory.com/767#entry767comment</comments>
      <pubDate>Wed, 6 Aug 2025 17:12:20 +0900</pubDate>
    </item>
    <item>
      <title>도커 볼륨이란?</title>
      <link>https://jun-coding.tistory.com/766</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;컨테이너가 가진 문제점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 활용하면 특정 프로그램을 컨테이너로 띄울 수 있다.&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;b&gt;Docker는 변경된 부분을 수정하는것이 아니라,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새로운 컨테이너를 만들어서 통째로 갈아 끼워야 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 특징 때문에 &lt;b&gt;기존 컨테이너를 새로운 컨테이너로 교체하면,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기존 컨테이너에 있던 데이터도 같이 사라진다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 컨테이너가 DB를 실행시키는 컨테이너였다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 저장된 데이터도 같이 삭제되는것이다.&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;b&gt;'&lt;span style=&quot;color: #8a3db6;&quot;&gt;볼륨(Volume)&lt;/span&gt;'&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;도커 컨테이너에서 데이터를 영속적으로 저장하기 위한 방법&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;호스트 자체의 저장 공간을 공유해서 사용하는 형태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hm6ub/btsPD1Qrwwj/IZBxz1815nKUDHtzgPInl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hm6ub/btsPD1Qrwwj/IZBxz1815nKUDHtzgPInl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hm6ub/btsPD1Qrwwj/IZBxz1815nKUDHtzgPInl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHm6ub%2FbtsPD1Qrwwj%2FIZBxz1815nKUDHtzgPInl1%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;1280&quot; height=&quot;726&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&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;전역 변수 처럼, 컨테이너 외부에 데이터를 저장해서&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;h3 data-ke-size=&quot;size23&quot;&gt;볼륨 사용하기&lt;/h3&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;pre id=&quot;code_1754296157091&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -v [호스트의 디렉터리 절대경로]:[컨테이너의 디렉터리 절대경로] [이미지명]:[태그명]&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;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;호스트의 디렉터리가 컨테이너의 디렉터리를 덮어씌운다.&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;1280&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ehy2JF/btsPEL02xZZ/WkKbHxQZ47cdkBzNHGRPxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ehy2JF/btsPEL02xZZ/WkKbHxQZ47cdkBzNHGRPxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ehy2JF/btsPEL02xZZ/WkKbHxQZ47cdkBzNHGRPxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fehy2JF%2FbtsPEL02xZZ%2FWkKbHxQZ47cdkBzNHGRPxk%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;1280&quot; height=&quot;718&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;718&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;`[호스트의 디렉터리 절대경로]`에 디렉터리가 존재하지 않을 경우,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;호스트의 디렉터리 절대 경로에 디렉터리를 새로 만들고,&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컨테이너의 디렉터리에 있는 파일들을 호스트의 디렉터리로 복사해온다.&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;1280&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO0EdT/btsPHiwopLt/Wh3YjrXrZP2Z0NMGyQNfBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO0EdT/btsPHiwopLt/Wh3YjrXrZP2Z0NMGyQNfBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO0EdT/btsPHiwopLt/Wh3YjrXrZP2Z0NMGyQNfBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO0EdT%2FbtsPHiwopLt%2FWh3YjrXrZP2Z0NMGyQNfBk%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;1280&quot; height=&quot;722&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/766</guid>
      <comments>https://jun-coding.tistory.com/766#entry766comment</comments>
      <pubDate>Mon, 4 Aug 2025 18:30:11 +0900</pubDate>
    </item>
    <item>
      <title>실행중인 컨테이너 내부에 접속하기</title>
      <link>https://jun-coding.tistory.com/765</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너는 호스트 컴퓨터 내부에 있는 각각의 독립된 공간이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서, 각각 본인의 운영체제, 실행환경, 저장공간 등 본인의 환경을 가지고 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그래서 우리는 어떤 컨테이너 안의 어떤 파일을 보고싶을 때가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금까지는 컨테이너를 조회하고 실행하는데 그쳤지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;안의 파일들은 어떻게 볼 수 있을까?&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 접속하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너는 다음과 같은 명령어로 접속할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753949423319&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it [CONTAINTER ID] [컨테이너 내에서 실행할 명령어]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오후 5.11.02.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NEZGz/btsPDXMLAHr/s7gNzwLYn7vjKkUVJJvDjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NEZGz/btsPDXMLAHr/s7gNzwLYn7vjKkUVJJvDjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NEZGz/btsPDXMLAHr/s7gNzwLYn7vjKkUVJJvDjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNEZGz%2FbtsPDXMLAHr%2Fs7gNzwLYn7vjKkUVJJvDjK%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;1914&quot; height=&quot;508&quot; data-filename=&quot;스크린샷 2025-07-31 오후 5.11.02.png&quot; data-origin-width=&quot;1914&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명령어를 하나씩 뜯어보면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`docker exec`은 이미 실행 중인 컨테이너 안에서 명령어를 실행할 때 사용하는 명령이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-i` 옵션은 컨테이너의 표준 입력을 활성화해서 상호작용을 할 수 있게 해주고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-t` 옵션은 TTY 모드를 활성화해 터미널 세션처럼 사용할 수 있게 해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;보통 위와 같이 `-it`로 같이 사용해 터미널 환경을 만들어준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 `bash`는 bash 셸을 실행해서 쉘 환경에 들어가겠다는 뜻이다.&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;font-family: 'Nanum Gothic';&quot;&gt;참고로 TTY는 &lt;b&gt;T&lt;/b&gt;ele&lt;b&gt;TY&lt;/b&gt;periter의 약자로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컴퓨터와 연결된 가상의 터미널, 즉 사용자가 텍스트 입력과 출력을 할 수 있는 환경을 뜻한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;모두 마친 뒤, `ls`로 파일 리스트를 보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 폴더와 파일들이 있는데 etc로 들어가주자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 우리가 설치했던 nginx가 있는 것을 볼 수 있다.&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;스크린샷 2025-07-31 오후 5.17.31.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;834&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5ZFFT/btsPC7vSwa2/WhnIliKcXbCZb9Ndyggjok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5ZFFT/btsPC7vSwa2/WhnIliKcXbCZb9Ndyggjok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5ZFFT/btsPC7vSwa2/WhnIliKcXbCZb9Ndyggjok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5ZFFT%2FbtsPC7vSwa2%2FWhnIliKcXbCZb9Ndyggjok%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;2002&quot; height=&quot;834&quot; data-filename=&quot;스크린샷 2025-07-31 오후 5.17.31.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;834&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;nginx로 들어가서 설정파일인 nginx.conf 파일의 코드를 봐보자.&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;스크린샷 2025-07-31 오후 5.23.21.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9LWXZ/btsPC4ToDoB/Krur4wpVcGownwQgbGw8y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9LWXZ/btsPC4ToDoB/Krur4wpVcGownwQgbGw8y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9LWXZ/btsPC4ToDoB/Krur4wpVcGownwQgbGw8y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9LWXZ%2FbtsPC4ToDoB%2FKrur4wpVcGownwQgbGw8y1%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;2002&quot; height=&quot;1548&quot; data-filename=&quot;스크린샷 2025-07-31 오후 5.23.21.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;1548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`cat` 명령어를 사용해 위와 같이 내부 코드도 볼 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;만약 이제 컨테이너에서 나오고 싶으면 간단하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`exit`를 입력하면 본인 컴퓨터 환경으로 다시 돌아올 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/765</guid>
      <comments>https://jun-coding.tistory.com/765#entry765comment</comments>
      <pubDate>Thu, 31 Jul 2025 17:26:18 +0900</pubDate>
    </item>
    <item>
      <title>컨테이너 로그 조회하기</title>
      <link>https://jun-coding.tistory.com/764</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로그(log)는 굉장히 중요한 정보이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;흔히 디버깅 할 때, 디버깅 툴도 많이 이용하지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단히 디버깅 하기 위해서는 `console.log()` 같은 명령어도 많이 이용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금 이 글을 작성하기 전까지 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왜 `console.print()`가 아닌 `console.log()`일까라는 생각을 못해봤다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정말 단순히 콘솔에 '로그'를 남긴다는 의미이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;'로그', 즉 '기록'을 남기면서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 기록으로 어디가 잘못되었는지 디버깅을 하는것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;컨테이너도 마찬가지로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 컨테이너가 잘 실행되고 있는지,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;혹은 에러가 났는지 알기위해서 로그를 읽어보는 것이 중요하다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;그런데, 우리는 사실 이미 로그를 봤다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`docker run -d nginx` 명령어는 background에서 실행하는 명령어였다.&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;스크린샷 2025-07-31 오전 10.34.59.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYVvWD/btsPE2sNzBb/VIuQ683orI7etgLjmeBLek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYVvWD/btsPE2sNzBb/VIuQ683orI7etgLjmeBLek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYVvWD/btsPE2sNzBb/VIuQ683orI7etgLjmeBLek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYVvWD%2FbtsPE2sNzBb%2FVIuQ683orI7etgLjmeBLek%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;2436&quot; height=&quot;426&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.34.59.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;426&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, `-d` 없이 foreground에서 실행하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실시간 로그들을 볼 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.35.52.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;1446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvJxv5/btsPB40zmZ5/kQeuxL8v1A90cfjZ9Oq0Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvJxv5/btsPB40zmZ5/kQeuxL8v1A90cfjZ9Oq0Q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvJxv5/btsPB40zmZ5/kQeuxL8v1A90cfjZ9Oq0Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvJxv5%2FbtsPB40zmZ5%2FkQeuxL8v1A90cfjZ9Oq0Q0%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;2436&quot; height=&quot;1446&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.35.52.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;1446&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 로그 조회하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, 위 방법으로 실행할 경우에는 터미널에서 다른 명령어를 입력할 수 없다는 단점이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 background로 실행중인 컨테이너의 로그를 보고 싶다면 어떻게 할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 조회할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753925984520&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.39.51.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;1446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyKkdr/btsPDVgRkGk/N4qY2vkD38OTRkIqZh2c80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyKkdr/btsPDVgRkGk/N4qY2vkD38OTRkIqZh2c80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyKkdr/btsPDVgRkGk/N4qY2vkD38OTRkIqZh2c80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyKkdr%2FbtsPDVgRkGk%2FN4qY2vkD38OTRkIqZh2c80%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;2436&quot; height=&quot;1446&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.39.51.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;1446&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;font-family: 'Nanum Gothic';&quot;&gt;하지만 로그가 쌓이다보면, 최신 로그들만 보고 싶을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럴 때는 `--tail` 옵션으로 개수 제한을 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753926067720&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs --tail [개수] [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.41.43.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZI5pJ/btsPDalvwoG/elkvsmDZPqqD57r8JzgITK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZI5pJ/btsPDalvwoG/elkvsmDZPqqD57r8JzgITK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZI5pJ/btsPDalvwoG/elkvsmDZPqqD57r8JzgITK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZI5pJ%2FbtsPDalvwoG%2FelkvsmDZPqqD57r8JzgITK%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;2436&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.41.43.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`--tail 10`은 마지막 10개의 로그만 보겠다는 의미이다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 이번엔 기존에 foreground에서 실행했던 것 처럼&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실시간으로 로그를 보고 싶을 경우가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럴 때는 다음 명령어를 입력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753927644109&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs -f [CONTAINER ID]&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, 실시간으로 계속 쌓였던 로그를 전부 보는것이 아니라&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금부터 생성되는 로그를 보고 싶을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럴 때는 다음과 같이 위의 두 명령어를 조합해서 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753927761924&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs --tail 0 -f [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/764</guid>
      <comments>https://jun-coding.tistory.com/764#entry764comment</comments>
      <pubDate>Thu, 31 Jul 2025 11:10:06 +0900</pubDate>
    </item>
    <item>
      <title>컨테이너 관련 명령어 알아보기</title>
      <link>https://jun-coding.tistory.com/763</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개요&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이번 포스팅에서는 그동안 알아보지 않고 무작정 썼던 명령어들을 조금 자세히 알아보려 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너와 이미지 생성, 삭제 등 이미 모두 해보았지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명령어의 각 옵션이 무엇을 의미하는지 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 조회하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 조회하기 위해서 기본적으로 다음 명령어를 사용했었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753921832369&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.31.24.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dthlpQ/btsPEqAT73a/sgxdsIDrXZwOZO7TtbtRCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dthlpQ/btsPEqAT73a/sgxdsIDrXZwOZO7TtbtRCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dthlpQ/btsPEqAT73a/sgxdsIDrXZwOZO7TtbtRCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdthlpQ%2FbtsPEqAT73a%2FsgxdsIDrXZwOZO7TtbtRCk%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;2436&quot; height=&quot;426&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.31.24.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 중요하게 알아야 할 것이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 명령어는 모든 컨테이너를 조회하는 것이 아니라,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;'실행중인 컨테이너'&lt;/span&gt;를 조회하는 명령어&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래 명령어는 위 명령어와 뭐가 다를까?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753922002731&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.33.49.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CKFlB/btsPDltyrnF/V76z0dAwMVyUyMWc4Ci9k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CKFlB/btsPDltyrnF/V76z0dAwMVyUyMWc4Ci9k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CKFlB/btsPDltyrnF/V76z0dAwMVyUyMWc4Ci9k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCKFlB%2FbtsPDltyrnF%2FV76z0dAwMVyUyMWc4Ci9k1%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;2436&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.33.49.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 &lt;b&gt;`-a` 옵션을 붙였는데, 'all'의 약자&lt;/b&gt;라고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실행중인 컨테이너, 중지된 컨테이너 &lt;span style=&quot;color: #8a3db6;&quot;&gt;'모두'&lt;/span&gt; 포함해서 조회하는 명령어&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;STATUS를 보면 'Exited'라고 되어있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중단된 컨테이너를 의미한다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 실행하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 중단된 컨테이너를 실행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753922309379&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d nginx&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 `&lt;b&gt;-d`는 'detached'의 약자&lt;/b&gt;라고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'detached'는 '분리된' 이라는 의미를 가지고 있으며,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;foreground가 아닌, background에서 실행해준다.&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;스크린샷 2025-07-31 오전 9.41.12.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEdGud/btsPEKMF5Ir/ku05g6WcAGS5DFxGot9uE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEdGud/btsPEKMF5Ir/ku05g6WcAGS5DFxGot9uE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEdGud/btsPEKMF5Ir/ku05g6WcAGS5DFxGot9uE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEdGud%2FbtsPEKMF5Ir%2Fku05g6WcAGS5DFxGot9uE0%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;2436&quot; height=&quot;494&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.41.12.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행중인 컨테이너를 조회하는 명령어로 확인해보면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중단된 상태였던 컨테이너가 잘 보이는 것을 확인할 수 있다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 중지하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 &lt;b&gt;중지&lt;/b&gt;하기 위해서는 다음 명령어를 사용했었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753922669354&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker stop [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.44.54.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKCqGE/btsPDGRJ43S/2xaXigmrVcHQnKnQ7TgAk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKCqGE/btsPDGRJ43S/2xaXigmrVcHQnKnQ7TgAk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKCqGE/btsPDGRJ43S/2xaXigmrVcHQnKnQ7TgAk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKCqGE%2FbtsPDGRJ43S%2F2xaXigmrVcHQnKnQ7TgAk1%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;2436&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.44.54.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 때, CONTAINER ID는 다른 컨테이너와 구분이 가는 정도에서 일부만 입력해도 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론, NAMES를 지정해줬을 경우에는 컨테이너 이름을 입력해줘도 된다.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, 만약 컨테이너가 멈추지 않거나, 응답이 없다면 어떻게할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리가 컴퓨터를 전원 버튼을 꾹 눌러서 강제종료 하듯이,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너도 다음 명령어로 &lt;b&gt;강제종료&lt;/b&gt; 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753922926791&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker kill [CONTAINER ID]&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 위 방법은 데이터가 손실되거나 비정상으로 종료될 위험이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러므로, 최후의 수단으로 사용해야 한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;일반적으로는 `docker stop`으로 안전하게 종료하고,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컨테이너가 멈추지 않거나, 응답이 완전히 없을 때만 `docker kill`을 사용하는게 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 삭제하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 삭제할 땐 다음 명령어를 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753923140073&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.53.13.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFN9jg/btsPEtEp7My/3WcSTmdElEaX2K7nKngEJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFN9jg/btsPEtEp7My/3WcSTmdElEaX2K7nKngEJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFN9jg/btsPEtEp7My/3WcSTmdElEaX2K7nKngEJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFN9jg%2FbtsPEtEp7My%2F3WcSTmdElEaX2K7nKngEJ0%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;2436&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.53.13.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 중간에 공백을 두어서 여러 컨테이너를 한 번에 지울 수도 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;하지만, 컨테이너는 실행 중에 지울 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테스트를 위해 컨테이너를 실행해서 다시 지워보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b15Qq9/btsPDlNSV1t/CEVZU634JKkZJzwh8iC1kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b15Qq9/btsPDlNSV1t/CEVZU634JKkZJzwh8iC1kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b15Qq9/btsPDlNSV1t/CEVZU634JKkZJzwh8iC1kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb15Qq9%2FbtsPDlNSV1t%2FCEVZU634JKkZJzwh8iC1kk%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;2436&quot; height=&quot;732&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 에러가 발생하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;에러메시지를 보면 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;컨테이너를 지우기 전에 컨테이너를 중지&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 중지하고 삭제해보자.&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;스크린샷 2025-07-31 오전 9.58.12.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsWGgU/btsPEK0b4TA/jJXLy20JyphxNsnBZgZixK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsWGgU/btsPEK0b4TA/jJXLy20JyphxNsnBZgZixK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsWGgU/btsPEK0b4TA/jJXLy20JyphxNsnBZgZixK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsWGgU%2FbtsPEK0b4TA%2FjJXLy20JyphxNsnBZgZixK%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;2436&quot; height=&quot;630&quot; data-filename=&quot;스크린샷 2025-07-31 오전 9.58.12.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위와 같이 잘 삭제가 된 것을 볼 수 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;만약 여러개의 컨테이너를 한 번에 지우고 싶다면 어떻게 할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같이 여러 컨테이너가 있다고 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.01.04.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rnfnt/btsPC6QWKHB/dTFtpCMFdeD8Txstubfksk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rnfnt/btsPC6QWKHB/dTFtpCMFdeD8Txstubfksk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rnfnt/btsPC6QWKHB/dTFtpCMFdeD8Txstubfksk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frnfnt%2FbtsPC6QWKHB%2FdTFtpCMFdeD8Txstubfksk%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;2436&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.01.04.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 중간에 공백을 두고 CONTAINER ID를 모두 입력할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, 컨테이너가 많아질수록 힘들어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럴땐 다음 명령어로 한 번에 지울 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753923743094&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm $(docker ps -qa)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.04.35.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNTD3/btsPClA5MKO/AeNTfhFN2NGq2mlQgli3c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNTD3/btsPClA5MKO/AeNTfhFN2NGq2mlQgli3c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNTD3/btsPClA5MKO/AeNTfhFN2NGq2mlQgli3c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNTD3%2FbtsPClA5MKO%2FAeNTfhFN2NGq2mlQgli3c0%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;2436&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.04.35.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 `docker ps -qa`는 현재 호스트에 저장된 모든 컨테이너의 ID를 호출한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-q` 옵션은 'quiet'로, ID만 추출하고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;`-a` 옵션은 'all'로, 실행 중이든 중지 상태든 모든 컨테이너를 포함한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로, 실행 중이던 컨테이너를 바로 삭제하는 법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753923982945&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm -f [CONTAINER ID]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.06.08.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccDU7G/btsPDV8Y3zI/4Qp147bqQXLTc54f1zFd3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccDU7G/btsPDV8Y3zI/4Qp147bqQXLTc54f1zFd3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccDU7G/btsPDV8Y3zI/4Qp147bqQXLTc54f1zFd3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccDU7G%2FbtsPDV8Y3zI%2F4Qp147bqQXLTc54f1zFd3K%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;2436&quot; height=&quot;766&quot; data-filename=&quot;스크린샷 2025-07-31 오전 10.06.08.png&quot; data-origin-width=&quot;2436&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 &lt;b&gt;`-f`는 'force'의 약자&lt;/b&gt;로, '강제로' 한다는 의미이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/763</guid>
      <comments>https://jun-coding.tistory.com/763#entry763comment</comments>
      <pubDate>Thu, 31 Jul 2025 10:07:23 +0900</pubDate>
    </item>
    <item>
      <title>컨테이너 생성 / 실행하기</title>
      <link>https://jun-coding.tistory.com/762</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 생성하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너는 이미지를 바탕으로 생성하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 이미지를 이용해서 컨테이너를 생성할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753913380365&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker create &amp;lt;이미지명&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.09.25.png&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wLoL6/btsPC37HyE8/bIU9LVgzXBk77JkKdDeRE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wLoL6/btsPC37HyE8/bIU9LVgzXBk77JkKdDeRE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wLoL6/btsPC37HyE8/bIU9LVgzXBk77JkKdDeRE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwLoL6%2FbtsPC37HyE8%2FbIU9LVgzXBk77JkKdDeRE0%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;1738&quot; height=&quot;712&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.09.25.png&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 nginx 이미지를 삭제했었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;알아서 최신 버전으로 pull해서 설치까지 해준다.&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;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 만들었으니 확인해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 로컬 시스템에 있는 모든 Docker 컨테이너 목록을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753913515503&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.10.33.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTo62N/btsPEM4LPxe/2LuYdxrSGWo8B0ev6FdvU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTo62N/btsPEM4LPxe/2LuYdxrSGWo8B0ev6FdvU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTo62N/btsPEM4LPxe/2LuYdxrSGWo8B0ev6FdvU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTo62N%2FbtsPEM4LPxe%2F2LuYdxrSGWo8B0ev6FdvU1%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;2002&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.10.33.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기에 STATUS 부분에 'Created' 라는 상태가 보일 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;'Created'&lt;/span&gt;는 생성은 했지만, 실행중인 컨테이너가 아닌 상태이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 실행하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 nginx 컨테이너를 실행해주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753913637223&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker start &amp;lt;CONTAINER ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.14.47.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wJYgh/btsPClOxKH1/DyUsEm6ZOX6wRFH5jDkVmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wJYgh/btsPClOxKH1/DyUsEm6ZOX6wRFH5jDkVmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wJYgh/btsPClOxKH1/DyUsEm6ZOX6wRFH5jDkVmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwJYgh%2FbtsPClOxKH1%2FDyUsEm6ZOX6wRFH5jDkVmk%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;2002&quot; height=&quot;698&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.14.47.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행해준 뒤, 다시 리스트를 보면 STATUS가 'Up'으로 된 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;'Up'&lt;/span&gt;은 실행중인 컨테이너라는 의미이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;생성과 동시에 실행하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금은 create로 컨테이너를 만들고, start로 컨테이너를 실행시켜주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, run이라는 명령어로 한 번에 컨테이너를 만들고, 바로 실행시킬 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 run 명령어는 이전 포스팅에서 잠깐 보였던 적이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.30 - [Docker] - Docker를 활용해서 Nginx 설치 및 실행하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753914144568&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;Docker를 활용해서 Nginx 설치 및 실행하기&quot; data-og-description=&quot;Nginx란?Nginx는 웹 서버, 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 역할을 하는 서버 중 하나이다.여기서 웹 서버는 HTML 웹 페이지를 렌더링 시키는 역할을 한다.나머지는 차차 알아보자. Ngi&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/759&quot; data-og-url=&quot;https://jun-coding.tistory.com/759&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eAuFoA/hyZrpMpUfU/JeCgYzRxPPsScEpDPJ5yfK/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/T2Ejv/hyZq3QsnpQ/IYxriphkn4EY5M1ewZz12k/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/bH13w2/hyZqXpbVr7/2TbpO7JfQYLQZu9M3DBRmK/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/759&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eAuFoA/hyZrpMpUfU/JeCgYzRxPPsScEpDPJ5yfK/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/T2Ejv/hyZq3QsnpQ/IYxriphkn4EY5M1ewZz12k/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/bH13w2/hyZqXpbVr7/2TbpO7JfQYLQZu9M3DBRmK/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112');&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;Docker를 활용해서 Nginx 설치 및 실행하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nginx란?Nginx는 웹 서버, 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 역할을 하는 서버 중 하나이다.여기서 웹 서버는 HTML 웹 페이지를 렌더링 시키는 역할을 한다.나머지는 차차 알아보자. Ngi&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단, 설치되어 있는 이미지와 컨테이너를 모두 지워주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지우는 명령어는 지난 포스팅에 언급해두었다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/761&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.31 - [Docker] - 도커 이미지 조회 / 삭제하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753914346074&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;도커 이미지 조회 / 삭제하기&quot; data-og-description=&quot;2025.07.30 - [Docker] - 도커 이미지 다운로드 하기 도커 이미지 다운로드 하기컨테이너를 실행하려면 도커 이미지가 필요하다.이미지를 다운받기 위해서는 다음과 같은 명령어를 입력하면 된다.docke&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/761&quot; data-og-url=&quot;https://jun-coding.tistory.com/761&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bunz0U/hyZqRighkm/02xSwIFY10cKLXfekuulKK/img.png?width=800&amp;amp;height=201&amp;amp;face=0_0_800_201,https://scrap.kakaocdn.net/dn/ljduw/hyZq0lXPEA/AK3GUEZ6ryzjegVGkdVTN1/img.png?width=800&amp;amp;height=201&amp;amp;face=0_0_800_201,https://scrap.kakaocdn.net/dn/MXlM1/hyZq3psxej/xkkW5BYj8aOTqFtMBbPdsk/img.png?width=1826&amp;amp;height=902&amp;amp;face=0_0_1826_902&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/761&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/761&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bunz0U/hyZqRighkm/02xSwIFY10cKLXfekuulKK/img.png?width=800&amp;amp;height=201&amp;amp;face=0_0_800_201,https://scrap.kakaocdn.net/dn/ljduw/hyZq0lXPEA/AK3GUEZ6ryzjegVGkdVTN1/img.png?width=800&amp;amp;height=201&amp;amp;face=0_0_800_201,https://scrap.kakaocdn.net/dn/MXlM1/hyZq3psxej/xkkW5BYj8aOTqFtMBbPdsk/img.png?width=1826&amp;amp;height=902&amp;amp;face=0_0_1826_902');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;도커 이미지 조회 / 삭제하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2025.07.30 - [Docker] - 도커 이미지 다운로드 하기 도커 이미지 다운로드 하기컨테이너를 실행하려면 도커 이미지가 필요하다.이미지를 다운받기 위해서는 다음과 같은 명령어를 입력하면 된다.docke&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 다음 명령어로 nginx 이미지를 설치하고, 실행해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753914374809&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.27.11.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRyrak/btsPB56avHn/17SYhbsNlT4rzX7BkK0gX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRyrak/btsPB56avHn/17SYhbsNlT4rzX7BkK0gX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRyrak/btsPB56avHn/17SYhbsNlT4rzX7BkK0gX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRyrak%2FbtsPB56avHn%2F17SYhbsNlT4rzX7BkK0gX0%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;2002&quot; height=&quot;732&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.27.11.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지가 없으니, 자동으로 이미지를 다운로드 하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실행까지 시켜주는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, foreground에서 실행되기 때문에 로그들이 터미널에 보이게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;터미널에서는 실시간 로그들이 보이기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 종료하고 싶으면 윈도우는 Ctrl + C,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Mac은 Command + C를 누르면 된다.&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;font-family: 'Nanum Gothic';&quot;&gt;background에서 실행시키고 싶으면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전에 언급한 `-d` 플래그로 실행시켜주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753914547669&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.30.46.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I71Vb/btsPDI20PhH/G4YE8SkCUZm2kZp2HzJb11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I71Vb/btsPDI20PhH/G4YE8SkCUZm2kZp2HzJb11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I71Vb/btsPDI20PhH/G4YE8SkCUZm2kZp2HzJb11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI71Vb%2FbtsPDI20PhH%2FG4YE8SkCUZm2kZp2HzJb11%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;2002&quot; height=&quot;596&quot; data-filename=&quot;스크린샷 2025-07-31 오전 7.30.46.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 목록까지 확인해보면 잘 실행되고 있는 것을 볼 수 있다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너에 이름 붙이기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;nginx 컨테이너에 이름을 붙이고 싶으면 다음과 같이 입력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753917254415&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name my-web-server nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.15.13.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmm6LD/btsPB1bHv3z/SV0i98PWAKkylSmq1NqcU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmm6LD/btsPB1bHv3z/SV0i98PWAKkylSmq1NqcU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmm6LD/btsPB1bHv3z/SV0i98PWAKkylSmq1NqcU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmm6LD%2FbtsPB1bHv3z%2FSV0i98PWAKkylSmq1NqcU0%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;2002&quot; height=&quot;936&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.15.13.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;확인해보면, NAMES에 'my-web-server'로 잘 지정된것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포트 연결하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 보면 PORTS 부분에 '80/tcp'라고 적힌것을 볼 수 있다.&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;스크린샷 2025-07-31 오전 8.18.53.png&quot; data-origin-width=&quot;2074&quot; data-origin-height=&quot;372&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAG8ZC/btsPBLUo3Kf/YVI4qfxkOuxq8G898j4Fv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAG8ZC/btsPBLUo3Kf/YVI4qfxkOuxq8G898j4Fv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAG8ZC/btsPBLUo3Kf/YVI4qfxkOuxq8G898j4Fv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAG8ZC%2FbtsPBLUo3Kf%2FYVI4qfxkOuxq8G898j4Fv1%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;2074&quot; height=&quot;372&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.18.53.png&quot; data-origin-width=&quot;2074&quot; data-origin-height=&quot;372&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 브라우저에서 80번 포트로 접속할 수 있을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;웹 HTTP의 기본 포트가 80번이니 브라우저에서 localhost로 접속해보자.&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;스크린샷 2025-07-31 오전 8.20.33.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FG55t/btsPE45cBSY/qkiS8KVAOOQHhVMMKWEQe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FG55t/btsPE45cBSY/qkiS8KVAOOQHhVMMKWEQe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FG55t/btsPE45cBSY/qkiS8KVAOOQHhVMMKWEQe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFG55t%2FbtsPE45cBSY%2FqkiS8KVAOOQHhVMMKWEQe0%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;3248&quot; height=&quot;2112&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.20.33.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위와 같이 nginx 페이지가 잘 보이는 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;하지만, 이것은 &lt;span style=&quot;color: #8a3db6;&quot;&gt;캐싱된 페이지&lt;/span&gt;일 수 있으니 '시크릿 모드'로 접속해보자.&lt;/b&gt;&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;스크린샷 2025-07-31 오전 8.21.47.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2LbY7/btsPDcDwiMb/IZRBr5onJZiKu3N8x3yOTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2LbY7/btsPDcDwiMb/IZRBr5onJZiKu3N8x3yOTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2LbY7/btsPDcDwiMb/IZRBr5onJZiKu3N8x3yOTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2LbY7%2FbtsPDcDwiMb%2FIZRBr5onJZiKu3N8x3yOTk%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;3248&quot; height=&quot;2112&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.21.47.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이처럼, 접속할 수 없는 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;무슨 이유일까?&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컨테이너는 &lt;span style=&quot;color: #8a3db6;&quot;&gt;'독립된 공간'&lt;/span&gt; 이라고 했다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 말은, 호스트 컴퓨터와 컨테이너는 서로 다른 네트워크를 사용한다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 우리의 컴퓨터에서는 '호스트 컴퓨터'에만 접근이 가능하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'컨테이너'로 접근할 수는 없는것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;따라서 이 '독립된 컨테이너'에 접근하려면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포트를 연결해주어야 한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;기존의 컨테이너는 지우고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 새로 만들어주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753918038355&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker run -d -p [호스트 포트]:[컨테이너 포트] 이미지명[:태그명]
docker run -d -p 4000:80 nginx&lt;/code&gt;&lt;/pre&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;2378&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2c7KU/btsPDUIY0df/HbS4bkKDWoK7vcvTspxLu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2c7KU/btsPDUIY0df/HbS4bkKDWoK7vcvTspxLu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2c7KU/btsPDUIY0df/HbS4bkKDWoK7vcvTspxLu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2c7KU%2FbtsPDUIY0df%2FHbS4bkKDWoK7vcvTspxLu0%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;2378&quot; height=&quot;474&quot; data-origin-width=&quot;2378&quot; data-origin-height=&quot;474&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 생성한 뒤, PORTS를 보면 아까와는 다르게 표시되고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4000번 포트로 '호스트 컴퓨터'에 접근하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;호스트 컴퓨터가 80번 포트로 '컨테이너'에 접근할 수 있게되는것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vk8Ga/btsPCK8rIcU/tBhvRU6ug7mp4HUNAtRluK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vk8Ga/btsPCK8rIcU/tBhvRU6ug7mp4HUNAtRluK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vk8Ga/btsPCK8rIcU/tBhvRU6ug7mp4HUNAtRluK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvk8Ga%2FbtsPCK8rIcU%2FtBhvRU6ug7mp4HUNAtRluK%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;1280&quot; height=&quot;686&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;686&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 브라우저에서 `localhost:4000`으로 접속해보자.&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;스크린샷 2025-07-31 오전 8.29.59.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tVOMl/btsPDHQAFZv/YDYkw6Z6T09LRoQiekFMt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tVOMl/btsPDHQAFZv/YDYkw6Z6T09LRoQiekFMt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tVOMl/btsPDHQAFZv/YDYkw6Z6T09LRoQiekFMt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtVOMl%2FbtsPDHQAFZv%2FYDYkw6Z6T09LRoQiekFMt0%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;3248&quot; height=&quot;2112&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.29.59.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이와 같이, 4000번 포트로 접속하면 nginx 페이지가 잘 뜨는 것을 볼 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;브라우저(HTTP)의 기본 포트가 80이라고 했으니,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;80:80으로 설정하면 그냥 localhost로 접속해도 되지 않을까?&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;font-family: 'Nanum Gothic';&quot;&gt;기존 컨테이너를 지운 뒤, 다음과 같이 입력해보자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753918382809&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# docker run -d -p [호스트 포트]:[컨테이너 포트] 이미지명[:태그명]
docker run -d -p 80:80 nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.33.15.png&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zu3yd/btsPDPHRtkh/9PIRrOPgY1Q4uMOKmBXil1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zu3yd/btsPDPHRtkh/9PIRrOPgY1Q4uMOKmBXil1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zu3yd/btsPDPHRtkh/9PIRrOPgY1Q4uMOKmBXil1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZu3yd%2FbtsPDPHRtkh%2F9PIRrOPgY1Q4uMOKmBXil1%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;2466&quot; height=&quot;562&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.33.15.png&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;562&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 나서, 브라우저에는 캐싱된 페이지가 남을 수 있기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저 전체를 끄고 다시 시크릿 모드로 들어가주자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 4000번 포트로 다시 들어가보면 연결이 되지 않는 것을 볼 수 있다.&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;스크린샷 2025-07-31 오전 8.34.00.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTXiT6/btsPCqoL4yB/stopVQIE684ne68JJbKsp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTXiT6/btsPCqoL4yB/stopVQIE684ne68JJbKsp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTXiT6/btsPCqoL4yB/stopVQIE684ne68JJbKsp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTXiT6%2FbtsPCqoL4yB%2FstopVQIE684ne68JJbKsp0%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;3248&quot; height=&quot;2112&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.34.00.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 이제 80번 포트, 즉 그냥 localhost로 접속해보면 다음과 같이 정상적으로 보인다.&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;스크린샷 2025-07-31 오전 8.34.35.png&quot; data-origin-width=&quot;3160&quot; data-origin-height=&quot;2024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXWVYi/btsPES4XUDc/yCuyifkyfTTMlTfuTaUgQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXWVYi/btsPES4XUDc/yCuyifkyfTTMlTfuTaUgQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXWVYi/btsPES4XUDc/yCuyifkyfTTMlTfuTaUgQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXWVYi%2FbtsPES4XUDc%2FyCuyifkyfTTMlTfuTaUgQ0%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;3160&quot; height=&quot;2024&quot; data-filename=&quot;스크린샷 2025-07-31 오전 8.34.35.png&quot; data-origin-width=&quot;3160&quot; data-origin-height=&quot;2024&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;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/762</guid>
      <comments>https://jun-coding.tistory.com/762#entry762comment</comments>
      <pubDate>Thu, 31 Jul 2025 07:17:26 +0900</pubDate>
    </item>
    <item>
      <title>도커 이미지 조회 / 삭제하기</title>
      <link>https://jun-coding.tistory.com/761</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/760&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.30 - [Docker] - 도커 이미지 다운로드 하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753902858119&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;도커 이미지 다운로드 하기&quot; data-og-description=&quot;컨테이너를 실행하려면 도커 이미지가 필요하다.이미지를 다운받기 위해서는 다음과 같은 명령어를 입력하면 된다.docker pull 그리고 다운받은 이미지 리스트를 보고 싶으면 다음과 같은 명령어&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/760&quot; data-og-url=&quot;https://jun-coding.tistory.com/760&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0EgK5/hyZqWRnUQS/dVILuoRJswxY7VE2a5O7yK/img.png?width=800&amp;amp;height=516&amp;amp;face=0_0_800_516,https://scrap.kakaocdn.net/dn/d1AaPh/hyZrzuLdHC/xCHxZ4kA24HskntngikeA0/img.png?width=800&amp;amp;height=516&amp;amp;face=0_0_800_516,https://scrap.kakaocdn.net/dn/bUd9vg/hyZrpZYHtS/UDsikvElD9DqYr10vzVn9k/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/760&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/760&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0EgK5/hyZqWRnUQS/dVILuoRJswxY7VE2a5O7yK/img.png?width=800&amp;amp;height=516&amp;amp;face=0_0_800_516,https://scrap.kakaocdn.net/dn/d1AaPh/hyZrzuLdHC/xCHxZ4kA24HskntngikeA0/img.png?width=800&amp;amp;height=516&amp;amp;face=0_0_800_516,https://scrap.kakaocdn.net/dn/bUd9vg/hyZrpZYHtS/UDsikvElD9DqYr10vzVn9k/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;도커 이미지 다운로드 하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너를 실행하려면 도커 이미지가 필요하다.이미지를 다운받기 위해서는 다음과 같은 명령어를 입력하면 된다.docker pull 그리고 다운받은 이미지 리스트를 보고 싶으면 다음과 같은 명령어&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 이미지를 다운로드 하고, 조회를 하는 기능을 알아봤다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지를 조회했을 때 어떤 정보들이 나오는지 아주 조금 더 자세히 알아보자.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 조회하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래 명령어로 다운로드 받은 이미지를 조회할 수 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753902939976&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.15.58.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WbbnJ/btsPEs6xRw5/KLxy4CnwAecakqEJQXWa0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WbbnJ/btsPEs6xRw5/KLxy4CnwAecakqEJQXWa0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WbbnJ/btsPEs6xRw5/KLxy4CnwAecakqEJQXWa0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWbbnJ%2FbtsPEs6xRw5%2FKLxy4CnwAecakqEJQXWa0K%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;1826&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.15.58.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;REPOSITORY&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 저장소 명을 나타낸다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;TAG&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지의 버전을 나타낸다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IMAGE ID&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 이미지에 부여된 고유한 ID를 나타낸다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;CREATED&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지를 다운로드 한 날짜가 아닌 이미지가 생성된 날짜이다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.0697%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SIZE&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 85.9303%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지의 용량을 나타낸다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 삭제하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 있던 nginx 이미지를 삭제해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IMAGE ID를 rm 명령어와 함께 입력하여 삭제할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ID의 일부만 입력해줘도, 입력한 ID로 시작하는 이미지가 삭제된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753903192890&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image rm &amp;lt;IMAGE ID&amp;gt;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, 다음과 같은 에러가 뜨면서 삭제되지 않았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전에 nginx 이미지가 실행중인 컨테이너를 stop 시켜놨었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;stop 중인 컨테이너에 있는 이미지이기 때문에 삭제할 수 없다는 에러가 뜬다.&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;스크린샷 2025-07-31 오전 4.22.42.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJOSJx/btsPDtkG8Zr/iW6EdbV1qfi4r3jHUTKiV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJOSJx/btsPDtkG8Zr/iW6EdbV1qfi4r3jHUTKiV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJOSJx/btsPDtkG8Zr/iW6EdbV1qfi4r3jHUTKiV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJOSJx%2FbtsPDtkG8Zr%2FiW6EdbV1qfi4r3jHUTKiV1%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;1826&quot; height=&quot;596&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.22.42.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왜 컨테이너가 stop 상태임에도 삭제할 수 없을까?&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;font-family: 'Nanum Gothic';&quot;&gt;도커 이미지는 '&lt;b&gt;컨테이너를 만들기 위한 설계도나 템플릿 같은 존재&lt;/b&gt;'라고 했었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너의 실행/정지 상태와 상관없이 컨테이너가 존재한다면 그 이미지를 참조중이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 이미지가 사라지면 컨테이너 파일시스템이나 구조에 문제가 생기게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그래서 먼저 컨테이너를 삭제한 후, 이미지를 지워야 한다.&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;font-family: 'Nanum Gothic';&quot;&gt;위 터미널 캡쳐본 마지막에 컨테이너 id가 보일 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같은 명령어로 컨테이너를 먼저 지워주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753903782461&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm &amp;lt;CONTAINTER ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.29.19.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV0AuQ/btsPEDGUjb2/6MGvaeBOK2FPyt3KzK3xtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV0AuQ/btsPEDGUjb2/6MGvaeBOK2FPyt3KzK3xtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV0AuQ/btsPEDGUjb2/6MGvaeBOK2FPyt3KzK3xtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV0AuQ%2FbtsPEDGUjb2%2F6MGvaeBOK2FPyt3KzK3xtK%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;1826&quot; height=&quot;630&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.29.19.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;630&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 나서 다시 이미지를 삭제하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지 목록을 다시 보면 잘 삭제가 된 것을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.31.18.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qg1p0/btsPCjQFxPf/VRptMH2nkogsb5vHIYWGJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qg1p0/btsPCjQFxPf/VRptMH2nkogsb5vHIYWGJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qg1p0/btsPCjQFxPf/VRptMH2nkogsb5vHIYWGJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqg1p0%2FbtsPCjQFxPf%2FVRptMH2nkogsb5vHIYWGJk%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;1826&quot; height=&quot;902&quot; data-filename=&quot;스크린샷 2025-07-31 오전 4.31.18.png&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 중단된 컨테이너가 사용하는 이미지를 이런 과정 없이 삭제하고 싶다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 명령어로 강제로 삭제해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 중요한 것은 이 명령어는 &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;'중단된 컨테이너'&lt;/span&gt;가 사용하는 이미지&lt;/b&gt;만 삭제 가능하다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753904041223&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image rm -f &amp;lt;IMAGE ID&amp;gt;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 컨테이너가 사용하고 있지 않은 이미지들을 모두 삭제하고 싶다면 다음 명령어를 입력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753904142716&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image rm -f $(docker images -q)&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 `docker images -q`는 로컬에 있는 모든 이미지의 ID를 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 $()로 감싸주게 되면, 이것들을 앞에 있는 명령어의 인자로 넘겨주게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 모든 도커 이미지의 ID를 불러와서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 ID에 삭제 명령어를 내린다고 생각하면 된다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/761</guid>
      <comments>https://jun-coding.tistory.com/761#entry761comment</comments>
      <pubDate>Thu, 31 Jul 2025 04:39:49 +0900</pubDate>
    </item>
    <item>
      <title>도커 이미지 다운로드 하기</title>
      <link>https://jun-coding.tistory.com/760</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너를 실행하려면 도커 이미지가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지를 다운받기 위해서는 다음과 같은 명령어를 입력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753883492601&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull &amp;lt;이미지명&amp;gt;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 다운받은 이미지 리스트를 보고 싶으면 다음과 같은 명령어를 입력했다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753883553563&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image ls&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서 nginx를 다운받고 설치까지 해서 실행을 해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.30 - [Docker] - Docker를 활용해서 Nginx 설치 및 실행하기&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753883620070&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;Docker를 활용해서 Nginx 설치 및 실행하기&quot; data-og-description=&quot;Nginx란?Nginx는 웹 서버, 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 역할을 하는 서버 중 하나이다.여기서 웹 서버는 HTML 웹 페이지를 렌더링 시키는 역할을 한다.나머지는 차차 알아보자. Ngi&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/759&quot; data-og-url=&quot;https://jun-coding.tistory.com/759&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eAuFoA/hyZrpMpUfU/JeCgYzRxPPsScEpDPJ5yfK/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/T2Ejv/hyZq3QsnpQ/IYxriphkn4EY5M1ewZz12k/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/bH13w2/hyZqXpbVr7/2TbpO7JfQYLQZu9M3DBRmK/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/759&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/759&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eAuFoA/hyZrpMpUfU/JeCgYzRxPPsScEpDPJ5yfK/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/T2Ejv/hyZq3QsnpQ/IYxriphkn4EY5M1ewZz12k/img.png?width=800&amp;amp;height=586&amp;amp;face=0_0_800_586,https://scrap.kakaocdn.net/dn/bH13w2/hyZqXpbVr7/2TbpO7JfQYLQZu9M3DBRmK/img.png?width=3248&amp;amp;height=2112&amp;amp;face=0_0_3248_2112');&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;Docker를 활용해서 Nginx 설치 및 실행하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Nginx란?Nginx는 웹 서버, 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 역할을 하는 서버 중 하나이다.여기서 웹 서버는 HTML 웹 페이지를 렌더링 시키는 역할을 한다.나머지는 차차 알아보자. Ngi&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 다른 이미지를 다운 받고 싶다면 어디서 찾아야 할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker Hub&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://hub.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hub.docker.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753884418223&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;Docker Hub Container Image Library | App Containerization&quot; data-og-description=&quot;Software supply chain Secure Your Supply Chain with Docker Hardened Images Use Docker's enterprise-grade base images: secure, stable, and backed by SLAs for Ubuntu, Debian, Java, and more. Regularly scanned and maintained with CVE remediation and long-term&quot; data-og-host=&quot;hub.docker.com&quot; data-og-source-url=&quot;https://hub.docker.com/&quot; data-og-url=&quot;https://hub.docker.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnXFQb/hyZq0TJZ55/P2fGRuiSRKwQXsCBzeGWP0/img.png?width=3372&amp;amp;height=1896&amp;amp;face=0_0_3372_1896&quot;&gt;&lt;a href=&quot;https://hub.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hub.docker.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnXFQb/hyZq0TJZ55/P2fGRuiSRKwQXsCBzeGWP0/img.png?width=3372&amp;amp;height=1896&amp;amp;face=0_0_3372_1896');&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;Docker Hub Container Image Library | App Containerization&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Software supply chain Secure Your Supply Chain with Docker Hardened Images Use Docker's enterprise-grade base images: secure, stable, and backed by SLAs for Ubuntu, Debian, Java, and more. Regularly scanned and maintained with CVE remediation and long-term&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hub.docker.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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker Hub라는 사이트에서 사람들이 올린 이미지들을 확인하고 다운로드 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Docker Hub는 &quot;이미지를 저장, 다운받을 수 있는 역할을 하는 저장소 서비스이다.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;github에서 프로젝트를 pull로 당겨오는 것 처럼,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;dockerhub에서도 이미지를 pull로 가져올 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;이미 설치했지만, nginx를 찾아서 설치해본다고 가정해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 다음과 같이 dockerhub에서 nginx를 검색한다.&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;스크린샷 2025-07-30 오후 11.10.39.png&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byHnAL/btsPDpo8WKg/v0Kuo5JAmZ216qBeyemI8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byHnAL/btsPDpo8WKg/v0Kuo5JAmZ216qBeyemI8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byHnAL/btsPDpo8WKg/v0Kuo5JAmZ216qBeyemI8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyHnAL%2FbtsPDpo8WKg%2Fv0Kuo5JAmZ216qBeyemI8k%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;3208&quot; height=&quot;2072&quot; data-filename=&quot;스크린샷 2025-07-30 오후 11.10.39.png&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 다음과 같이 결과가 나오는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 첫 번째꺼를 클릭해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y11pZ/btsPClnqCsp/G8w00MkKIsEsQlsFie9v90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y11pZ/btsPClnqCsp/G8w00MkKIsEsQlsFie9v90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y11pZ/btsPClnqCsp/G8w00MkKIsEsQlsFie9v90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy11pZ%2FbtsPClnqCsp%2FG8w00MkKIsEsQlsFie9v90%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;3208&quot; height=&quot;2072&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;들어가보면, Overview에서는 전체적인 이미지에 대한 설명을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 Tags에서는 이미지의 버전을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kFJqw/btsPCJ9vbH1/2x5FiEe1uHxABv0p7HWlXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kFJqw/btsPCJ9vbH1/2x5FiEe1uHxABv0p7HWlXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kFJqw/btsPCJ9vbH1/2x5FiEe1uHxABv0p7HWlXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkFJqw%2FbtsPCJ9vbH1%2F2x5FiEe1uHxABv0p7HWlXk%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;3208&quot; height=&quot;2072&quot; data-origin-width=&quot;3208&quot; data-origin-height=&quot;2072&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;들어가보면, 여러 버전의 이미지들이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 특정 버전의 이미지를 다운 받고 싶다면, 명령어를 복사해서 터미널에 입력해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;' : ' 뒤에 붙는 것이 버전명, 즉 '태그명'이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCXHi/btsPDmF0Yni/c75jceRJf6EQVR8ePLYFkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCXHi/btsPDmF0Yni/c75jceRJf6EQVR8ePLYFkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCXHi/btsPDmF0Yni/c75jceRJf6EQVR8ePLYFkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCXHi%2FbtsPDmF0Yni%2Fc75jceRJf6EQVR8ePLYFkK%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;3248&quot; height=&quot;2112&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 포스팅에서는 뒤에 아무것도 붙이지 않고 `docker pull`만 입력했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 어떤 버전을 다운로드 한 것일까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무것도 붙이지 않을 경우 `:latest`가 붙은 효과를 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 최신 버전을 다운로드 하겠다는 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/760</guid>
      <comments>https://jun-coding.tistory.com/760#entry760comment</comments>
      <pubDate>Wed, 30 Jul 2025 23:32:03 +0900</pubDate>
    </item>
    <item>
      <title>Docker를 활용해서 Nginx 설치 및 실행하기</title>
      <link>https://jun-coding.tistory.com/759</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Nginx란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Nginx는 웹 서버, 리버스 프록시, 로드 밸런서, HTTP 캐시 등 다양한 역할을 하는 서버 중 하나이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여기서 웹 서버는 HTML 웹 페이지를 렌더링 시키는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나머지는 차차 알아보자.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Nginx 설치하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker가 설치되어 있다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;터미널에서 다음과 같은 명령어로 설치해주자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753862799250&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.06.06.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gxv6k/btsPCLzkJK0/dMn28ASrZfzPKMHbZUxkD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gxv6k/btsPCLzkJK0/dMn28ASrZfzPKMHbZUxkD0/img.png&quot; data-alt=&quot;nginx라는 이미지를 docker로 다운받기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gxv6k/btsPCLzkJK0/dMn28ASrZfzPKMHbZUxkD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGxv6k%2FbtsPCLzkJK0%2FdMn28ASrZfzPKMHbZUxkD0%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;1554&quot; height=&quot;1140&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.06.06.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1140&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;nginx라는 이미지를 docker로 다운받기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;잘 설치되었는지 확인해보려면 다음 명령어를 입력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753862927670&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.08.18.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MQPsp/btsPDcwEPMz/2x4UW8Qj4KrolyO022cW7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MQPsp/btsPDcwEPMz/2x4UW8Qj4KrolyO022cW7k/img.png&quot; data-alt=&quot;nginx라는 이미지가 있는 것을 볼 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MQPsp/btsPDcwEPMz/2x4UW8Qj4KrolyO022cW7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMQPsp%2FbtsPDcwEPMz%2F2x4UW8Qj4KrolyO022cW7k%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;1554&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.08.18.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;nginx라는 이미지가 있는 것을 볼 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Nginx 실행하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이미지를 실행하면 자동으로 컨테이너 환경에서 설치되고 실행된다고 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서 nginx 이미지를 설치했으니, 한 번 실행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;터미널에서 다음 명령어로 실행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753863195182&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run --name webserver -d -p 80:80 nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.12.45.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HTJMF/btsPEwOxDl5/XvKbg5KttK03wHPGVJqpkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HTJMF/btsPEwOxDl5/XvKbg5KttK03wHPGVJqpkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HTJMF/btsPEwOxDl5/XvKbg5KttK03wHPGVJqpkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHTJMF%2FbtsPEwOxDl5%2FXvKbg5KttK03wHPGVJqpkK%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;1554&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.12.45.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;460&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;명령어는 사용하면서 점차 익숙해지겠지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간략하게 무슨 의미인지 한 번 알아보자.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, 새로운 컨테이너를 생성해서 실행하라는 명령어이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753863300327&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로, 컨테이너의 이름을 'webserver'로 지정해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753863361329&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--name webserver&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모드를 지정해줄 수 있는데, 'detached' 모드로 실행해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;터미널을 차지하지 않고, 백그라운드에서 실행해 주는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753863847786&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-d&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약, detached 모드로 안해주면 터미널에 로그들이 뜬다.&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;스크린샷 2025-07-30 오후 5.23.44.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zm2My/btsPED7Uy60/NJ1yj6QNs82JTxKy9Tn8V0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zm2My/btsPED7Uy60/NJ1yj6QNs82JTxKy9Tn8V0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zm2My/btsPED7Uy60/NJ1yj6QNs82JTxKy9Tn8V0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzm2My%2FbtsPED7Uy60%2FNJ1yj6QNs82JTxKy9Tn8V0%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;1554&quot; height=&quot;1786&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.23.44.png&quot; data-origin-width=&quot;1554&quot; data-origin-height=&quot;1786&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 다음으로 어디서 실행할지 포트를 지정해주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;왼쪽에 있는 80은 내 컴퓨터(호스트)의 80번 포트이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;오른쪽에 있는 80은 컨테이너 내부의 80번 포트이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉, `http://localhost:80`으로 접속하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너 안의 Nginx 웹 서버(80번 포트)에 접속하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753863913047&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-p 80:80&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로 nginx 이미지를 사용해 컨테이너를 생성해준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753864001173&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nginx&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;&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;font-family: 'Nanum Gothic';&quot;&gt;실행까지 마치고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저에서 `http://localhost:80`으로 접속하면 다음과 같은 화면을 확인할 수 있다.&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;스크린샷 2025-07-30 오후 5.27.25.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5d6iF/btsPC6Dg1so/BCHP7YpTy1gKoymJWbZ9N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5d6iF/btsPC6Dg1so/BCHP7YpTy1gKoymJWbZ9N1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5d6iF/btsPC6Dg1so/BCHP7YpTy1gKoymJWbZ9N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5d6iF%2FbtsPC6Dg1so%2FBCHP7YpTy1gKoymJWbZ9N1%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;3248&quot; height=&quot;2112&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.27.25.png&quot; data-origin-width=&quot;3248&quot; data-origin-height=&quot;2112&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구성은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;호스트 컴퓨터, 즉 지금 내가 사용하고 있는 컴퓨터에서 컨테이너를 실행하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지금은 nginx 이미지를 사용한 컨테이너만 있지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 컨테이너가 있을 수도 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;721&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyXqI/btsPEqOj4E6/iAESvF15AdTKy1SwbH4uw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyXqI/btsPEqOj4E6/iAESvF15AdTKy1SwbH4uw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyXqI/btsPEqOj4E6/iAESvF15AdTKy1SwbH4uw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyXqI%2FbtsPEqOj4E6%2FiAESvF15AdTKy1SwbH4uw1%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;1280&quot; height=&quot;721&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;721&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;font-family: 'Nanum Gothic';&quot;&gt;마지막으로, 이게 내가 실행한 것이 맞는지 확인하고 싶을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러면 다음 명령어로 현재 실행중인 도커 컨테이너의 목록을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753864192529&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.30.38.png&quot; data-origin-width=&quot;2450&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgHGp1/btsPCUwdWTR/LRaaSnmwEtKE040zyPMcHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgHGp1/btsPCUwdWTR/LRaaSnmwEtKE040zyPMcHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgHGp1/btsPCUwdWTR/LRaaSnmwEtKE040zyPMcHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgHGp1%2FbtsPCUwdWTR%2FLRaaSnmwEtKE040zyPMcHk%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;2450&quot; height=&quot;460&quot; data-filename=&quot;스크린샷 2025-07-30 오후 5.30.38.png&quot; data-origin-width=&quot;2450&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IMAGE에 nginx,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;PORTS에 80번에서 80번 포트로 접속,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NAMES에서 지정한 이름까지 확인할 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 실행중인 컨테이너를 정지하고 싶다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리가 설정해준 'webserver' 라는 이름을 활용해서 다음 명령어로 정지시킬 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1753864366249&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker stop webserver&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/759</guid>
      <comments>https://jun-coding.tistory.com/759#entry759comment</comments>
      <pubDate>Wed, 30 Jul 2025 17:34:36 +0900</pubDate>
    </item>
    <item>
      <title>Docker 설치하기 (Mac OS)</title>
      <link>https://jun-coding.tistory.com/758</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 설치파일 다운로드 하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 아래의 docker 공식 사이트에 들어가준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;애플 실리콘(M1~) 유저라면, 'Docker Desktop for Mac with Apple silicon'을 선택하고,&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예전 Intel 칩셋이라면 'Docker Desktop for Mac with Intel chip'을 선택하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753856732859&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;Mac&quot; data-og-description=&quot;Install Docker Desktop for Mac to get started. This guide covers system requirements, where to download, and instructions on how to install and update.&quot; data-og-host=&quot;docs.docker.com&quot; data-og-source-url=&quot;https://docs.docker.com/desktop/setup/install/mac-install/&quot; data-og-url=&quot;https://docs.docker.com/desktop/setup/install/mac-install/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mjI6M/hyZrzOVZSo/giFjTWSeL0jKd1krZExzAk/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260&quot;&gt;&lt;a href=&quot;https://docs.docker.com/desktop/setup/install/mac-install/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.docker.com/desktop/setup/install/mac-install/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mjI6M/hyZrzOVZSo/giFjTWSeL0jKd1krZExzAk/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Mac&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Install Docker Desktop for Mac to get started. This guide covers system requirements, where to download, and instructions on how to install and update.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.27.06.png&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kFYDg/btsPB6qk1FJ/fqBkbjiIjYcuELPIrSJ2sK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kFYDg/btsPB6qk1FJ/fqBkbjiIjYcuELPIrSJ2sK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kFYDg/btsPB6qk1FJ/fqBkbjiIjYcuELPIrSJ2sK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkFYDg%2FbtsPB6qk1FJ%2FfqBkbjiIjYcuELPIrSJ2sK%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;676&quot; height=&quot;250&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.27.06.png&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;250&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설치 파일 다운로드가 완료되면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;drag an drop으로 Applications 폴더로 설치 파일을 옮겨주면 된다.&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;스크린샷 2025-07-30 오후 3.28.33.png&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;904&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckmhze/btsPCJn0Z6O/cQ2NMkxele5OVVbaIbsEd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckmhze/btsPCJn0Z6O/cQ2NMkxele5OVVbaIbsEd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckmhze/btsPCJn0Z6O/cQ2NMkxele5OVVbaIbsEd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckmhze%2FbtsPCJn0Z6O%2FcQ2NMkxele5OVVbaIbsEd1%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;1664&quot; height=&quot;904&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.28.33.png&quot; data-origin-width=&quot;1664&quot; data-origin-height=&quot;904&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 설치 확인하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 설치된 파일을 실행하면, 세팅을 위한 창을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음 사용하는 거니까 'Use recommended settings'를 선택해주자.&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;스크린샷 2025-07-30 오후 3.32.22.png&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1864&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm02hq/btsPCIJoraT/h9Wkrcv4kc8iPpSsVhsVL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm02hq/btsPCIJoraT/h9Wkrcv4kc8iPpSsVhsVL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm02hq/btsPCIJoraT/h9Wkrcv4kc8iPpSsVhsVL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm02hq%2FbtsPCIJoraT%2Fh9Wkrcv4kc8iPpSsVhsVL1%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;1864&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.32.22.png&quot; data-origin-width=&quot;2024&quot; data-origin-height=&quot;1864&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그럼 다음과 같이 이렇게 다음 메뉴바의 맨 왼쪽에 있는 고래 모양 같은 아이콘이 표시된다.&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;스크린샷 2025-07-30 오후 3.34.55.png&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2On2y/btsPDDUWqyg/hgCprKAkYVgGHyawUULSF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2On2y/btsPDDUWqyg/hgCprKAkYVgGHyawUULSF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2On2y/btsPDDUWqyg/hgCprKAkYVgGHyawUULSF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2On2y%2FbtsPDDUWqyg%2FhgCprKAkYVgGHyawUULSF0%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;976&quot; height=&quot;66&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.34.55.png&quot; data-origin-width=&quot;976&quot; data-origin-height=&quot;66&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 Docker가 잘 설치되었다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;터미널에서 `docker -v`를 입력해보면 버전을 확인할 수 있다.&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;스크린샷 2025-07-30 오후 3.41.11.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHFvuS/btsPBE1Ybwu/uds3wb9V3I75CKX49LmQvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHFvuS/btsPBE1Ybwu/uds3wb9V3I75CKX49LmQvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHFvuS/btsPBE1Ybwu/uds3wb9V3I75CKX49LmQvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHFvuS%2FbtsPBE1Ybwu%2Fuds3wb9V3I75CKX49LmQvk%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;1570&quot; height=&quot;1412&quot; data-filename=&quot;스크린샷 2025-07-30 오후 3.41.11.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;1412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/758</guid>
      <comments>https://jun-coding.tistory.com/758#entry758comment</comments>
      <pubDate>Wed, 30 Jul 2025 15:42:47 +0900</pubDate>
    </item>
    <item>
      <title>Docker란?</title>
      <link>https://jun-coding.tistory.com/757</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;컨테이너&lt;/b&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사실 아직 Docker의 이론만 공부하고, 사용해보기 전이라 크게 와닿지는 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker를 공부하는 '프론트엔드 개발'을 공부하는 사람으로써,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;매번 사이드 프로젝트 할 때마다 같은 개발 환경을 설정하기 귀찮아서 찾아보다가 Docker를 공부하게 되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;u&gt;앞으로도 '프론트엔드의 입장'에서 글을 정리해나갈 생각이다.&lt;/u&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;font-family: 'Nanum Gothic';&quot;&gt;이론 공부하면서 Docker를 왜 배워야 하는지에 대한 궁금증 정리는 전 글에 정리해두었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/755&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2025.07.29 - [Docker] - &amp;lt;프론트가&amp;gt; Docker를 왜 배워야 할까.&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1753782570578&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;&amp;lt;프론트가&amp;gt; Docker를 왜 배워야 할까.&quot; data-og-description=&quot;Docker를 왜 배워야 할까결론부터 말하자면, 특정 프로그램을 다른 곳으로 쉽게 옮겨서 설치 및 실행할 수 있는 '이식성' 때문이다.이러한 이식성은 다음과 같은 상황에 장점이 보인다.환경 일관&quot; data-og-host=&quot;jun-coding.tistory.com&quot; data-og-source-url=&quot;https://jun-coding.tistory.com/755&quot; data-og-url=&quot;https://jun-coding.tistory.com/755&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b1kvkM/hyZrvMkH51/K4kavxbaByDoC3qdeHZVF1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/HA3EM/hyZqPYDm8a/POv1Hi6XHjCIvkhm5p4uY1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://jun-coding.tistory.com/755&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://jun-coding.tistory.com/755&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b1kvkM/hyZrvMkH51/K4kavxbaByDoC3qdeHZVF1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/HA3EM/hyZqPYDm8a/POv1Hi6XHjCIvkhm5p4uY1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;lt;프론트가&amp;gt; Docker를 왜 배워야 할까.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker를 왜 배워야 할까결론부터 말하자면, 특정 프로그램을 다른 곳으로 쉽게 옮겨서 설치 및 실행할 수 있는 '이식성' 때문이다.이러한 이식성은 다음과 같은 상황에 장점이 보인다.환경 일관&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;jun-coding.tistory.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;컨테이너란 하나의 컴퓨터 환경 내에서 &lt;span style=&quot;color: #8a3db6;&quot;&gt;독립적인 컴퓨터 환경&lt;/span&gt;을 구성해서,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;각 환경에 프로그램을 별도로 설치할 수 있게 만든 개념이다.&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;font-family: 'Nanum Gothic';&quot;&gt;Windows 운영체제를 사용하면, 여러 사용자를 만들어서 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 사용자는 독립된 환경이기 때문에 필요한 프로그램을 각 사용자별로 설치해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너도 이와 비슷한 개념이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;869&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGKkiQ/btsPBGeaU2s/D76c35t9MHCw0gAIO6hMhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGKkiQ/btsPBGeaU2s/D76c35t9MHCw0gAIO6hMhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGKkiQ/btsPBGeaU2s/D76c35t9MHCw0gAIO6hMhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGKkiQ%2FbtsPBGeaU2s%2FD76c35t9MHCw0gAIO6hMhk%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;1280&quot; height=&quot;869&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;869&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하나의 컴퓨터 환경 내에서 여러 개의 '독립된 실행 환경'을 구성할 수 있는 형태이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 '독립된 실행 환경'을 '컨테이너'라고 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 이 컨테이너를 포함하고 있는 컴퓨터를 '호스트 컴퓨터'라고 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너의 독립성&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서 컨테이너는 &lt;b&gt;'&lt;span style=&quot;color: #8a3db6;&quot;&gt;독립된&lt;/span&gt; 실행 환경'&lt;/b&gt;이라고 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;구체적으로 어떤것이 독립된 환경일까?&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;먼저, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;프로세스와 파일시스템이 독립적이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각 컨테이너는 자체 파일시스템, 네트워크, 런타임 환경을 가지고 돌아간다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, 한 컨테이너에서 `npm install`로 잘못된 패키지를 설치하거나 node_modules가 꼬여도,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;옆에 있는 다른 컨테이너에는 전혀 영향이 없다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;또한, 파일시스템이 독립적이기 때문에 A컨테이너에서 B컨테이너에 있는 파일에 접근할 수 없다.&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;font-family: 'Nanum Gothic';&quot;&gt;두 번째로, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;의존성과 환경이 독립적이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너마다 Node.js, yarn, npm 등 설치 버전, 환경변수를 자유롭게 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;A컨테이너에 있는 프로젝트는 Node.js 20,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;B컨테이너에 있는 프로젝트는 Node.js 16을 사용해도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;서로 충돌 없이 각각 자기만의 환경을 쓴다.&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;font-family: 'Nanum Gothic';&quot;&gt;세 번째로, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;실행 중인 프로세스가 독립적이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너마다 독립된 PID 네임스페이스를 사용해서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;한 컨테이너에서 실행 중인 프로그램은&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;다른 컨테이너에 보이지 않고, 직접 접근하거나 통제할 수 없다.&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;font-family: 'Nanum Gothic';&quot;&gt;마지막으로, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;네트워크 영역이 독립적이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;각 컨테이너마다 고유의 네트워크를 가지고 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 컨테이너는 각자의 IP 주소를 가지고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특히, 컨테이너마다 별도의 가상 네트워크를 구성할 수 있기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특정 컨테이너끼리만 통신하게 제한하거나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;내부망/외부망을 세분화할 수도 있다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 이미지란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 이미지는 컨테이너라는 실행 환경을 만들기 위한 &lt;b&gt;설계도나 템플릿 같은 존재&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;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, React 프로젝트를 만들고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자주쓰는 axios, Tanstack Query같은 라이브러리를 설치해서 이미지로 만들었다고 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 이미지를 Docker로 실행시키면 이 프로젝트가 컨테이너 환경에서 실행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나중에 똑같이 세팅해야 할 때도, 복잡한 설치 과정을 거칠 필요 없이 실행할 수 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;즉, 이미지는 애플리케이션을 실행하는 데 필요한 코드,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;라이브러리, 설정, 환경 등 프로그램을 실행하는 데 필요한 모든 것을 포함하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 이미지의 특징&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도커 이미지는 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;불변성&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;재사용성 &lt;/b&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;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;&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;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/757</guid>
      <comments>https://jun-coding.tistory.com/757#entry757comment</comments>
      <pubDate>Wed, 30 Jul 2025 13:38:12 +0900</pubDate>
    </item>
    <item>
      <title>IP와 Port</title>
      <link>https://jun-coding.tistory.com/756</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IP의 개념&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IP란 &quot;Internet Protocol&quot;의 약자로, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;네트워크 상에서의 특정 컴퓨터를 가리키는 주소이다.&lt;/b&gt;&lt;/span&gt;&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;스크린샷 2025-07-29 오후 3.48.42.png&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db8VZa/btsPClAowSU/MQ82LsrRk877H6rYyNMqSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db8VZa/btsPClAowSU/MQ82LsrRk877H6rYyNMqSk/img.png&quot; data-alt=&quot;구글의 서버 IP 주소&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db8VZa/btsPClAowSU/MQ82LsrRk877H6rYyNMqSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb8VZa%2FbtsPClAowSU%2FMQ82LsrRk877H6rYyNMqSk%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;530&quot; height=&quot;134&quot; data-filename=&quot;스크린샷 2025-07-29 오후 3.48.42.png&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;구글의 서버 IP 주소&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위와 같이 `nslookup` 명령어를 이용해서 주소를 입력하면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;google.com도 168.126.63.1 이라는 서버 IP 주소를 가지고 있는 것을 볼 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;인터넷에 연결된 모든 장치는 반드시 자신의 IP 주소를 가지고 있어야 정보를 주고 받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 IP 주소는 데이터를 보낼 때 &lt;b&gt;목적지(받는 쪽)&lt;/b&gt;와 &lt;b&gt;출발지(보내는 쪽)&lt;/b&gt;을 지정하는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Port의 개념&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Port는 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;한 컴퓨터 내에서 실행되고 있는 특정 프로그램의 주소이다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인터넷 통신을 하려면 IP 주소가 컴퓨터의 '집 주소' 역할을 하지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하나의 컴퓨터에도 여러 프로그램이 동시에 네트워크를 쓸 수 있기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어느 프로그램에 데이터를 전달할지 구분할 필요가 있다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이때 포트 번호가 &lt;b&gt;집 안의 각 방 번호&lt;/b&gt;처럼 작용해서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;들어오는 데이터가 어떤 프로그램으로 가야 할지 구체적으로 지정해준다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;예를 들어, 특정 컴퓨너 내부에 있는 Spring Boot 서버에 통신을 하고 싶다고 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 외부에서 IP 주소만 알아서는 실행되고 있는 여러 프로그램 중에서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 프로그램과 통신을 해야할지 알 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그래서 특정 서버와 통신을 할 때는,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&lt;u&gt;IP 주소&lt;/u&gt;와 서버가 실행되고 있는 &lt;u&gt;포트 번호&lt;/u&gt;까지 알고 있어야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;브라우저 창에 포트 번호를 입력하지 않는 이유&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서 통신을 하려면 IP 주소와 포트 번호 모두 알아야 된다고 했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주소창에 'google.com' 같이 포트 번호를 입력하지 않아도 접속이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 이유는 &lt;b&gt;웹 프로토콜별로 '기본 포트 번호'가 미리 정해져 있기 때문이다.&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;font-family: 'Nanum Gothic';&quot;&gt;HTTP 프로토콜은 기본적으로 80번 포트를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 HTTPS 프로토콜은 기본적으로 443번 포트를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 브라우저는 URL에 포트 번호가 명시되지 않으면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;자동으로 HTTP는 80번, HTTPS는 443번으로 접속을 시도한다.&lt;/span&gt;&lt;/p&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/LGNDg/btsPB4eGylg/ij1Mxrx2FLDuNB9v0wYiZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LGNDg/btsPB4eGylg/ij1Mxrx2FLDuNB9v0wYiZk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;82&quot; data-filename=&quot;스크린샷 2025-07-29 오후 5.05.57.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LGNDg/btsPB4eGylg/ij1Mxrx2FLDuNB9v0wYiZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLGNDg%2FbtsPB4eGylg%2Fij1Mxrx2FLDuNB9v0wYiZk%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;522&quot; height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0F97V/btsPAX8dWwL/zMBI2XNDvSp5EbRTMf5qB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0F97V/btsPAX8dWwL/zMBI2XNDvSp5EbRTMf5qB0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;82&quot; data-filename=&quot;스크린샷 2025-07-29 오후 5.06.19.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0F97V/btsPAX8dWwL/zMBI2XNDvSp5EbRTMf5qB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0F97V%2FbtsPAX8dWwL%2FzMBI2XNDvSp5EbRTMf5qB0%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;522&quot; height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 위처럼 직접 포트번호를 명시해줘도 우리가 평소에 접속하는 google에 접속할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, HTTPS가 HTTP보다 보안이 강화되어 있기 때문에&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;80번 포트로 접속해도 보안을 위해 자동으로 443번 포트, 즉 HTTPS로 리다이렉트 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;잘 알려진 포트(Well-Known Port)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포트 번호는 0번부터 65535번까지 총 65536개가 사용 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이는 포트 번호가 16비트로 표현되기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포드 번호의 구간별 구분은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0 ~ 1023 (Well-Known 포트)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1024 ~ 49151 (등록된 포트, Registered Port)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;49152 ~ 65535 (동적/사설 포트, Dynamic/Private Port)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 중에서 Well-Known Port는 인터넷에서 시스템적으로 널리 쓰이는 서비스에 대해 정해놓은 포트 번호 범위이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 257px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포트 번호&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대표 서비스&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 19px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;20, 21&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;FTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;파일 전송 프로토콜(20: 데이터, 21: 제어)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;22&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;SSH&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;보안 셸(원격 접속)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;23&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Telnet&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원격 터미널 접속(암호화X, 비추천)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;25&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SMTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이메일 송신&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;53&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;DNS&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;도메인 이름 -&amp;gt; IP 변환&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;67, 68&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;DHCP/BOOTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IP 자동 할당(서버: 67, 클라이언트: 68)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;69&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;TFTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순 파일 전송(보안 약함)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;80&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;HTTP&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;일반 웹 서비스&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;110&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;POP3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이메일 수신(클라이언트 프로토콜)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;123&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네트워크 시간 동기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;143&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;IMAP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이메일 수신(고급 메일 프로토콜)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;161, 162&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SNMP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네트워크 관리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;389&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;LDAP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;디렉터리 서비스(조직 등 정보관리)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.7286%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;443&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;HTTPS&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%; height: 17px;&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;보안 웹 서비스(SSL/TLS 암호화)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 14.7286%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;445&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.938%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;SMB&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.3333%;&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;윈도우 파일 공유&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위 중에서 보라색으로 되어있는 것은 자주 사용되는 포트 번호이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;포트 번호를 다르게 지정해도 동작은 가능하지만,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일반적으로 관례에 맞는 well-known 포트를 사용한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/756</guid>
      <comments>https://jun-coding.tistory.com/756#entry756comment</comments>
      <pubDate>Tue, 29 Jul 2025 18:33:14 +0900</pubDate>
    </item>
    <item>
      <title>&amp;lt;프론트가&amp;gt; Docker를 왜 배워야 할까.</title>
      <link>https://jun-coding.tistory.com/755</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker를 왜 배워야 할까&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;결론부터 말하자면, &lt;b&gt;특정 프로그램을 다른 곳으로 쉽게 옮겨서 설치 및 실행할 수 있는 &lt;span style=&quot;color: #8a3db6;&quot;&gt;'이식성'&lt;/span&gt; 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이러한 이식성은 다음과 같은 상황에 장점이 보인다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;환경 일관성 확보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;빠른 개발 환경 세팅 및 온보딩&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배포 환경과 개발 환경의 완벽 동기화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;의존성/버전 충돌 방지와 격리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;백엔드/API, DB 등 다양한 서비스와 연동 용이&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;운영 자동화 및 스케일링&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하나씩 간단하게 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. &quot;내 PC에서는 되는데?&quot; 문제 해결&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Docker는 개발, 테스트, 배포에 필요한 Node.js 버전, 라이브러리, 환경변수 등을 모두 컨테이너 안에 캡슐화한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;팀원이 각자 다른 OS, Node.js, 패키지 버전을 사용한다고 해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;협업 간에 각자 사용하는 버전 차이로 인해서 어떤 사람은 되고, 어떤 사람은 되지 않는 경우가 생길 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 &lt;b&gt;Docker를 사용하면, 모두 같은 환경을 보장하기 때문에 예상치 못한 에러를 방지할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 빠른 개발 환경 세팅 및 온보딩&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;같은 역할로 여러 프로젝트를 진행하다보면, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;지난 프로젝트에서 했던 프로젝트 세팅을 그대로 하고 있는 내 모습을 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만, &lt;b&gt;이미 설정된 Docker가 있다면, 소스만 클론 받아서 한 번에 개발 환경 전체를 바로 실행할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중간에 새로 들어온 개발자도 복잡한 환경설정 과정 및 온보딩 과정을 생략할 수 있는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;결과적으로 '개발 환경 구축 및 동기화'라는 가장 귀찮고 번거로운 장벽이 제거되는 장점이 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 배포 환경과 개발 환경의 완벽 동기화&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Docker 이미지는 로컬과 스테이징, 프로덕션 어디든 똑같이 실행된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;개발 때 쓰던 이미지 그대로 실제 서버에 배포하기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;환경 차이로 인한 예상치 못한 배포 장애가 크게 줄어든다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. 의존성/버전 충돌 방지와 격리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;여러 프로젝트를 동시에 개발/운영하거나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;레거시/최신 프로젝트가 섞여있을 때도 환경 충돌 없이 독립적 개발이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;각각 아예 격리된 컨테이너에서 각각의 작업을 하면 되기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;5. 백엔드/API, DB 등 다양한 서비스와 연동&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;실제 서비스는 프론트엔드만 단독으로 운영되는 경우는 거의 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;프론트엔드, 백엔드, 데이터베이스, Redis 등 다양한 컨테이너를 한 번에 띄울 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 로컬에서 여러 서비스를 연동하는 테스트를 해야하는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;Docker가 있으면 실제 운영 서버와 거의 동일한 환경에서 개발 및 테스트가 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;Nginx와 같은 프록시와 연동해서 로컬에서도 실제 서비스 아키텍처를 그대로 재현할 수 있어서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;협업과 통합 테스트가 매우 쉬워진다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;6. 운영 자동화 및 스케일링&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;컨테이너는 여러 환경에 손쉽게 복제, 확장, 업데이트, 롤백이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;프론트엔드 서버 부하가 늘어나면 컨테이너를 더 띄워 부하 분산을 하면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Docker</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/755</guid>
      <comments>https://jun-coding.tistory.com/755#entry755comment</comments>
      <pubDate>Tue, 29 Jul 2025 15:43:56 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / 과제테스트 / [실무 역량 과제] 게시물 레이아웃 재구성하기 (FE)</title>
      <link>https://jun-coding.tistory.com/754</link>
      <description>&lt;h1&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;게시물 레이아웃 재구성하기&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/a89c6cce-d444-4ba3-b14e-59b836a30577/type02-97.gif&quot; alt=&quot;type02-97.gif&quot; /&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;  문제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;테이블 형태로 나열되어 있는 게시물 조금 더 보기 좋게 카드 형태로 레이아웃을 수정하고, 정렬 및 북마크 기능을 추가하려고 합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아래의 요구사항을 읽고 레이아웃 및 추가 기능을 완성해 주세요.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;✅ 레이아웃&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주어진 Card 컴포넌트를 활용하여 카드 형태로 레이아웃을 수정해 주세요.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이때, 카드 요소 마다 특정 &lt;code&gt;id&lt;/code&gt; 값을 지정해 주어야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;✅ 정렬&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우측 상단의 셀렉트 버튼을 사용하여 게시물의 정렬 형태를 변경할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;게시물을 &lt;code&gt;최근등록순&lt;/code&gt;과 &lt;code&gt;조회순&lt;/code&gt;으로 정렬할 수 있으며, 게시물은 기본으로 &lt;code&gt;최근등록순&lt;/code&gt;으로 정렬되어야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;✅ 북마크&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;카드 우측 상단의 북마크 아이콘 버튼을 사용하여 게시물을 북마크 할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;게시물이 북마크 되었음을 나타내기 위해서 북마크 된 게시물의 경우 북마크 아이콘이 빨간색으로 표시되어야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;북마크된 게시물의 경우에는 제일 우선으로 정렬되어야 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1. 카드 형태로 레이아웃 수정하기&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;주어진 Card 컴포넌트를 활용하여 카드 형태로 레이아웃을 수정해 주세요.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;이때, 카드 요소 마다 특정 id 값을 지정해 주어야 합니다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초기엔 Table 컴포넌트로 렌더링이 되어있는데, 이미 주어진 Card 컴포넌트로 바꾸면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나는 여기에서 Card 리스트를 보여주는 CardList 컴포넌트를 따로 만들었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748576775152&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from 'react';
import { ulid } from 'ulid';
import posts from '../data/posts.json';
import Card from './Card';
import './Card.css';

const initPostList = posts.map((post) =&amp;gt; ({ id: ulid(), ...post }));

function CardList() {
  const [postList, setPostList] = useState(initPostList);

  return (
    &amp;lt;div className=&quot;card-list&quot;&amp;gt;
      {postList.map((post) =&amp;gt; (
        &amp;lt;Card key={post.id} {...post} /&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default CardList;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;&quot;카드 요소 마다 특정 id를 지정해 주어야 합니다.&quot;&amp;nbsp;&lt;/b&gt;라는 요구사항이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 일단 주어진 posts.json 에서 데이터를 불러오고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;배열의 각 요소마다 id를 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;ulid&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;대부분의 사람들은 ulid보다 uuid가 더 익숙할 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;둘의 차이점은 뭘까?&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;가장 큰 차이점은 &lt;b&gt;ulid는&lt;/b&gt; &lt;b&gt;정렬이 가능하다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;타임스탬프에 랜덤값이 붙기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;시간순 정렬, 사전식 정렬이 가능하다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;물론, 이 테스트엔 포스트 생성기능도 없고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;upload_date가 따로 주어지므로 굳이 사용할 필요는 없다.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 가장 바깥의 div 태그에 .card-list 라는 클래스를 넣어주었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음과 같이 카드를 나열하는 css를 적용하기 위해서 넣어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748581830686&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.card-list {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 해주면, 다음과 같은 레이아웃을 구성할 수 있을것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;1890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HVYRX/btsOjdYhw0V/MOmRDRedv3ausT8N8qQilk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HVYRX/btsOjdYhw0V/MOmRDRedv3ausT8N8qQilk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HVYRX/btsOjdYhw0V/MOmRDRedv3ausT8N8qQilk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHVYRX%2FbtsOjdYhw0V%2FMOmRDRedv3ausT8N8qQilk%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;3024&quot; height=&quot;1890&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;1890&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 flex-wrap을 wrap으로 안해주면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;카드들이 가로로 쭉 늘어져서 나열되게 되므로 주의하자.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 게시물 정렬 기능 구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;게시물을&amp;nbsp;최근등록순과&amp;nbsp;조회순으로 정렬할 수 있으며, 게시물은 기본으로&amp;nbsp;최근등록순으로 정렬되어야 합니다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단 기능을 구현하기 전에 타입부터 따로 정의해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;나는 types 폴더에 따로 구현해놨다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748582440255&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export type Post = {
  id: string;
  title: string;
  views: number;
  upload_date: string;
  bookmark: boolean;
};&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 드롭다운에서 선택하는 정렬 방법을 상태값으로 갖고 있어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;게시물에 관련한 정보는 CardList 컴포넌트에서 갖고 오기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;App 컴포넌트에서 변화하는 상태값을 props로 내려주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748582589643&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 여기에 주어진 요구 사항을 충족 시키기 위한 코드를 작성 및 수정해 주세요. */
import { useState } from 'react';
import './App.css';
import CardList from './components/CardList';

const NEWEST = '1';
const VIEWS = '2';

function App() {
  const [orderType, setOrderType] = useState(NEWEST);

  const handleOrderChange = (e: React.ChangeEvent&amp;lt;HTMLSelectElement&amp;gt;) =&amp;gt; {
    setOrderType(e.target.value);
  };

  return (
    &amp;lt;div className=&quot;container&quot;&amp;gt;
      &amp;lt;div className=&quot;section __order&quot;&amp;gt;
        &amp;lt;select id=&quot;order_type&quot; value={orderType} onChange={handleOrderChange}&amp;gt;
          &amp;lt;option value={NEWEST}&amp;gt;최근등록순&amp;lt;/option&amp;gt;
          &amp;lt;option value={VIEWS}&amp;gt;조회순&amp;lt;/option&amp;gt;
        &amp;lt;/select&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div className=&quot;section&quot;&amp;gt;
        &amp;lt;CardList orderType={orderType} /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default App;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;NEWEST와 VIEWS라는 상수 변수를 정의해주었는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;각각 option 태그의 value 속성의 값으로 쓰이는 변수이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그냥 '1', '2'로 쓰이는 것 보다는 확실하게 보이도록 따로 선언해주었다.&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;font-family: 'Nanum Gothic';&quot;&gt;그리고 정렬 방법을 변경하는 함수인 handleOrderChange를 구현해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;select 태그의 onChange 이벤트 핸들러로 달아주고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정렬 방법인 orderType 상태값을 CardList 컴포넌트에 props로 내려주었다.&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;font-family: 'Nanum Gothic';&quot;&gt;다음으로는 정렬 기능 구현이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748583070094&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from 'react';
import { ulid } from 'ulid';
import posts from '../data/posts.json';
import type { Post } from '../types';
import Card from './Card';
import './Card.css';

const NEWEST = '1';
const VIEWS = '2';

const initPostList: Post[] = posts.map((post) =&amp;gt; ({ id: ulid(), ...post }));

interface CardListProps {
  orderType: string;
}

function CardList({ orderType }: CardListProps) {
  const [postList, setPostList] = useState&amp;lt;Post[]&amp;gt;(initPostList);

  const sortedPostList = [...postList].sort((a, b) =&amp;gt; {
    if (orderType === NEWEST) {
      return (
        new Date(b.upload_date).getTime() - new Date(a.upload_date).getTime()
      );
    } else {
      return b.views - a.views;
    }
  });

  return (
    &amp;lt;div className=&quot;card-list&quot;&amp;gt;
      {sortedPostList.map((post) =&amp;gt; (
        &amp;lt;Card key={post.id} {...post} /&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}

export default CardList;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;크게 어려울 것은 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;정렬 방법에 맞게 최신순, 조회순으로 sort()를 이용해 정렬해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최신순 정렬을 할 때는 &lt;b&gt;Date()의 getTime()을 이용하면 1970년 1월 1일 00:00:00 UTC 기준으로,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그 후로 몇 밀리초가 지났는지 숫자로 반환해준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;클수록 오래지났다는 의미이니까, 최신순이 된다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;3. 북마크 토글 기능 구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;카드 우측 상단의 북마크 아이콘 버튼을 사용하여 게시물을 북마크 할 수 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;게시물이 북마크 되었음을 나타내기 위해서 북마크 된 게시물의 경우 북마크 아이콘이 빨간색으로 표시되어야 합니다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 색을 변하게 하기 전에 북마크 상태를 토글하는 기능을 만들어주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748583558237&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const handleBookmarkToggle = (id: string) =&amp;gt; {
  setPostList((prevPostList) =&amp;gt;
    prevPostList.map((post) =&amp;gt;
      post.id === id ? { ...post, bookmark: !post.bookmark } : post
    )
  );
};&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 포스트를 순회하면서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 북마크 아이콘을 클릭한 포스트의 아이디와 같다면 해당 포스트의 bookmark를 바꿔주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이전 상태값에 의존해서 상태 변경이 일어나기 때문에,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;함수형 업데이트&lt;/b&gt;&lt;/span&gt;를 사용해주어야 한다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이렇게 만든 함수를 onBookmarkToggle 이라는 이름의 prop으로 넘겨주었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748583774613&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;Card key={post.id} {...post} onBookmarkToggle={handleBookmarkToggle} /&amp;gt;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이제 이 넘겨준 함수를 북마크 아이콘에 달아주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748583913663&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;span className=&quot;icon bookmark&quot; onClick={() =&amp;gt; onBookmarkToggle(id)}&amp;gt;
  &amp;lt;i className=&quot;fa fa-bookmark&quot; style={{ color: bookmark ? 'red' : '#fff' }}&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/span&amp;gt;&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 북마크 상태에 따라서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;style에 color를 red로 주거나, 기본값인 흰색으로 주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;4. 북마크 우선 정렬 기능 구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;북마크된 게시물의 경우에는 제일 우선으로 정렬되어야 합니다.&lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;마지막으로, 북마크된 게시물은 가장 앞으로 와야한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그리고 북마크된 게시물들끼리도 설정한 정렬 방법에 따라 정렬이 이루어져야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;간단하게 정렬 조건에 하나만 추가해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1748584181934&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const sortedPostList = [...postList].sort((a, b) =&amp;gt; {
  if (a.bookmark !== b.bookmark) {
    return a.bookmark ? -1 : 1;
  }

  if (orderType === NEWEST) {
    return (
      new Date(b.upload_date).getTime() - new Date(a.upload_date).getTime()
    );
  } else {
    return b.views - a.views;
  }
});&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;앞, 뒤 게시물끼리 북마크 여부를 판단해서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;북마크 여부 상태가 다를 경우에 북마크 된 것을 앞으로 보내주면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;만약, 둘 다 북마크가 되어있거나, 되어있지 않을 경우에는&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에 설정해준 정렬 방법에 따른 조건에따라 정렬을 수행할 것이다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이렇게 완성!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;주의!&lt;/span&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;초기에 설정한 값이 아니라, 데이터대로 다 표시되어 있는지 확인하자.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특히, Card 컴포넌트에 id값 잘 확인하자!&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>programmers</category>
      <category>[실무 역량 과제] 게시물 레이아웃 재구성하기 (fe)</category>
      <category>과제 테스트</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/754</guid>
      <comments>https://jun-coding.tistory.com/754#entry754comment</comments>
      <pubDate>Fri, 30 May 2025 14:53:56 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 투 포인터 / 22862번 / 가장 긴 짝수 연속한 부분 수열 (large) / JS</title>
      <link>https://jun-coding.tistory.com/753</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;길이가 N인 수열 S가 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;수열 S는 1이상 정수로 이루어져 있는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;최대 K개의 정수를 삭제할 수 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;최대 K개 삭제한 수열에서,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;짝수로 이루어져 있는 연속한 부분 수열 중,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;가장 긴 길이를 구하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= N &amp;lt;= 1,000,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= K &amp;lt;= 100,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= 원소의 값 &amp;lt;= 1,000,000&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1744001501843&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, K] = input.shift().split(' ').map(Number);
const sequence = input.shift().split(' ').map(Number);

function solution() {
  let left = 0;
  let right = 0;
  let removeCount = 0; // 제거한 홀수의 개수
  let result = 0;

  while (right &amp;lt; N) {
    // 짝수일 경우
    if (sequence[right] % 2 === 0) {
      result = Math.max(result, right - left - removeCount + 1);
      right++;
    } else {
      // 홀수일 경우
      // 제거한 홀수의 개수가 K보다 작으면 제거한 홀수의 개수를 증가시키고 포인터를 오른쪽으로 이동
      if (removeCount &amp;lt; K) {
        removeCount++;
        right++;
      } else {
        // 더 이상 제거할 수 없으면 왼쪽 포인터를 오른쪽으로 이동
        while (removeCount === K) {
          // 왼쪽 포인터가 가리키는 수가 홀수일 경우
          // 제거한 홀수의 개수를 줄이고 왼쪽 포인터 한 칸 오른쪽으로 이동
          if (sequence[left] % 2 === 1) {
            removeCount--;
          }
          left++;
        }
      }
    }
  }

  console.log(result);
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;투 포인터 알고리즘에서 조금 더 응용이 들어간 문제였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본적인 문제에서 다음 두 가지만 신경쓰면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제거 횟수 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 이상 제거할 수 없을 때 어떻게 할것인지&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제거 횟수 관리&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;먼저, 제거 횟수를 관리하는 부분부터 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에 최대 제거 횟수 K가 주어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우리는 이 횟수를 홀수를 제거하는데 써야한다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;오른쪽 포인터가 수열의 끝에 다다를 때 까지 반복문으로 탐색한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;오른쪽 포인터가 가리키는 값이 짝수&lt;/b&gt;라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;현재 저장되어 있는 최댓값과 &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;현재 수열의 길이에서 제거한 수를 뺀만큼의 길이를 비교하면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그리고 오른쪽 포인터를 한 칸 옮겨준다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;만약 오른쪽 포인터가 가리키는 값이 홀수&lt;/b&gt;라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 두 가지 상황이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제거할 수 있는 횟수가 남았을 때&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제거할 수 있는 횟수가 남지 않았을 때&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제거할 수 있는 횟수가 남았을 때&lt;/b&gt;는 간단하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;현재 가리키는 홀수를 제거하고, &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;포인터를 한 칸 옮겨주면 된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;더 이상 제거할 수 없을 때 어떻게 할 것인지&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그런데, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;제거할 수 있는 횟수가 남지 않았을 때는 어떻게 할까?&lt;/span&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: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;일단 왼쪽 포인터를 짝수를 만날때까지 옮겨준다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그러면 우리가 홀수를 제거할 때 썼던 횟수를 충전할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;예시로 알아보자.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;1, 2, 4, 4, 5, 6, 7, 8 이라는 수열이 있을 때,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;현재 left가 1을 가리키고 있고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;right가 5를 가리키고 있다고 해보자.&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;font-family: 'Nanum Gothic';&quot;&gt;'가장 긴 짝수 연속한 부분 수열'을 구해야 하므로,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1을 제거하는데 제거 횟수를 한 번 썼을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러니까 이 때 사용한 제거 횟수를 충전하기 위해서&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;left를 2로 옮겨준다.&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;font-family: 'Nanum Gothic';&quot;&gt;그러면 1, 2, 4, 4, 5 에서 가장 긴 짝수 연속한 부분 수열이나,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2, 4, 4, 5에서 가장 긴 짝수 연속한 부분 수열은 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, 전자는 제거 횟수를 1을 제거하는데에 썼고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;후자는 제거 횟수를 사용하지 않았다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;이런 식으로 계속해서 반복하다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단 한번의 순회로 문제를 해결할 수 있다.&lt;/span&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: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시간 복잡도는 O(n)이 되는 것이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>22862번</category>
      <category>js</category>
      <category>가장 긴 짝수 연속한 부분 수열</category>
      <category>백준</category>
      <category>투 포인터</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/753</guid>
      <comments>https://jun-coding.tistory.com/753#entry753comment</comments>
      <pubDate>Mon, 7 Apr 2025 21:34:11 +0900</pubDate>
    </item>
    <item>
      <title>Programmers / Level 2 / 우박수열 정적분 / JS</title>
      <link>https://jun-coding.tistory.com/752</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;우박수열은 1을 만들기 위해 다음과 같은 단계를 거칩니다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1-1. 입력된 수가 짝수라면 2로 나눕니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2. 결과로 나온 수가 1보다 크다면 위 작업을 반복합니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;은지는 우박수열을 좌표 평면 위에 꺾은선 그래프로 나타내보려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초항이 k인 우박수열이 있다면, x = 0일때 y = k이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 우박수는 x = 1에 표시합니다.&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;font-family: 'Nanum Gothic';&quot;&gt;이렇게 만든 꺾은선 그래프를 정적분 하려고 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;x에 대한 범위 [a, b]가 주어진다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음부터 a만큼, 끝에서 b만큼 좌표사이의 넓이를 구하면 됩니다.&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;font-family: 'Nanum Gothic';&quot;&gt;예를 들어,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;좌표가 6개 주어졌고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;[a, b]가 [1, -2]라면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;x = 1부터 x = 5(배열은 0부터 시작하므로 6은 5번째이다)에서 2를 뺀 3까지의 넓이를 구하면 됩니다.&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;font-family: 'Nanum Gothic';&quot;&gt;위 방법대로 주어진 ranges의 각 구간별 정적분(넓이)결과를 담아서 반환하면 됩니다.&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2 &amp;lt;= k &amp;lt;= 10,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= ranges의 길이 &amp;lt;= 10,000&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ranges의 원소는 [a, b] 형식이며,&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0 &amp;lt;= a &amp;lt; 200&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;-200 &amp;lt; b &amp;lt;= a&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주어진 모든 입력값의 정적분 결과는 2^27을 넘지 않습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1743592034426&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 우박수열 정적분
 * @param {number} k 우박수열의 첫 번째 수
 * @param {number[][]} ranges 정적분을 구할 범위
 * @returns {number[]} 정적분 결과
 */
function solution(k, ranges) {
  const hailstoneSequence = [{ x: 0, y: k }];
  const areaList = [];
  const result = [];

  /**
   * 우박수열 생성
   */
  const getHailstoneSequence = () =&amp;gt; {
    let order = 0;
    let curNumber = k;

    while (curNumber &amp;gt; 1) {
      if (curNumber % 2 === 0) {
        curNumber = curNumber / 2;
      } else {
        curNumber = curNumber * 3 + 1;
      }

      order++;
      hailstoneSequence.push({ x: order, y: curNumber });
    }
  };

  /**
   * 넓이 리스트 생성
   */
  const getAreaList = () =&amp;gt; {
    for (let i = 1; i &amp;lt; hailstoneSequence.length; i++) {
      const prevCoords = hailstoneSequence[i - 1];
      const curCoords = hailstoneSequence[i];

      const upperBase = prevCoords.y;
      const lowerBase = curCoords.y;
      const height = 1;
      const area = ((upperBase + lowerBase) * height) / 2;

      areaList.push(area);
    }
  };

  /**
   * 정적분 계산
   * @param {number} a 시작 인덱스
   * @param {number} b 끝 인덱스
   * @returns {number} 정적분 결과
   */
  const getIntegral = (a, b) =&amp;gt; {
    const start = a;
    const end = hailstoneSequence.length - 1 + b;

    if (start &amp;gt; end) {
      return -1;
    }

    if (start === end) {
      return 0;
    }

    let sum = 0;
    for (let i = start; i &amp;lt; end; i++) {
      sum += areaList[i];
    }

    return sum;
  };

  /**
   * 결과 생성
   */
  const getResult = () =&amp;gt; {
    for (const [a, b] of ranges) {
      const integral = getIntegral(a, b);

      result.push(integral);
    }
  };

  getHailstoneSequence();
  getAreaList();
  getResult();

  return result;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제에 나온대로 그대로 구현하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에 넓이를 구할 때,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;반으로 나눠서 사각형과 삼각형의 넓이를 따로 구해서 더하려고 했는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사다리꼴 넓이 공식을 까먹고 있었기 때문이다...&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;사다리꼴 넓이 공식은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;(윗 변 + 아랫 변) * 높이 / 2&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;여기서 윗 변과 아랫 변은 각각 y좌표이며,&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;높이는 1로 고정되어 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;특별히 미리 조건처리하면 좋을 것들은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시작점의 x좌표가 끝점의 x좌표보다 클 때&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;유효하지 않으므로 -1을 반환한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;시작점의 x좌표와 끝점의 x좌표와 같을 때&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;넓이가 0이므로 0을 반환한다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 조건들만 미리 처리해주면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;굳이 불필요한 계산을 하지 않고 쉽게 답을 구할 수 있다.&lt;/span&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;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 2</category>
      <category>우박수열 정적분</category>
      <category>프로그래머스</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/752</guid>
      <comments>https://jun-coding.tistory.com/752#entry752comment</comments>
      <pubDate>Wed, 2 Apr 2025 20:13:21 +0900</pubDate>
    </item>
    <item>
      <title>Programers / Level 3 / 양과 늑대 / JS</title>
      <link>https://jun-coding.tistory.com/751</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-size: 16px; letter-spacing: 0px; font-family: 'Nanum Gothic';&quot;&gt;&quot;양과 늑대&quot; 문제는 트리 구조에서 양과 늑대를 관리하며 최대한 많은 양을 모으는 문제입니다.&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2 &amp;lt;= info의 길이 &amp;lt;= 17&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;info의 원소는 0 또는 1입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;info[i]는 i번 노드에 있는 양 또는 늑대를 나타냅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0은 양, 1은 늑대를 의미합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;info[0]의 값은 항상 0입니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉, 0번 노드(루트 노드)에는 항상 양이 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;edges의 세로(행)의 길이 = info의 길이 - 1&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;edges의 가로(열)의 길이 = 2&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;edges의 각 행은 [부모 노드 번호, 자식 노드 번호] 형태로,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;서로 연결된 두 노드를 나타냅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;동일한 간선에 대한 정보가 중복해서 주어지지 않습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;항상 하나의 이진 트리 형태로 입력이 주어지며, 잘못도니 데이터가 주어지는 경우는 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0번 노드는 항상 루트 노드입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1740715924114&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * 주어진 정보와 엣지를 기반으로 최대 양의 수를 계산합니다.
 * @param {number[]} info - 각 노드가 양인지 늑대인지 나타내는 배열 (0: 양, 1: 늑대)
 * @param {number[][]} edges - 그래프의 엣지를 나타내는 배열 (각 엣지는 [from, to] 형태)
 * @returns {number} - 가능한 최대 양의 수
 */
function solution(info, edges) {
  const SHEEP = 0;
  const WOLF = 1;

  const graph = Array.from({ length: info.length }, () =&amp;gt; []);

  let maxSheepCount = 0;

  /**
   * 엣지를 기반으로 그래프를 초기화합니다.
   * @description 이 함수는 전역 변수 `graph`를 엣지 정보로 채워 트리 구조를 생성합니다.
   */
  const initGraph = () =&amp;gt; {
    for (const [from, to] of edges) {
      graph[from].push(to);
    }
  };

  /**
   * 깊이 우선 탐색을 통해 가능한 모든 경로를 탐색하며 양의 수를 최대화합니다.
   * @param {number} curNode - 현재 탐색 중인 노드의 인덱스
   * @param {number} sheepCount - 현재까지 만난 양의 수
   * @param {number} wolfCount - 현재까지 만난 늑대의 수
   * @param {Set&amp;lt;number&amp;gt;} possibleVisitSet - 방문 가능한 노드의 집합
   * @description 이 함수는 재귀적으로 호출되며, 늑대 수가 양의 수 이상이 되지 않는 경로에서 최대 양의 수를 계산합니다.
   */
  const dfs = (curNode, sheepCount, wolfCount, possibleVisitSet) =&amp;gt; {
    let nextSheepCount = sheepCount;
    let nextWolfCount = wolfCount;

    if (info[curNode] === SHEEP) {
      nextSheepCount++;
    } else {
      nextWolfCount++;
    }

    if (nextWolfCount &amp;gt;= nextSheepCount) {
      return;
    }

    maxSheepCount = Math.max(maxSheepCount, nextSheepCount);

    // 원본이 수정되는것을 막기 위해 복사를해서 사용합니다.
    const nextPossibleVisitSet = new Set(possibleVisitSet);
    // 현재 노드는 방문중이므로 방문 가능한 노드 Set에서 삭제합니다.
    nextPossibleVisitSet.delete(curNode);

    for (const adjNode of graph[curNode]) {
      nextPossibleVisitSet.add(adjNode);
    }

    for (const nextPossibleNode of nextPossibleVisitSet) {
      dfs(
        nextPossibleNode,
        nextSheepCount,
        nextWolfCount,
        nextPossibleVisitSet
      );
    }
  };

  initGraph();
  dfs(0, 0, 0, new Set());

  return maxSheepCount;
}&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기본 DFS 문제들과 비슷하지만, 하나 추가된게 있다면 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;갈 수 있는 후보 노드들을 저장&lt;/b&gt;&lt;/span&gt;해놔야 한다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중복되면 안되므로 Set 자료구조를 이용했는데, 그냥 배열로 처리해도 상관은 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다만, 어떤 자료구조를 이용해도 조심해야 할 것은 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 재귀를 진행하기 위해 인자를 넘기기 위해 &lt;b&gt;현재 재귀에서 사용했던 자료구조를 그대로 넘기면 안된다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;배열이나 Set 등의 자료구조를 그냥 넘기게 되면 주소값을 넘기게 되므로, 원본이 바뀌기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 복사해서 로직을 진행 한 후,&lt;b&gt; 복사한 것을 넘겨줘야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/Programmers</category>
      <category>js</category>
      <category>Level 3</category>
      <category>programmers</category>
      <category>양과 늑대</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/751</guid>
      <comments>https://jun-coding.tistory.com/751#entry751comment</comments>
      <pubDate>Fri, 28 Feb 2025 13:16:39 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 수학 / 11444번 / 피보나치 수 6 / JS</title>
      <link>https://jun-coding.tistory.com/750</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;n이 주어졌을 때, n번째 피보나치 수를 출력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start; font-family: 'Nanum Gothic';&quot;&gt; n은 1,000,000,000,000,000,000보다 작거나 같은 자연수이다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1736764671938&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const n = BigInt(input.shift());

const DIVISOR = BigInt(1e9 + 7);
const memo = [];

function solution() {
  memo[0] = 0n;
  memo[1] = 1n;
  memo[2] = 1n;

  const result = fibonacci(n);
  console.log(result.toString());
}

function fibonacci(n) {
  if (memo[n]) {
    return memo[n];
  }

  const half = n / 2n;
  if (n % 2n === 0n) {
    memo[n] =
      (fibonacci(half) * (2n * fibonacci(half - 1n) + fibonacci(half))) %
      DIVISOR;
  } else {
    memo[n] =
      (fibonacci(half) * fibonacci(half) +
        fibonacci(half + 1n) * fibonacci(half + 1n)) %
      DIVISOR;
  }

  return memo[n];
}

solution();&lt;/code&gt;&lt;/pre&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;902&quot; data-origin-height=&quot;1160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VZGSW/btsLMD5qbEN/BorjotqEfobCkUFy541Kl0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VZGSW/btsLMD5qbEN/BorjotqEfobCkUFy541Kl0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VZGSW/btsLMD5qbEN/BorjotqEfobCkUFy541Kl0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVZGSW%2FbtsLMD5qbEN%2FBorjotqEfobCkUFy541Kl0%2Fimg.jpg&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;902&quot; height=&quot;1160&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;1160&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;도가뉴 항등식&lt;/a&gt;을 이용해 풀이했다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736767136142&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;피보나치 수 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 피보나치 수를 이용한 사각형 채우기 수학에서 피보나치 수(영어: Fibonacci numbers)는 첫째 및 둘째 항이 1이며 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열이다. &quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/8rMbn/hyX0AaWrDT/MU8sWcSWn53cRQvj6rGHAk/img.png?width=223&amp;amp;height=138&amp;amp;face=0_0_223_138,https://scrap.kakaocdn.net/dn/fcfJy/hyX0mcHIUS/kKKKxOGuJVCWhEogOgyEe1/img.png?width=223&amp;amp;height=138&amp;amp;face=0_0_223_138&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/8rMbn/hyX0AaWrDT/MU8sWcSWn53cRQvj6rGHAk/img.png?width=223&amp;amp;height=138&amp;amp;face=0_0_223_138,https://scrap.kakaocdn.net/dn/fcfJy/hyX0mcHIUS/kKKKxOGuJVCWhEogOgyEe1/img.png?width=223&amp;amp;height=138&amp;amp;face=0_0_223_138');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;피보나치 수 - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위키백과, 우리 모두의 백과사전. 피보나치 수를 이용한 사각형 채우기 수학에서 피보나치 수(영어: Fibonacci numbers)는 첫째 및 둘째 항이 1이며 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열이다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.wikipedia.org&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 외에도 claude에게 물어보니, 행렬의 거듭제곱으로 풀이하는 방법도 있던데 나중에 알아봐야겠다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>11444번</category>
      <category>js</category>
      <category>백준</category>
      <category>수학</category>
      <category>피보나치 수 6</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/750</guid>
      <comments>https://jun-coding.tistory.com/750#entry750comment</comments>
      <pubDate>Mon, 13 Jan 2025 20:19:36 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 그래프 / 2206번 / 벽 부수고 이동하기 / JS</title>
      <link>https://jun-coding.tistory.com/749</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;N&amp;times;M 크기의 맵이 주어집니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;맵의 각 칸은 0(이동 가능) 또는 1(벽)입니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(1,1)에서 (N,M)까지 이동하려고 합니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;벽을 한 번만 부술 수 있는 능력이 있습니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;목표는 최단 경로의 길이를 찾는 것입니다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= N &amp;lt;= 1,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= M &amp;lt;= 1,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(1, 1)과 (N, M)은 항상 0이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 &lt;span style=&quot;color: #ee2323;&quot;&gt;(시간 초과)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1736606427173&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split('').map(Number));

const EMPTY = 0;
const WALL = 1;

const dr = [-1, 1, 0, 0];
const dc = [0, 0, -1, 1];

let result = Infinity;

function solution() {
  bfs();

  console.log(result === Infinity ? -1 : result);
}

function bfs() {
  const queue = [[0, 0, 1, false]];
  const visited = Array.from({ length: N }, () =&amp;gt; Array(M).fill(false));

  visited[0][0] = true;

  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curCount, broken] = queue.shift();

    if (curRow === N - 1 &amp;amp;&amp;amp; curCol === M - 1) {
      result = curCount;
      return;
    }

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      if (!isValid(nr, nc)) {
        continue;
      }
      if (visited[nr][nc]) {
        continue;
      }
      if (broken &amp;amp;&amp;amp; map[nr][nc] === WALL) {
        continue;
      }

      visited[nr][nc] = true;

      if (map[nr][nc] === WALL &amp;amp;&amp;amp; !broken) {
        queue.push([nr, nc, curCount + 1, true]);
      } else {
        queue.push([nr, nc, curCount + 1, broken]);
      }
    }
  }
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; M;
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;BFS를 이용해 문제를 풀었다. 2% 정도에서 시간초과가 났었는데, 문제는 BFS의 while문에 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;while문에서 &lt;b&gt;queue의 맨 앞의 요소를 뽑아내기 위해 shift() 메서드를 사용했는데, 그렇게되면 그 뒤 요소들이 앞으로 한 칸 씩 당겨지는 O(N)의 시간복잡도를 매 반복마다 가지기 때문에 시간초과가 발생했다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;(오답)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1736606575777&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split('').map(Number));

const EMPTY = 0;
const WALL = 1;

const dr = [-1, 1, 0, 0];
const dc = [0, 0, -1, 1];

let result = Infinity;

function solution() {
  bfs();

  console.log(result === Infinity ? -1 : result);
}

function bfs() {
  const queue = [[0, 0, 1, false]];
  const visited = Array.from({ length: N }, () =&amp;gt; Array(M).fill(false));

  visited[0][0] = true;

  let queueIndex = 0;
  while (queueIndex &amp;lt; queue.length) {
    const [curRow, curCol, curCount, broken] = queue[queueIndex++];

    if (curRow === N - 1 &amp;amp;&amp;amp; curCol === M - 1) {
      result = curCount;
      return;
    }

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      if (!isValid(nr, nc)) {
        continue;
      }
      if (visited[nr][nc]) {
        continue;
      }
      if (broken &amp;amp;&amp;amp; map[nr][nc] === WALL) {
        continue;
      }

      visited[nr][nc] = true;

      if (map[nr][nc] === WALL &amp;amp;&amp;amp; !broken) {
        queue.push([nr, nc, curCount + 1, true]);
      } else {
        queue.push([nr, nc, curCount + 1, broken]);
      }
    }
  }
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; M;
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서 말했다시피, shift() 메서드가 문제였기 때문에 queue의 index를 나타내는 queueIndex라는 변수를 따로 뒀다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 약 15% 정도에서 틀렸다.&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;font-family: 'Nanum Gothic';&quot;&gt;생각해보니 &lt;b&gt;각 칸마다 벽을 부수고 도달했는지, 부수지 않고 도달했는지를 판단할 수 없었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;위의 코드는 단순히, 한 번 벽을 부쉈으니까 다음엔 벽 못부셔~&lt;/b&gt; 라는 로직일 뿐이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;visited 배열을 벽을 부수고 도달했는지, 부수지 않고 도달했는지를 따로 저장하도록 3차원 배열을 만들어서 해결했다.&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1736606819703&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split('').map(Number));

const EMPTY = 0;
const WALL = 1;

const dr = [-1, 1, 0, 0];
const dc = [0, 0, -1, 1];

function solution() {
  const result = bfs();

  console.log(result);
}

function bfs() {
  const queue = [[0, 0, 1, 0]];
  const visited = Array.from({ length: N }, () =&amp;gt;
    Array.from({ length: M }, () =&amp;gt; Array(2).fill(false))
  );

  visited[0][0][0] = true;

  let queueIndex = 0;
  while (queueIndex &amp;lt; queue.length) {
    const [curRow, curCol, curCount, broken] = queue[queueIndex++];

    if (curRow === N - 1 &amp;amp;&amp;amp; curCol === M - 1) {
      return curCount;
    }

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      if (!isValid(nr, nc)) {
        continue;
      }

      // 갈 수 있는 곳 일 때,
      if (map[nr][nc] === EMPTY) {
        if (!visited[nr][nc][broken]) {
          queue.push([nr, nc, curCount + 1, broken]);
          visited[nr][nc][broken] = true;
        }
        // 벽이지만, 아직 벽을 부순 적이 없을 경우,
      } else if (map[nr][nc] === WALL &amp;amp;&amp;amp; broken === 0) {
        if (!visited[nr][nc][1]) {
          queue.push([nr, nc, curCount + 1, 1]);
          visited[nr][nc][1] = true;
        }
      }
    }
  }

  return -1;
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; N &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; M;
}

solution();&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/백준</category>
      <category>2206번</category>
      <category>js</category>
      <category>그래프</category>
      <category>백준</category>
      <category>벽 부수고 이동하기</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/749</guid>
      <comments>https://jun-coding.tistory.com/749#entry749comment</comments>
      <pubDate>Sat, 11 Jan 2025 23:47:37 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 그래프 / 9019번 / DSLR / JS</title>
      <link>https://jun-coding.tistory.com/748</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;네 자리 숫자 A를 B로 바꾸기 위해 아래 4개의 명령어를 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;D&lt;/b&gt;: A를 두 배로 만들고, 10000 이상이면 10000으로 나눈 나머지.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;S&lt;/b&gt;: A에서 1을 뺀 값. 0이면 9999.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;L&lt;/b&gt;: A의 왼쪽 회전. 예: 1234 &amp;rarr; 2341.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;R&lt;/b&gt;: A의 오른쪽 회전. 예: 1234 &amp;rarr; 4123.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;목표&lt;/b&gt;:&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;숫자 A에서 시작해 숫자 B로 바꾸는 최소한의 명령어 나열을 구하시오.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start; font-family: 'Nanum Gothic';&quot;&gt; 가능한 명령어 나열이 여러가지면, 아무거나 출력한다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start; font-family: 'Nanum Gothic';&quot;&gt; A 와 B는 모두 0 이상 10,000 미만이다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 (시간 초과)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1735749233362&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

let index = 0;
const T = +input.shift();

function solution() {
  for (let testCase = 1; testCase &amp;lt;= T; testCase++) {
    const [A, B] = input[index++].split(' ').map(Number);

    bfs(A, B);
  }
}

function bfs(A, B) {
  const queue = [[A, '']];
  const visited = Array.from({ length: 10000 }, () =&amp;gt; false);

  visited[A] = true;

  let head = 0;
  while (queue.length &amp;gt; 0) {
    const [curNumber, totalCommand] = queue[head++];

    if (curNumber === B) {
      console.log(totalCommand);
      return;
    }

    const nextNumberList = [
      [D(curNumber), 'D'],
      [S(curNumber), 'S'],
      [L(curNumber), 'L'],
      [R(curNumber), 'R'],
    ];
    nextNumberList.forEach(([nextNumber, command]) =&amp;gt; {
      if (visited[nextNumber]) {
        return;
      }

      visited[nextNumber] = true;
      queue.push([nextNumber, totalCommand + command]);
    });
  }
}

function D(number) {
  return (number * 2) % 10000;
}

function S(number) {
  return number - 1 === 0 ? 9999 : number - 1;
}

function L(number) {
  const strNumber = number.toString().padStart(4, '0');
  return Number(strNumber.slice(1) + strNumber[0]);
}

function R(number) {
  const strNumber = number.toString().padStart(4, '0');
  return Number(strNumber[3] + strNumber.slice(0, 3));
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 그대로 구현하였는데, 계속 시간 초과가 나왔다. AI에게 도움 요청을해서 로직에 대한것만 확인해달라고 하였지만 로직에 대한것은 틀린것이 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무리봐도 BFS 과정에선 틀린것이 없을 것 같아서, 함수로 눈길을 돌렸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;L과 R 함수에 padStart(), slice() 같은 함수가 있어서 만약 L,R 커맨드를 많이 하게 될 경우 시간초과가 날 것 같았다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1735749390817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const T = +input.shift();

function solution() {
  for (let testCase = 1; testCase &amp;lt;= T; testCase++) {
    const [A, B] = input.shift().split(' ').map(Number);

    bfs(A, B);
  }
}

function bfs(A, B) {
  const queue = [[A, '']];
  const visited = Array(10000).fill(false);
  visited[A] = true;

  while (queue.length &amp;gt; 0) {
    const [cur, commandList] = queue.shift();

    if (cur === B) {
      console.log(commandList);
      return;
    }

    const nextStateList = [
      [D(cur), 'D'],
      [S(cur), 'S'],
      [L(cur), 'L'],
      [R(cur), 'R'],
    ];

    for (const [nextNumber, command] of nextStateList) {
      if (!visited[nextNumber]) {
        visited[nextNumber] = true;
        queue.push([nextNumber, commandList + command]);
      }
    }
  }
}

function D(number) {
  return (number * 2) % 10000;
}

function S(number) {
  return number === 0 ? 9999 : number - 1;
}

function L(number) {
  const d1 = Math.floor(number / 1000);
  return (number % 1000) * 10 + d1;
}

function R(number) {
  const d4 = number % 10;
  return Math.floor(number / 10) + d4 * 1000;
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;생각했던게 맞았다. L과 R함수의 메서드 사용에 대한 시간복잡도가 문제였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다른건 바뀐게 없지만, &lt;b&gt;본래 String으로 형변환하여 한칸씩 옮기는것을 처리했던 것을 &lt;span style=&quot;color: #8a3db6;&quot;&gt;단순히 모듈러 연산을통해 자릿수를 조정하여 처리&lt;/span&gt;하였다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특별한 메서드 없이 단순 연산이기 때문에 시간복잡도가 줄었을 것이고, 통과하였다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>9019번</category>
      <category>DSLR</category>
      <category>js</category>
      <category>그래프</category>
      <category>백준</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/748</guid>
      <comments>https://jun-coding.tistory.com/748#entry748comment</comments>
      <pubDate>Thu, 2 Jan 2025 01:46:13 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 그래프 / 16928번 / 뱀과 사다리 게임 / JS</title>
      <link>https://jun-coding.tistory.com/747</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&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&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;게임의 규칙&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1번 칸에서 시작하여 100번 칸에 도달하는 것을 목표로 하는 게임.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;플레이어는 매턴 주사위를 굴려 1에서 6까지의 값을 얻어 앞으로 이동.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;특정 칸에는 &lt;b&gt;사다리&lt;/b&gt;나 &lt;b&gt;뱀&lt;/b&gt;이 있음:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;사다리&lt;/b&gt;: 해당 칸에 도달하면 더 높은 칸으로 이동.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;뱀&lt;/b&gt;: 해당 칸에 도달하면 더 낮은 칸으로 이동.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;입력&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;첫 줄: 사다리의 수 N과 뱀의 수 M.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 N줄: 각 줄에 사다리의 시작과 끝 &lt;span aria-hidden=&quot;true&quot;&gt;x,y&lt;/span&gt; (항상 x&amp;lt;y).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;다음 M줄: 각 줄에 뱀의 머리와 꼬리 u,v(항상 &lt;span aria-hidden=&quot;true&quot;&gt;u&amp;gt;v&lt;/span&gt;).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;출력&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1번 칸에서 시작하여 100번 칸에 도달하기 위한 &lt;b&gt;최소 이동 횟수&lt;/b&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;1&amp;le;N,M&amp;le;15&lt;/span&gt;: 사다리와 뱀의 개수.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;칸 번호는 1&amp;le;x,y,u,v&amp;le;1001 \leq x, y, u, v \leq 100&lt;span aria-hidden=&quot;true&quot;&gt;1&amp;le;x,y,u,v&amp;le;100&lt;/span&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;칸은 서로 연결되며, 순환이 없음(사다리나 뱀을 따라 무한 루프에 빠지지 않음).&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 (DP)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1735120739916&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

let index = 0;
const [N, M] = input[index++].split(' ').map(Number);
const ladderInfoList = input
  .slice(index, index + N)
  .map((info) =&amp;gt; info.split(' ').map(Number));
index += N;
const snakeInfoList = input
  .slice(-M)
  .map((info) =&amp;gt; info.split(' ').map(Number));

const MAX = 100;
const NORMAL = 'NORMAL';
const LADDER = 'LADDER';
const SNAKE = 'SNAKE';

const board = Array.from({ length: MAX + 1 }, () =&amp;gt; ({
  state: NORMAL,
  count: Infinity,
  next: 0,
}));

function solution() {
  initBoard();
  dp();

  console.log(board[100].count);
}

function initBoard() {
  ladderInfoList.forEach(
    ([x, y]) =&amp;gt; (board[x] = { state: LADDER, count: Infinity, next: y })
  );
  snakeInfoList.forEach(
    ([u, v]) =&amp;gt; (board[u] = { state: SNAKE, count: Infinity, next: v })
  );

  board[1].count = 0;

  for (let i = 2; i &amp;lt;= 7; i++) {
    const { state, next } = board[i];

    // 2~7까지는 한 번 굴려서 갈 수 있다.
    board[i].count = 1;

    // 만약 사다리가 설치되어있다면, 도착지점도 한 번으로 카운팅한다.
    if (state === LADDER) {
      board[next].count = 1;
    }
  }
}

function dp() {
  for (let i = 7; i &amp;lt;= 100; i++) {
    const { state: curState, next: curNext } = board[i];

    for (let j = i - 6; j &amp;lt; i; j++) {
      const { state: prevState, count: prevCount } = board[j];

      // 전의 칸에 아무것도 설치되어 있지 않을 경우,
      if (prevState === NORMAL) {
        board[i].count = Math.min(board[i].count, prevCount + 1);
      }
    }

    // 사다리가 설치되어 있는 경우,
    if (curState === LADDER) {
      board[curNext].count = board[i].count;
      // 뱀이 있는 경우,
    } else if (curState === SNAKE) {
      board[curNext].count = Math.min(board[curNext].count, board[i].count);
    }
  }
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;dp를 이용해서 문제를 풀었다. 다만, 여느 dp와 달리 '사다리'와 '뱀'이라는 조건에 따라 이동하게 되는 칸이 달라지기 때문에 구조가 약간 복잡하게 되었다. 하지만 테스트케이스는 다 맞았기 때문에 맞을 수 있을줄 알았다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;틀린 이유는 논리의 특정성에 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;위에서도 말했다시피, 특정 조건에 따라 이동하게 되는 칸이 달라지고 그에 따라 dp의 값이 달라지게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그 칸에 '사다리'나 '뱀'이 있다면 반드시 이동해야 하므로, 재귀적으로 확인&lt;/b&gt;해야 할 필요가 있다는 말이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그러므로,&lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt; &quot;전에 나왔던 dp값에 대해서 현재 값을 특정할 수 없다&quot;&lt;/span&gt; 라는 전제때문에 결국 dp로 값을 구할 수가 없다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;dp는 이동이 단순히 i -&amp;gt; i+1 식으로 연결되는 단순한 이동에 적합하고, &lt;span style=&quot;color: #8a3db6;&quot;&gt;이 문제는 최단 경로를 구하기 때문에 BFS가 더 적합한 풀이&lt;/span&gt;이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드 (BFS)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1735121045213&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

let index = 0;
const [N, M] = input[index++].split(' ').map(Number);
const ladderInfoList = input
  .slice(index, index + N)
  .map((info) =&amp;gt; info.split(' ').map(Number));
const snakeInfoList = input
  .slice(-M)
  .map((info) =&amp;gt; info.split(' ').map(Number));

const MAX = 100;
const board = Array.from({ length: MAX + 1 }, () =&amp;gt; 0);

function solution() {
  initBoard();
  const minMoveCount = getMinMoveCount();

  console.log(minMoveCount);
}

function initBoard() {
  ladderInfoList.forEach(([x, y]) =&amp;gt; (board[x] = y));
  snakeInfoList.forEach(([u, v]) =&amp;gt; (board[u] = v));
}

function getMinMoveCount() {
  // [현재 위치, 이동 횟수]
  const queue = [[1, 0]];
  const visited = Array.from({ length: MAX + 1 }, () =&amp;gt; false);

  visited[1] = true;

  while (queue.length &amp;gt; 0) {
    const [curNumber, curMoveCount] = queue.shift();

    if (curNumber === MAX) {
      return curMoveCount;
    }

    for (let dice = 1; dice &amp;lt;= 6; dice++) {
      let nextNumber = curNumber + dice;

      if (nextNumber &amp;gt; 100) {
        break;
      }

      // 만약 사다리나 뱀이 설치된 곳이라면,
      // 그것을 이용해서 갈 수 있는 다음칸으로 값을 갱신한다.
      if (board[nextNumber] !== 0) {
        nextNumber = board[nextNumber];
      }

      if (visited[nextNumber]) {
        continue;
      }

      visited[nextNumber] = true;
      queue.push([nextNumber, curMoveCount + 1]);
    }
  }
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;단순한 BFS로직을 이용했다. 단 한가지 추가된점이 있다면, BFS 내부에서&lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt; '사다리'나 '뱀'인 칸일 경우 그것을 이용해서 갈 수 있는 다음칸으로 값을 갱신&lt;/b&gt;&lt;/span&gt;한다는 것이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>16928번</category>
      <category>js</category>
      <category>그래프</category>
      <category>백준</category>
      <category>뱀과 사다리 게임</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/747</guid>
      <comments>https://jun-coding.tistory.com/747#entry747comment</comments>
      <pubDate>Wed, 25 Dec 2024 19:06:57 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 구현 / 18111번 / 마인크래프트 / JS</title>
      <link>https://jun-coding.tistory.com/746</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt; N&amp;times;M 크기의 땅을 모두 동일한 높이로 만드는데 필요한 최소 시간을 구하고, 그때의 땅의 높이를 출력하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;만약 최소 시간으로 가능한 경우가 여러가지 일 경우, 가장 높은 높이를 출력하면 된다.&lt;/span&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;조건&lt;/b&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&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;(i, j) 위치의 블록을 제거해 인벤토리에 넣는 작업: &lt;b&gt;2초 소요&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인벤토리에서 블록을 꺼내 (i, j) 위치에 쌓는 작업: &lt;b&gt;1초 소요&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;초기 인벤토리에 B개의 블록이 주어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;높이는 0~256 사이여야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= M(가로), N(세로) &amp;lt;= 500&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0 &amp;lt;= B(시작할 때 들어있는 블록의 개수) &amp;lt;= 6.4 * 10^7&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 (&lt;span style=&quot;color: #ee2323;&quot;&gt;시간 초과&lt;/span&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1734790668117&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M, B] = input.shift().split(' ');
const map = input.map((row) =&amp;gt; row.split(' ').map(Number));

function solution() {
  const min = Math.min(...map.flat());
  const max = Math.max(...map.flat());

  let minTime = Infinity;
  let maxHeight = -Infinity;

  for (let targetHeight = min; targetHeight &amp;lt;= max; targetHeight++) {
    let time = 0;
    let restBlock = B;

    for (let i = 0; i &amp;lt; N; i++) {
      for (let j = 0; j &amp;lt; M; j++) {
        const curHeight = map[i][j];

        if (curHeight &amp;gt; targetHeight) {
          const curRestBlock = curHeight - targetHeight;
          restBlock += curRestBlock;
          time += 2 * curRestBlock;
        } else if (curHeight &amp;lt; targetHeight) {
          const curLackBlock = targetHeight - curHeight;
          restBlock -= curLackBlock;
          time += 1 * curLackBlock;
        }
      }

      if (time &amp;gt; minTime) {
        break;
      }
    }

    if (restBlock &amp;lt; 0) {
      continue;
    }

    if (time &amp;lt;= minTime) {
      minTime = time;

      if (targetHeight &amp;gt; maxHeight) {
        maxHeight = targetHeight;
      }
    }
  }

  console.log(minTime, maxHeight);
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;문제 그대로 구현한 코드이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;답은 다 맞지만, 시간 복잡도가 O(H*N*M) 이므로 시간초과가 나게된다.&lt;/span&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1734790860566&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M, B] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split(' ').map(Number));
const MAX_HEIGHT = 256;

function solution() {
  const { minHeight, maxHeight, heightCountList } = calculateHeightData(map);
  const { minTime, optimalHeight } = findOptimalHeight(
    minHeight,
    maxHeight,
    heightCountList,
    B
  );

  console.log(minTime, optimalHeight);
}

/**
 * 각 높이의 출현 빈도와 최소/최대 높이를 계산하는 함수이다.
 *
 * @param {number[][]} map - N x M 크기의 맵 데이터
 * @returns {Object} - { minHeight, maxHeight, heightCountList }
 */
function calculateHeightData(map) {
  const heightCountList = Array.from({ length: MAX_HEIGHT + 1 }, () =&amp;gt; 0);
  let minHeight = Infinity;
  let maxHeight = -Infinity;

  map.forEach((row) =&amp;gt;
    row.forEach((height) =&amp;gt; {
      heightCountList[height]++;
      minHeight = Math.min(minHeight, height);
      maxHeight = Math.max(maxHeight, height);
    })
  );

  return { minHeight, maxHeight, heightCountList };
}

/**
 * 주어진 높이 범위에서 최적의 시간을 계산하고, 해당 높이를 반환하는 함수이다.
 *
 * @param {number} minHeight - 맵의 최소 높이
 * @param {number} maxHeight - 맵의 최대 높이
 * @param {number[]} heightCountList - 각 높이의 출현 빈도
 * @param {number} initialBlocks - 초기 블록 수
 * @returns {Object} - { minTime, optimalHeight }
 */
function findOptimalHeight(
  minHeight,
  maxHeight,
  heightCountList,
  initialBlocks
) {
  let minTime = Infinity;
  let optimalHeight = -Infinity;

  for (
    let targetHeight = minHeight;
    targetHeight &amp;lt;= maxHeight;
    targetHeight++
  ) {
    const { time, remainingBlocks } = calculateTimeAndBlocks(
      targetHeight,
      heightCountList,
      initialBlocks
    );

    if (remainingBlocks &amp;gt;= 0 &amp;amp;&amp;amp; time &amp;lt;= minTime) {
      minTime = time;
      if (targetHeight &amp;gt; optimalHeight) {
        optimalHeight = targetHeight;
      }
    }
  }

  return { minTime, optimalHeight };
}

/**
 * 특정 목표 높이에서 소요 시간과 남은 블록 수를 계산하는 함수이다.
 *
 * @param {number} targetHeight - 목표 높이
 * @param {number[]} heightCountList - 각 높이의 출현 빈도
 * @param {number} initialBlocks - 초기 블록 수
 * @returns {Object} - { time, remainingBlocks }
 */
function calculateTimeAndBlocks(targetHeight, heightCountList, initialBlocks) {
  let time = 0;
  let remainingBlocks = initialBlocks;

  heightCountList.forEach((count, height) =&amp;gt; {
    if (count === 0) return;

    if (height &amp;gt; targetHeight) {
      const removeBlocks = (height - targetHeight) * count;
      time += 2 * removeBlocks;
      remainingBlocks += removeBlocks;
    } else if (height &amp;lt; targetHeight) {
      const addBlocks = (targetHeight - height) * count;
      time += addBlocks;
      remainingBlocks -= addBlocks;
    }
  });

  return { time, remainingBlocks };
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;일단, 변수명과 문법적인 부분은 선언형 프로그래밍과 모듈화를 해보려고 시도해서 코드는 좀 길어졌다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그 외에도, flat() 함수로 최소 높이와 최대 높이를 구하던 부분도 따로 하지 않고 반복문 하나 안에서 해결했다.&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;font-family: 'Nanum Gothic';&quot;&gt;원래 사용하던 로직은 크게 달라진 부분이 없다. 단지 시간을 개선하기 위해 값을 미리 저장하는 방법을 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;어떤 값을 저장하냐면, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;기존 맵에서 각 높이의 출현 빈도를 배열에 저장&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;기존에는 모든 배열을 직접 순회하면서 각 높이마다 얼마나 블록을 더하고 빼야하는지 계산했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이런 방식을 하게 되면 같은 높이에 대해 얼마나 더하고 뺄건지는 고정 값이므로, &lt;b&gt;(높이의 차이 * 해당 높이의 개수)&lt;/b&gt;로 한번에 처리할 수 있다. 이렇게 되면 &lt;b&gt;중복된 값에 대한 계산이 줄고 반복이 줄게 되므로 시간이 단축된다.&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;font-family: 'Nanum Gothic';&quot;&gt;반복에서 나오지 않은 높이부분은 continue로 반복을 생략하게 되는데, 이런 부분을 넣고싶지 않다면 Map 자료구조를 사용해도 좋을 것 같다는 생각이 든다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>18111번</category>
      <category>js</category>
      <category>구현</category>
      <category>마인크래프트</category>
      <category>백준</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/746</guid>
      <comments>https://jun-coding.tistory.com/746#entry746comment</comments>
      <pubDate>Sat, 21 Dec 2024 23:30:56 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 문자열 / 5525번 / IOIOI / JS</title>
      <link>https://jun-coding.tistory.com/745</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;N+1개의 I와 N개의 O로 이루어져 있으면, I와 O가 교대로 나오는 문자열을 P_N이라고 한다.&lt;br /&gt;I와&amp;nbsp;O로만&amp;nbsp;이루어진&amp;nbsp;문자열&amp;nbsp;S와&amp;nbsp;정수&amp;nbsp;N이&amp;nbsp;주어졌을&amp;nbsp;때,&amp;nbsp;S안에&amp;nbsp;P_N이&amp;nbsp;몇&amp;nbsp;군데&amp;nbsp;포함되어&amp;nbsp;있는지&amp;nbsp;구하는&amp;nbsp;프로그램을&amp;nbsp;작성하시오.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;lt;= N &amp;lt;= 1,000,000&lt;/li&gt;
&lt;li&gt;2N+1 &amp;lt;= M &amp;lt;= 1,000,000&lt;/li&gt;
&lt;li&gt;S는 I와 O로만 이루어져 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731316401326&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const N = +input.shift();
const M = +input.shift();
const S = input.shift();

function solution() {
    let count = 0;                // 'IOI' 패턴을 찾은 횟수
    let result = 0;               // 원하는 패턴을 찾은 횟수
    let i = 0;
    
    while (i &amp;lt; M - 1) {
      if (S[i] === 'I' &amp;amp;&amp;amp; S.slice(i, i + 3) === 'IOI') {  // 'IOI' 패턴 찾기
        count += 1;               // 'IOI' 패턴이 연속되는 수를 세기
        if (count &amp;gt;= N) {
          result += 1;            // 'IOI'가 N번 이상 연속되면 패턴을 찾은 것으로 간주
        }
        i += 2;                   // 'IOI' 패턴을 찾으면 두 칸 이동
      } else {
        count = 0;                // 패턴이 끊기면 count 초기화
        i += 1;
      }
    }
    
    console.log(result);
}

solution();&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/백준</category>
      <category>5525번</category>
      <category>IOIOI</category>
      <category>js</category>
      <category>문자열</category>
      <category>백준</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/745</guid>
      <comments>https://jun-coding.tistory.com/745#entry745comment</comments>
      <pubDate>Sat, 9 Nov 2024 22:49:53 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 구현 / 5430번 / AC / JS</title>
      <link>https://jun-coding.tistory.com/744</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;숫자 배열이 주어진다. 명령어는 R과 D가 주어지는데 R은 배열 뒤집기, D는 배열의 맨 앞에서 하나를 제거하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;T &amp;lt;= 100&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= p.length &amp;lt;= 100,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;0 &amp;lt;= n &amp;lt;= 100,000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= 배열의 각 정수 &amp;lt;= 100&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;p.length + n &amp;lt;= 700,000&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 (메모리 초과)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1731049775174&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const T = +input.shift();

function solution() {
  const result = [];

  for (let testCase = 1; testCase &amp;lt;= T; testCase++) {
    const p = input.shift();
    const n = +input.shift();

    let numberList = input.shift().match(/\d+/g) || [];
    numberList = numberList.map(Number);

    for (const command of p) {
      if (command === 'R') {
        numberList = reverse(numberList);
      } else if (command === 'D') {
        numberList = deleteFirstNumber(numberList);

        if (numberList === 'error') {
          break;
        }
      }
    }

    result.push(numberList);
  }

  console.log(
    result.map((el) =&amp;gt; (el !== 'error' ? JSON.stringify(el) : el)).join('\n')
  );
}

function reverse(numberList) {
  return [...numberList].reverse();
}

function deleteFirstNumber(numberList) {
  if (numberList.length === 0) {
    return 'error';
  }

  const [_, ...newArray] = numberList;

  return newArray;
}

solution();&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;로직은 크게 문제가 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 메모리 초과가 나온 이유는, reverse()와 deleteFirstNumber() 함수 구현에 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;원본 배열을 수정하지 않기 위해 인자로 받고 전개 연산자로 깊은 복사를 통해 새로운 배열을 만들어주고, 그 배열을 조작해서 반환해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;실패 코드 (시간 초과)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1731049790646&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

let index = 0;
const T = +input[index++];

function solution() {
  const result = [];

  for (let testCase = 1; testCase &amp;lt;= T; testCase++) {
    const p = input[index++];
    const n = +input[index++];

    let numberList = JSON.parse(input[index++]).map(Number);

    for (const command of p) {
      if (command === 'R') {
        numberList.reverse();
      } else if (command === 'D') {
        if (numberList.length === 0) {
          numberList = 'error';
          break;
        }
        numberList = numberList.slice(1);
      }
    }

    result.push(numberList);
  }

  console.log(
    result.map((el) =&amp;gt; (el !== 'error' ? JSON.stringify(el) : el)).join('\n')
  );
}

solution();&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;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;처음에는 시간 초과가 shift() 메소드 때문에 나는 줄 알았다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;그래서 input의 각 값을 shift()를 통해 얻어오는 대신, 인덱스 변수를 두고 참조하게 하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;하지만 그래도 시간 초과가 났다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;물론 위에서 생각한 input의 값을 가져오는 부분에서의 shift() 연산의 영향이 아예 없지는 않겠지만, 결정적 문제는 다른 곳에 있었다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1731049074703&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

let index = 0;
const T = +input[index++];

function solution() {
  const result = [];

  for (let testCase = 1; testCase &amp;lt;= T; testCase++) {
    const p = input[index++];
    const n = +input[index++];

    let numberList = JSON.parse(input[index++]).map(Number);

    let isReversed = false;
    let isError = false;

    for (const command of p) {
      if (command === 'R') {
        isReversed = !isReversed;
      } else if (command === 'D') {
        if (numberList.length === 0) {
          isError = true;
          break;
        }

        // 만약 뒤집힌 상태라면, 뒤집지 않고 뒤에서 하나 제거한다.
        if (isReversed) {
          numberList.pop();
        } else {
          // 뒤집힌 상태가 아니라면 앞에서 하나 제거한다.
          numberList.shift();
        }
      }
    }

    // 뒤집힌 상태이고, 에러가 나지 않았다면 뒤집어준다.
    if (isReversed &amp;amp;&amp;amp; !isError) {
      numberList.reverse();
    }
    if (isError) {
      result.push('error');
    } else {
      result.push(numberList);
    }
  }

  // 배열을 그대로 출력하게 되면 양쪽 괄호([])가 보이지 않기 때문에 객체 자체를 문자열로 바꿔준다.
  console.log(
    result.map((el) =&amp;gt; (el !== 'error' ? JSON.stringify(el) : el)).join('\n')
  );
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;아무래도 확실한 것은 수많은 shift()와 reverse()의 사용이 분명했다.&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: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;shift()는 O(n)의 시간 복잡도를 가진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;reverse() 또한 O(n)의 시간 복잡도를 가진다.&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;font-family: 'Nanum Gothic';&quot;&gt;모든 명령마다 이 두 메소드를 호출하기 때문에 시간 복잡도가 커졌던 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;따라서 이 배열을 뒤집어야 하는지, 에러가 발생하는지에 대한 플래그 변수인 isReversed와 isError 변수를 두었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;'R' 명령이 들어왔다고 해서 바로 뒤집지 말고, 뒤집어야 하는지 일단 변수를 조작한다. isReversed를 true로 만들면 된다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그리고 나서 'D' 명령이 이어서 들어온다면 앞에서 shift() 하는 것이 아닌, 뒤에서 pop()을 한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #8a3db6; font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;pop()은 시간 복잡도가 O(1)이기 때문이다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;그리고 마지막에 isReversed의 true 여부에 따라 뒤집기를 딱 한 번만 수행하면 된다.&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;font-family: 'Nanum Gothic';&quot;&gt;각 명령마다 reverse()나 shift()를 했던 것과 달리 확실히 시간 복잡도를 줄여서 통과할 수 있었다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>5430번</category>
      <category>AC</category>
      <category>js</category>
      <category>구현</category>
      <category>백준</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/744</guid>
      <comments>https://jun-coding.tistory.com/744#entry744comment</comments>
      <pubDate>Fri, 8 Nov 2024 16:11:07 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 그래프 / 1389번 / 케빈 베이컨의 6단계 법칙 / JS</title>
      <link>https://jun-coding.tistory.com/743</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;이 문제는 두 사람이 몇 단계 이내에 친구의 친구로 이어질 수 있는지를 나타내는 &lt;b&gt;케빈 베이컨의 수&lt;/b&gt;를 계산하고, 케빈 베이컨의 수가 가장 작은 사람을 찾는 문제입니다. 각 사람마다 다른 모든 사람들과 최소 단계로 이어지는 경로를 구한 뒤, 그 경로의 단계 수를 모두 더하여 &lt;b&gt;케빈 베이컨의 수&lt;/b&gt;를 계산합니다. 예를 들어, 사람 A와 B가 최소 3단계로 연결된다면, A의 케빈 베이컨 수에는 3이 포함됩니다. 모든 유저의 케빈 베이컨 수를 계산한 뒤, 그 값이 가장 작은 사람을 찾는 것이 문제의 목표입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;2 &amp;lt;= N &amp;lt;= 100&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;1 &amp;lt;= M &amp;lt;= 5000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;입력 관계:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;입력은 각 친구 관계를 나타내며, (A, B) 형식으로 주어집니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;중복된 친구 관계가 존재할 수 있으며, 자기 자신과 친구인 관계는 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;모든 사람은 친구 관계로 이어져 있으며, 단절된 그룹은 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1730983590992&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [N, M] = input.shift().split(' ').map(Number);
const relationList = input.map((row) =&amp;gt; row.split(' ').map(Number));

// 인접 행렬
const adjList = {};
// 케빈 베이컨 카운트 인접 행렬
const kevinBaconCountAdjList = Array.from({ length: N + 1 }, () =&amp;gt;
  new Array(N + 1).fill(0)
);

function solution() {
  initAdjList();

  const kevinBaconCountList = getKevinBaconCountList();
  const result = getResult(kevinBaconCountList);

  console.log(result);
}

/**
 * 인접행렬을 초기화 해주는 함수이다.
 */
function initAdjList() {
  for (let i = 1; i &amp;lt;= N; i++) {
    adjList[i] = new Set();
  }

  for (const [user1, user2] of relationList) {
    adjList[user1].add(user2);
    adjList[user2].add(user1);
  }
}

/**
 * bfs를 이용해 각 노드까지의 단계를 구하는 함수이다.
 *
 * @param {number} start 시작 노드
 */
function bfs(start) {
  const queue = [[start, 1]];
  const visited = Array.from({ length: N + 1 }, () =&amp;gt; false);

  visited[start] = true;

  while (queue.length &amp;gt; 0) {
    const [curUser, curCount] = queue.shift();

    for (const adjUser of adjList[curUser]) {
      if (visited[adjUser]) {
        continue;
      }

      kevinBaconCountAdjList[curUser][adjUser] = 1;
      kevinBaconCountAdjList[start][adjUser] = curCount;

      visited[adjUser] = true;
      queue.push([adjUser, curCount + 1]);
    }
  }
}

/**
 * 각 유저별 케빈 베이컨수를 구하는 함수이다.
 *
 * @returns 각 유저별 케빈 베이컨수가 담긴 배열
 */
function getKevinBaconCountList() {
  for (let i = 1; i &amp;lt;= N; i++) {
    bfs(i);
  }

  const kevinBaconCountList = kevinBaconCountAdjList.map((row) =&amp;gt;
    row.reduce((acc, cur) =&amp;gt; acc + cur)
  );

  return kevinBaconCountList;
}

/**
 * 케빈 베이컨의 수가 가장 작은 사람을 구하는 함수이다.
 *
 * @param {number[]} kevinBaconCountList
 * @returns 케빈 베이커의 수가 가장 작은 사람
 */
function getResult(kevinBaconCountList) {
  const min = Math.min(...kevinBaconCountList.slice(1));
  const minIndex = kevinBaconCountList.indexOf(min);

  return minIndex;
}

solution();&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;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;인접 리스트를 이용해 문제에서 요구한 그대로 bfs로 구현하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;주의할 점은, &lt;b&gt;중복된 관계도 들어올 수 있기 때문에 Set 자료구조를 사용&lt;/b&gt;했다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>1389번</category>
      <category>js</category>
      <category>그래프</category>
      <category>백준</category>
      <category>오블완</category>
      <category>케빈 베이컨의 6단계 법칙</category>
      <category>티스토리챌린지</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/743</guid>
      <comments>https://jun-coding.tistory.com/743#entry743comment</comments>
      <pubDate>Thu, 7 Nov 2024 21:48:19 +0900</pubDate>
    </item>
    <item>
      <title>백준 / 그래프 / 14940번 / 쉬운 최단거리 / JS</title>
      <link>https://jun-coding.tistory.com/742</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;문제 간단설명&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;지도가 주어지면, 각 칸에서 목표지점까지의 거리를 출력하는 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오직 가로와 세로로만 움직여 갈 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;제한 사항&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2 &amp;lt;= n &amp;lt;= 1000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2 &amp;lt;= m &amp;lt;= 1000&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;0은 갈 수 없는 땅이고 1은 갈 수 있는 땅, 2는 목표지점이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;입력에서 2는 단 한개이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;실패 코드 (시간초과)&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1730902582234&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [n, m] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split(' ').map(Number));

const IMPOSSIBLE = 0;
const POSSIBLE = 1;
const GOAL = 2;

const dr = [-1, 1, 0, 0];
const dc = [0, 0, -1, 1];

function solution() {
  const resultMap = Array.from({ length: n }, () =&amp;gt; new Array(m));

  for (let i = 0; i &amp;lt; n; i++) {
    for (let j = 0; j &amp;lt; m; j++) {
      if (map[i][j] === IMPOSSIBLE || map[i][j] === GOAL) {
        resultMap[i][j] = 0;
        continue;
      }

      resultMap[i][j] = bfs(i, j);
    }
  }

  printResultMap(resultMap);
}

function bfs(startRow, startCol) {
  const queue = [[startRow, startCol, 0]];
  const visited = Array.from({ length: n }, () =&amp;gt; new Array(m).fill(false));

  visited[startRow][startCol] = true;

  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curCount] = queue.shift();

    if (map[curRow][curCol] === GOAL) {
      return curCount;
    }

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      if (!isValid(nr, nc)) {
        continue;
      }
      if (visited[nr][nc]) {
        continue;
      }
      if (map[nr][nc] === IMPOSSIBLE) {
        continue;
      }

      visited[nr][nc] = true;
      queue.push([nr, nc, curCount + 1]);
    }
  }
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; n &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; m;
}

function printResultMap(resultMap) {
  console.log(resultMap.map((row) =&amp;gt; row.join(' ')).join('\n'));
}

solution();&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;먼저 그냥 문제 그대로 구현해보았다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;각 칸에서 목표지점까지 bfs로 얼마나 걸리는지 판단하게 했더니 시간초과가 났다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;최대 1000 * 1000의 배열이기 때문에 시간초과&lt;/b&gt;가 걸리는 것은 당연한 풀이이다...&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;성공 코드&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1730902702486&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const fs = require('fs');
const filePath = process.platform === 'linux' ? '/dev/stdin' : '../input.txt';
// const filePath = process.platform === 'linux' ? '/dev/stdin' : 'BOJ/input.txt';
const input = fs
  .readFileSync(filePath)
  .toString()
  .trim()
  .split('\n')
  .map((el) =&amp;gt; el.trim());

const [n, m] = input.shift().split(' ').map(Number);
const map = input.map((row) =&amp;gt; row.split(' ').map(Number));

const IMPOSSIBLE = 0;
const POSSIBLE = 1;
const GOAL = 2;

const dr = [-1, 1, 0, 0];
const dc = [0, 0, -1, 1];

const resultMap = Array.from({ length: n }, () =&amp;gt; new Array(m).fill(-1));

function solution() {
  let [startRow, startCol] = getStartPosition();

  checkImpossible();
  bfs(startRow, startCol);
  printResultMap();
}

function getStartPosition() {
  for (let i = 0; i &amp;lt; n; i++) {
    for (let j = 0; j &amp;lt; m; j++) {
      if (map[i][j] === GOAL) {
        resultMap[i][j] = 0;
        return [i, j];
      }
    }
  }
}

function checkImpossible() {
  for (let i = 0; i &amp;lt; n; i++) {
    for (let j = 0; j &amp;lt; m; j++) {
      if (map[i][j] === IMPOSSIBLE) {
        resultMap[i][j] = 0;
      }
    }
  }
}

function bfs(startRow, startCol) {
  const queue = [[startRow, startCol, 0]];
  const visited = Array.from({ length: n }, () =&amp;gt; new Array(m).fill(false));

  visited[startRow][startCol] = true;

  while (queue.length &amp;gt; 0) {
    const [curRow, curCol, curCount] = queue.shift();

    for (let d = 0; d &amp;lt; 4; d++) {
      const nr = curRow + dr[d];
      const nc = curCol + dc[d];

      if (!isValid(nr, nc)) {
        continue;
      }
      if (visited[nr][nc]) {
        continue;
      }
      if (map[nr][nc] === IMPOSSIBLE || map[nr][nc] === GOAL) {
        continue;
      }

      visited[nr][nc] = true;
      queue.push([nr, nc, curCount + 1]);
      resultMap[nr][nc] = curCount + 1;
    }
  }
}

function isValid(row, col) {
  return 0 &amp;lt;= row &amp;amp;&amp;amp; row &amp;lt; n &amp;amp;&amp;amp; 0 &amp;lt;= col &amp;amp;&amp;amp; col &amp;lt; m;
}

function printResultMap() {
  console.log(resultMap.map((row) =&amp;gt; row.join(' ')).join('\n'));
}

solution();&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;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반대로 생각해서 각 칸에서 목표지점까지 가는 것을 생각하지 말고, &lt;span style=&quot;color: #8a3db6;&quot;&gt;&lt;b&gt;목표지점에서 각 칸까지 얼마나 걸리는지 구한다&lt;/b&gt;&lt;/span&gt;고 생각해보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그렇다면 &lt;b&gt;시작지점을 목표지점으로 잡고&lt;/b&gt;, 가로와 세로로 퍼져나가면서 각 칸에 대해서 이동거리를 표시해주면 &lt;b&gt;&lt;span style=&quot;color: #8a3db6;&quot;&gt;한번의 bfs&lt;/span&gt;로 문제를 해결&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>PS/백준</category>
      <category>14940번</category>
      <category>js</category>
      <category>그래프</category>
      <category>백준</category>
      <category>쉬운 최단거리</category>
      <author>KimMinJun</author>
      <guid isPermaLink="true">https://jun-coding.tistory.com/742</guid>
      <comments>https://jun-coding.tistory.com/742#entry742comment</comments>
      <pubDate>Wed, 6 Nov 2024 23:21:04 +0900</pubDate>
    </item>
  </channel>
</rss>