<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자 정현민</title>
    <link>https://hyunmindev.tistory.com/</link>
    <description>개발 일지</description>
    <language>ko</language>
    <pubDate>Mon, 11 May 2026 03:41:57 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hyunmin!</managingEditor>
    <image>
      <title>개발자 정현민</title>
      <url>https://tistory1.daumcdn.net/tistory/4135340/attach/488c0c268d164cdfb0f8a44ac5bffa2f</url>
      <link>https://hyunmindev.tistory.com</link>
    </image>
    <item>
      <title>react-query staleTime vs cacheTime</title>
      <link>https://hyunmindev.tistory.com/26</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blog-thumbnail_22.09.18.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rnRYE/btrMnnOBhlL/ZyuaVOsRcbiaCMuzTEDp11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rnRYE/btrMnnOBhlL/ZyuaVOsRcbiaCMuzTEDp11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rnRYE/btrMnnOBhlL/ZyuaVOsRcbiaCMuzTEDp11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrnRYE%2FbtrMnnOBhlL%2FZyuaVOsRcbiaCMuzTEDp11%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; alt=&quot;react-query staleTime vs cacheTime thumbnail&quot; loading=&quot;lazy&quot; width=&quot;368&quot; height=&quot;207&quot; data-filename=&quot;blog-thumbnail_22.09.18.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 tanstack사의 react-query가 버전 4를 정식 릴리즈 했다. 그리고 공식 이름을 tanstack-query로 변경하고 하위 패키지로 react-query를 제공한다. 이름을 변경한 이유는 react-query v4부터 react 뿐만 아니라 vue, solid, svelte도 지원하기 때문이 아닐까 추측해본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사에서 진행하는 프로젝트에 활발하게 react-query를 도입 중이다. react-query에는 비슷하지만 다른, 헷갈리는 개념들이 몇 개 있다. isFetching과 isLoading, staleTime과 cacheTime이 그러하다. 이번 글은 &lt;b&gt;staleTime과 cacheTime의 개념과 차이점&lt;/b&gt;을 정리한 내용이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;staleTime&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;stale&lt;/b&gt;의 뜻은 &lt;b&gt;&quot;신선하지 않은&quot;&lt;/b&gt;이다. 구체적인 사례를 들어 설명하겠다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;아이유 콘서트 티켓팅이 4시부터 시작되고 있다. 이번 기회에는 꼭 콘서트를 보고야 말겠다고 다짐한 현미는 운이 좋게 4시 0분 0초에 티켓팅 좌석 선택 페이지로 접근했다. 명당자리가 비어있는 것을 확인한 현미는 좌석을 선택하고 결제하기 버튼을 누른다. 결제 페이지로 이동하는 순간 &quot;해당 좌석은 예매가 완료되었습니다.&quot;라는 문구를 보고 좌절한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사례에서 &lt;b&gt;16:00:00&lt;/b&gt;에 좌석이 비어있다는 정보를 서버로부터 받아와서 현미에게 보여주었지만, 현미가 결제 페이지로 이동하는 순간인 &lt;b&gt;16:00:04&lt;/b&gt;에는 그 정보가 신선하지 않은 상한 정보였다. 즉, 현미가 처음 서버로부터 가져왔던 빈 좌석 정보는 stale 상태가 되었다. 일반적으로 서버와 클라이언트의 데이터 주고받음은 양방향 통신이 아니기 때문에 위와 같은 사례는 무수히 경험해보았을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이러한 상황을 피하고자 react-query는 서버로부터 응답받는 데이터를 &lt;b&gt;서버 상태&lt;/b&gt;라 정의하고, 이를 정확한 데이터 즉, 신선한 데이터로 동기화해주는 작업을 추상도 높게 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 특정 상황에 상한 데이터를 자동으로 신선한 데이터로 동기화를 하는 경우도 있다. 그 경우는 다음 세 가지이고, 충분히 데이터가 상했음을 의심할 수 있는 시점이라고 생각된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(쿼리 훅이 포함된) 컴포넌트가 마운트 됐을 때&lt;/li&gt;
&lt;li&gt;네트워크가 다시 연결됐을 때&lt;/li&gt;
&lt;li&gt;브라우저가 focus 됐을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞선 내용을 요약하자면 서버 상태는 신선한 상태 또는 상한 상태로 분류된다. 그리고 &lt;b&gt;staleTime&lt;/b&gt;은 &lt;b&gt;데이터의 신선한 상태가 유지되는 시간,&lt;/b&gt; 다시 말해 상하기까지의 시간이다. staleTime 타이머가 시작되는 시점은 서버 상태가 성공적으로 클라이언트에 도착한 시점이다. 그리고 신선한 상태를 유지하다가 지정한 staleTime이 지나면 stale 상태가 된다.&lt;br /&gt;아무 값을 지정하지 않는다면 기본값인 0(suspense: true 옵션을 사용할 경우 1)으로 설정된다. 이 말은 기본적으로 데이터는 가져온 즉시 상한다는 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신선한 상태이지만, 데이터를 강제로 다시 가져오기 위한 방법은 &lt;a href=&quot;https://tanstack.com/query/v4/docs/reference/QueryClient#queryclientinvalidatequeries&quot;&gt;invalidateQuries&lt;/a&gt;, &lt;a href=&quot;https://tanstack.com/query/v4/docs/reference/useQuery&quot;&gt;refetch&lt;/a&gt; 두 가지밖에 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;staleTime은 어떻게 설정하냐에 따라 중복 요청이 발생할 수도 안 할 수도 있는 중요한 옵션이다. react-query의 중복 요청에 관련된 내용은 아래 글을 참고 바란다.&lt;/p&gt;
&lt;figure id=&quot;og_1664101458654&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;react-query props drilling 피하기&quot; data-og-description=&quot;react-query는 상태 관리 도구이다. 상태 관리 도구를 사용하는 이유 중 큰 부분을 차지하는 것이 props-drilling을 피하기 위해서일 것이다. 이 포스트는 react-query를 사용할 때 props drilling을 피하기 위&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://hyunmindev.tistory.com/25&quot; data-og-url=&quot;https://blog.hyunmin.dev/25&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bvyWLi/hyPVnJIONe/FLAcCkb5Ek33XJl6gIiEJK/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/c1gY8I/hyPTXslF87/qeuAZnidKyBlkMAby3Kic0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/x36jp/hyPT7aDLN9/wqteUV9HmXkJauGejesXxK/img.png?width=790&amp;amp;height=466&amp;amp;face=0_0_790_466&quot;&gt;&lt;a href=&quot;https://hyunmindev.tistory.com/25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hyunmindev.tistory.com/25&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bvyWLi/hyPVnJIONe/FLAcCkb5Ek33XJl6gIiEJK/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/c1gY8I/hyPTXslF87/qeuAZnidKyBlkMAby3Kic0/img.png?width=800&amp;amp;height=449&amp;amp;face=0_0_800_449,https://scrap.kakaocdn.net/dn/x36jp/hyPT7aDLN9/wqteUV9HmXkJauGejesXxK/img.png?width=790&amp;amp;height=466&amp;amp;face=0_0_790_466');&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;react-query props drilling 피하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;react-query는 상태 관리 도구이다. 상태 관리 도구를 사용하는 이유 중 큰 부분을 차지하는 것이 props-drilling을 피하기 위해서일 것이다. 이 포스트는 react-query를 사용할 때 props drilling을 피하기 위&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;staleTime이 작동되는 메커니즘을 도식화하면 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2022-09-18 at 23.35.06.png&quot; data-origin-width=&quot;2372&quot; data-origin-height=&quot;896&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nQEuN/btrMkN2cJ3L/76upOK25dj7mGdoGQZjHS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nQEuN/btrMkN2cJ3L/76upOK25dj7mGdoGQZjHS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nQEuN/btrMkN2cJ3L/76upOK25dj7mGdoGQZjHS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnQEuN%2FbtrMkN2cJ3L%2F76upOK25dj7mGdoGQZjHS0%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; alt=&quot;리액트 쿼리 staleTime 흐름&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;257&quot; data-filename=&quot;Screen Shot 2022-09-18 at 23.35.06.png&quot; data-origin-width=&quot;2372&quot; data-origin-height=&quot;896&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;cacheTime&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cache라는 단어는 stale보다 상대적으로 친숙할 것이다. 개인적인 견해로, 일반적으로 사용되는 cache의 의미와 미세한 차이가 있고, 그래서 생기는 혼동이 있다고 생각된다. (request의 발생 여부와 전혀 연관이 있지 않다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;쿼리가 inactive 상태가 되면 cacheTime 동안 메모리에 존재하다가 가비지로 수집되어 제거된다.&lt;/b&gt; inactive 상태는 해당 쿼리 훅을 사용하는 모든 컴포넌트가 언마운트 되었다는 의미이다. cacheTime 내에 쿼리가 마운트 되면 react-query 캐시 저장소에 있던 값을 우선 반환한다. 그리고 이렇게 캐시 hit을 하더라도 재요청의 여부는 staleTime에 의해 결정된다.&lt;br /&gt;데이터를 서버로부터 가져온 시점부터 타이머를 시작하는 staleTime과 다르게 cacheTime은 inactive 상태가 되면 타이머를 시작한다. 그리고 staleTime의 기본값은 0이지만, cacheTime의 가본 값은 300,000(5분)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;staleTime이 0이라면 각 쿼리를 마운트마다 요청이 발생하기 때문에 캐시 데이터는 그저 placeholder의 역할밖에 하지 않는다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;흐름&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-query의 흐름을 간단하게 나타내면 다음 그림과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2022-09-25 at 18.47.38.png&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;1640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yFOro/btrMU6Uapiu/556jPWQUdK8LPzEdVO3D21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yFOro/btrMU6Uapiu/556jPWQUdK8LPzEdVO3D21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yFOro/btrMU6Uapiu/556jPWQUdK8LPzEdVO3D21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyFOro%2FbtrMU6Uapiu%2F556jPWQUdK8LPzEdVO3D21%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; alt=&quot;리액트 쿼리 흐름&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;520&quot; data-filename=&quot;Screen Shot 2022-09-25 at 18.47.38.png&quot; data-origin-width=&quot;2086&quot; data-origin-height=&quot;1640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상황 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 react-query 도큐먼트에서 나온 캐싱 예시이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 쿼리 인스턴스 &lt;code&gt;useQuery(\['todos'\], fetchTodos)&lt;/code&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;code&gt;\['todos'\]&lt;/code&gt;와 &lt;code&gt;fetchTodos&lt;/code&gt;를 고유 식별자로 데이터를 캐시 한다.&lt;/li&gt;
&lt;li&gt;쿼리 훅은 설정한 staleTime(기본값 0, 즉시) 이후에 상한 쿼리가 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useQuery(\['todos'\], fetchTodos)&lt;/code&gt;의 두 번째 인스턴스가 다른 위치에 마운트 된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 데이터는 이 쿼리의 첫 번째 인스턴스의 캐시 저장소에 존재하므로 해당 데이터는 캐시 저장소에서 즉시 반환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;새 인스턴스가 화면에 나타나기 때문에 두 쿼리 모두에 대해(단 하나의 요청만) 백그라운드 refetch가 트리거 된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답(fetch)이 성공하면 두 인스턴스 모두 새로운 데이터로 업데이트한다.(rerender)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useQuery(\['todos'\], fetchTodos)&lt;/code&gt; 쿼리의 두 인스턴스가 모두 마운트 해제되어 더 이상 사용되지 않는다. (inactive)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 쿼리의 active 인스턴스가 더 이상 없으므로 쿼리를 삭제하고 가비지 수집하기 위해 캐시 timeout이 cacheTime으로 설정된다. (기본값 5분).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;캐시 timeout이 완료되기 전에 다른 &lt;code&gt;useQuery(\['todos'\], fetchTodos)&lt;/code&gt;가 마운트 된다. 쿼리는 백그라운드에서 fetchTodos 함수를 실행하여 쿼리를 신선한 값으로 동기화하는 동안 사용 가능한 캐시 된 값을 즉시 반환합니다.&lt;/li&gt;
&lt;li&gt;마지막 useQuery(['todos'], fetchTodos)` 인스턴스가 언마운트 된다.&lt;/li&gt;
&lt;li&gt;5분 이내에 &lt;code&gt;useQuery('todos', fetchTodos)&lt;/code&gt; 쿼리 인스턴스가 더 이상 나타나지 않는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 쿼리와 해당 데이터는 삭제되고 가비지 수집된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;추천 및 주의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;staleTime을 cacheTime보다 크게 설정하는 것은 의미가 없을 수 있다.&lt;/b&gt; &lt;code&gt;staleTime = cacheTime&lt;/code&gt; 과 &lt;code&gt;staleTime &amp;gt; cacheTime&lt;/code&gt; 은 정확하게 같게 동작할 확률이 크다. 그 이유는, 캐시 값이 만료되면 신선함, 상함에 상관없이 가져올 데이터가 없기 때문이다. 즉, 캐시 값이 만료되면 무조건 요청이 발생한다.&lt;br /&gt;(자세한 설명은 다른 포스트에서 작성하겠습니다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cacheTime은 특정 값의 만료와 관련이 있고, staleTime은 특정 쿼리의 만료와 관련이 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tkdodo.eu/blog/practical-react-query#the-defaults-explained&quot;&gt;https://tkdodo.eu/blog/practical-react-query#the-defaults-explained&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/doctolib/react-query-cachetime-vs-staletime-ec74defc483e&quot;&gt;https://medium.com/doctolib/react-query-cachetime-vs-staletime-ec74defc483e&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/TanStack/query&quot;&gt;https://github.com/TanStack/query&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react-query-v3.tanstack.com/guides/caching&quot;&gt;https://react-query-v3.tanstack.com/guides/caching&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/React</category>
      <category>REACT</category>
      <category>react-query</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/26</guid>
      <comments>https://hyunmindev.tistory.com/26#entry26comment</comments>
      <pubDate>Sun, 18 Sep 2022 01:01:22 +0900</pubDate>
    </item>
    <item>
      <title>react-query props drilling 피하기</title>
      <link>https://hyunmindev.tistory.com/25</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LNmWP/btrM0mIzhSo/clHhXXwaEZqGNsOm4lLA00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LNmWP/btrM0mIzhSo/clHhXXwaEZqGNsOm4lLA00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LNmWP/btrM0mIzhSo/clHhXXwaEZqGNsOm4lLA00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLNmWP%2FbtrM0mIzhSo%2FclHhXXwaEZqGNsOm4lLA00%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;609&quot; height=&quot;342&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;r&lt;i&gt;eact-query&lt;/i&gt;는 &lt;b&gt;상태 관리 도구&lt;/b&gt;이다. 상태 관리 도구를 사용하는 이유 중 큰 부분을 차지하는 것이 props-drilling을 피하기 위해서일 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 포스트는 &lt;i&gt;react-query&lt;/i&gt;를 사용할 때 props drilling을 피하기 위해 고민했던 내용을 다룬다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;942&quot;&gt;&lt;span data-url=&quot;https://camo.githubusercontent.com/7d167f2a2d7d724d06ca36427ea80bfe7654fe49e7d79769ba010cbd6db4e22b/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f313630302f312a3837644a35454233796444375f4162684b6234554f512e706e67&quot; data-phocus=&quot;https://camo.githubusercontent.com/7d167f2a2d7d724d06ca36427ea80bfe7654fe49e7d79769ba010cbd6db4e22b/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f313630302f312a3837644a35454233796444375f4162684b6234554f512e706e67&quot; data-alt=&quot;상태 관리 도구(redux) 의 이점&quot;&gt;&lt;img src=&quot;https://camo.githubusercontent.com/7d167f2a2d7d724d06ca36427ea80bfe7654fe49e7d79769ba010cbd6db4e22b/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f313630302f312a3837644a35454233796444375f4162684b6234554f512e706e67&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fcamo.githubusercontent.com%2F7d167f2a2d7d724d06ca36427ea80bfe7654fe49e7d79769ba010cbd6db4e22b%2F68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f313630302f312a3837644a35454233796444375f4162684b6234554f512e706e67&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; alt=&quot;상태 관리 도구를 사용하는 이유&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;353&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;942&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;상태 관리 도구(redux) 의 이점&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버에 부담 주지 않기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;react-query&lt;/i&gt;는 동일 키의 쿼리를 동시에 여러 개 요청하면 내부적으로 하나의 요청으로 만든다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;export default function App() {
  const { data: posts1 } = useQuery(['posts'], fetchPosts);
  const { data: posts2 } = useQuery(['posts'], fetchPosts);
  const { data: posts3 } = useQuery(['posts'], fetchPosts);
  // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다소 비현실적인 예시로 user 리스트를 fetch 하는 훅을 3개 사용했다고 가정한다. 하지만 이 훅의 쿼리키는 모두 &lt;code&gt;[&quot;users&quot;]&lt;/code&gt; 로 같다. 세 번의 요청이 발생할 것으로 보여지지만, 실제로 서버에 도착하는 요청은 하나뿐이다.&lt;br /&gt;이러한 최적화에 감사할 수 있는 조금 더 현실적인 케이스는 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유저 리스트를 fetch 한다.&lt;/li&gt;
&lt;li&gt;유저의 수를 화면에 표시한다.&lt;/li&gt;
&lt;li&gt;유저 리스트를 렌더링 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 케이스는 데이터 fetching을 &lt;b&gt;container 컴포넌트&lt;/b&gt;에서 하고, &lt;b&gt;presentational 컴포넌트&lt;/b&gt;는 표현만 하도록 개발하는 패턴에서 주로 발생한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Container.jsx
export default function Container() {
  const { data: users } = useQuery(['users'], fetchUsers);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{users?.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;
      &amp;lt;UserList users={users} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList({ users }) {
  return users?.map(({ id, name }) =&amp;gt; &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 번만 props를 내려주면 되기 때문에 지금으로선 문제가 없을 수 있다. 하지만 요구 사항이 변경되어 &lt;code&gt;Container&lt;/code&gt; 컴포넌트와 &lt;code&gt;UserList&lt;/code&gt; 컴포넌트 사이에 5개의 컴포넌트가 추가되어 props로 전달하기가 부담스러워졌다고 가정해보겠다. 점점 의문이 들기 시작한다. 과연 &lt;i&gt;react-query&lt;/i&gt;를 잘 활용하고 있는 것일까? 이때 &lt;i&gt;react-query&lt;/i&gt;가 당당하게 해결법을 제시한다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Container.jsx
export default function Container() {
  const { data: users } = useQuery(['users'], fetchUsers);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{users?.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;
      &amp;lt;UserList /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList() {
  const { data: users } = useQuery(['users'], fetchUsers);
  return users?.map(({ id, name }) =&amp;gt; &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 두 번의 fetch를 하는 것 같지만 막상 &lt;b&gt;중복 요청&lt;/b&gt;은 발생하지 않는다. 더 이상 props drilling은 무섭지 않다. 클라이언트와 서버에 동시에 평화가 찾아온 것이다. 이렇게 이야기가 끝나면 얼마나 좋을까? 하지만 현실은 녹록지 않다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;나도 모르게 중복 요청을?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch가 끝날 때까지 기다리다가 완료되면 렌더링하는 경우가 있다. 로딩 상태일 경우 placeholder(주로 loading indicator)를 보여주고, 로딩이 끝나면 실제 데이터를 보여준다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Container.jsx
export default function Container() {
  const { data: users, isLoading } = useQuery(['users'], fetchUsers);

  if (isLoading) {
    return &amp;lt;h1&amp;gt;로딩&amp;lt;/h1&amp;gt;;
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{users.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;
      &amp;lt;UserList /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList() {
  const { data: users } = useQuery(['users'], fetchUsers);
  return users?.map(({ id, name }) =&amp;gt; &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시는 다음 순서로 동작한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Container&lt;/code&gt; 컴포넌트에서 user 리스트 fetch 시작&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isLoading&lt;/code&gt; 값 true로 초기화&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;h1&amp;gt;로딩&amp;lt;/h1&amp;gt;&lt;/code&gt; 렌더링&lt;/li&gt;
&lt;li&gt;user 리스트 fetch 완료&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isLoading&lt;/code&gt; 값 false로 변경&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserList&lt;/code&gt; 마운트&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UserList&lt;/code&gt; 컴포넌트에서 user 리스트 fetch 시작&lt;/li&gt;
&lt;li&gt;cache 된 user 리스트 렌더링&lt;/li&gt;
&lt;li&gt;user 리스트 fetch 완료&lt;/li&gt;
&lt;li&gt;새로운 user 리스트로 리렌더링&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번에서 한 번, 9번에서 한 번, 총 두 번의 요청이 발생한다. &lt;code&gt;UserList&lt;/code&gt; 에서 cache 된 데이터가 일시적으로 보여 체감이 쉽지 않지만, 명백한 중복 요청이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://goidle.github.io/static/83aa2072b273a11e7b733979b439d735/2e237/react-lifescycle.png&quot; data-phocus=&quot;https://goidle.github.io/static/83aa2072b273a11e7b733979b439d735/2e237/react-lifescycle.png&quot;&gt;&lt;img src=&quot;https://goidle.github.io/static/83aa2072b273a11e7b733979b439d735/2e237/react-lifescycle.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fgoidle.github.io%2Fstatic%2F83aa2072b273a11e7b733979b439d735%2F2e237%2Freact-lifescycle.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; alt=&quot;리액트 렌더링 과정&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;354&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 요청을 모아서 하나의 요청으로 만들어주는 것은 한 번의 &lt;b&gt;Render Phase&lt;/b&gt;에서의 요청들이다. 위 예시는 다른 &lt;b&gt;Render Phase&lt;/b&gt;에서의 요청이었기 때문에 하나의 요청으로 합쳐지지 않은 채 그대로 처리된 것이다. 컴포넌트별 데이터 불일치, 중복 에러 핸들링 등 다양한 부수 효과를 내재한 흐름이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다시 한번 부담 주지 않기&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Container.jsx
export default function Container() {
  const { data: users, isLoading } = useQuery(['users'], fetchUsers);

  if (isLoading) {
    return &amp;lt;h1&amp;gt;로딩&amp;lt;/h1&amp;gt;;
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{users.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;
      &amp;lt;UserList&amp;gt;
        {users?.map(({ id, name }) =&amp;gt; {
          return &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;;
        })}
      &amp;lt;/UserList&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList({ children }) {
  return children;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트를 합성하는 방법을 채택한다면 중복 요청이 발생하지 않는다. 그리고 props drilling도 개선할 수 있다. 하지만 기존에 다른 상태 관리 도구를 사용하다가 &lt;i&gt;react-query&lt;/i&gt;로 마이그레이션 하는 상황이라면, 기존의 컴포넌트를 상대적으로 많이 변경해야 하므로 큰 공사가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 방법은 일명 &quot;&lt;b&gt;적재적소 플레이스호더&lt;/b&gt;&quot; 이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Container.jsx
export default function Container() {
  const { data: users, isLoading } = useQuery(['users'], fetchUsers);

  return (
    &amp;lt;div&amp;gt;
      {!isLoading &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{users?.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;}
      &amp;lt;UserList /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList() {
  const { data: users, isLoading } = useQuery(['users'], fetchUsers);
  return !isLoading &amp;amp;&amp;amp; users?.map(({ id, name }) =&amp;gt; &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 데이터가 보여질 부분에 그 데이터의 로딩 상태 조건부 렌더링을 설정하는 것이다. 같은 &lt;b&gt;Render Phase&lt;/b&gt;에 동일 키의 쿼리가 요청되기 때문에 중복 요청이 발생하지 않는다. 그리고 이전 방법의 단점인, 컴포넌트 구조에 큰 변화도 필요하지 않다.&lt;br /&gt;하지만, 이 방법에는 필요 조건이 따른다. 각 부분별로 placeholder를 &lt;b&gt;잘&lt;/b&gt; 만드는 것이다. 위의 예시와 같이 하나의 쿼리(user 리스트)만 존재한다면, placeholder 없이도 큰 문제가 발생하지 않을 것이다. 하지만 여러 개의 쿼리 데이터가 필요하고, 비동기 fetch 작업이 완료되는 시점에 각각 렌더링이 된다면, 종잡을 수 없는 나쁜 유저 경험을 제공할 것이다. 이는 &lt;b&gt;누적 레이아웃 이동(&lt;a href=&quot;https://web.dev/i18n/ko/cls/&quot;&gt;CLS&lt;/a&gt;)&lt;/b&gt;이 많기 때문이다. 그래서 데이터가 fetch 되고, 렌더링 될 때의 크기와 동일한 placeholder가 필요하다. 대표적인 예시로 skeleton loading indicator 등이 있다. 하지만 동적인 데이터(크기가 정해지지 않은 뷰)의 로딩 인디케이터 등, 명백한 한계가 존재한다. 그리고 디자인, 마크업 등 추가적인 외부의 리소스가 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://wpguynews.com/wp-content/uploads/2021/04/thispagehasseveral.gif&quot; data-phocus=&quot;https://wpguynews.com/wp-content/uploads/2021/04/thispagehasseveral.gif&quot; data-alt=&quot;소름 돋는 CLS&quot;&gt;&lt;img src=&quot;https://wpguynews.com/wp-content/uploads/2021/04/thispagehasseveral.gif&quot; srcset=&quot;https://wpguynews.com/wp-content/uploads/2021/04/thispagehasseveral.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; alt=&quot;CLS 가 많이 발생하는 웹페이지&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;338&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;소름 돋는 CLS&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 방법은 &lt;b&gt;Suspense&lt;/b&gt;를 활용하는 것이다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/App.jsx
export default function Container() {
  return (
    &amp;lt;Suspense fallback={&amp;lt;h1&amp;gt;로딩&amp;lt;/h1&amp;gt;}&amp;gt;
      &amp;lt;Container /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/Container.jsx
export default function Container() {
  const { data: users } = useQuery(['users'], fetchUsers, {
    suspense: true, // default 설정으로 true도 가능
  });

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;{users.length} 명의 유저가 있습니다.&amp;lt;/p&amp;gt;
      &amp;lt;UserList /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

// src/components/UserList.jsx
export default function UserList() {
  const { data: users } = useQuery(['users'], fetchUsers, {
    suspense: true
  });

  return users.map(({ id, name }) =&amp;gt; &amp;lt;p key={id}&amp;gt;{name}&amp;lt;/p&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 쿼리의 로딩 상태를 상위 &lt;b&gt;Suspense&lt;/b&gt;로 끌어올리는 것이다. 그러면 쿼리 중 하나만 로딩 상태여도 &lt;b&gt;fallback&lt;/b&gt; 된다. 이는 다른 방법과 같은 원리로 중복 요청이 발생하지 않는다. &quot;&lt;b&gt;적재적소 플레이스호더&lt;/b&gt;&quot; 방법과의 차이점은 로딩 상태가 단 하나로 융합된다는 것이다. 따라서, 로딩 인디케이터도 두 개 이상 필요하지 않다.&lt;br /&gt;Suspense를 안정적으로 도입하기 위해서는 &lt;b&gt;리액트18&lt;/b&gt;이 필요하다. 리액트18은 IE11를 서포트하지 않는다. 그래서 불행히도 IE11을 지원하는 서비스에서는 사용하지 못하는 방법이다. 하지만 다행히도 IE11은 지원 종료됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props drilling을 피하고, &lt;i&gt;react-query&lt;/i&gt;의 힘을 온전히 느끼고 싶다면 결국 두가지 방법만이 선택지에 남는다. &quot;&lt;b&gt;플레이스호더&lt;/b&gt;&quot; 방법과 &quot;&lt;b&gt;Suspense&lt;/b&gt;&quot; 방법이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Suspense&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;적재적소 플레이스호더&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제는 &lt;a href=&quot;https://react-query-props-drilling.vercel.app/&quot;&gt;react-query-props-drilling&lt;/a&gt; 에서 확인 가능하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://react-query.tanstack.com/guides/suspense&quot;&gt;https://react-query.tanstack.com/guides/suspense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/i18n/ko/cls/&quot;&gt;https://web.dev/i18n/ko/cls/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jsonplaceholder.typicode.com&quot;&gt;https://jsonplaceholder.typicode.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Web/React</category>
      <category>props drilling</category>
      <category>REACT</category>
      <category>react-query</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/25</guid>
      <comments>https://hyunmindev.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 18 Jul 2022 18:58:12 +0900</pubDate>
    </item>
    <item>
      <title>react-query로 클라이언트 상태 관리 하기</title>
      <link>https://hyunmindev.tistory.com/23</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blog-thumbnail_22.04.03.png&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HMPo3/btrymjTeqqM/nvCCFXKImsKoEoio9InELK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HMPo3/btrymjTeqqM/nvCCFXKImsKoEoio9InELK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HMPo3/btrymjTeqqM/nvCCFXKImsKoEoio9InELK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHMPo3%2FbtrymjTeqqM%2FnvCCFXKImsKoEoio9InELK%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; alt=&quot;React Query 클라이언트 상태관리 하기&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;337&quot; data-filename=&quot;blog-thumbnail_22.04.03.png&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;'서버 상태 관리'&lt;/b&gt;라는 멋진 키워드로 등장한 react-query는 리액트 생태계에 큰바람을 불러일으키고 있다. 많은 프로젝트에서 redux + redux-saga 조합을 사용한다. 이 조합은 UI와 비동기 작업의 관심사 분리에 있어 해법처럼 사용되곤 했다. 하지만 프로젝트 규모가 커짐에 따라 redux 본연의 가치가 redux-saga의 거대한 덩치에 가려지기 일쑤이다. 그리고 이 조합은 리액트의 학습 곡선을 가파르게 한 주범이기도 하다. 그래서 redux + redux-saga 조합을 새로운 패러다임인 react-query로 대체하려는 움직임이 많이 보인다. 마이그레이션 과정에서 클라이언트 상태 관리 방법에 대한 고민이 늘 따랐다. 이번 포스트는 해당 고민을 정리한 글이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서버 상태, 클라이언트 상태&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-query는 그동안 우리가 &lt;b&gt;전역 상태&lt;/b&gt;라는 이름으로 뭉뚱그려 부르던 것을 클라이언트 상태와 서버 상태로 구분한다. 서버 상태는 서버와 클라이언트가 비동기적으로 공유하는 데이터를 말하고, 클라이언트 상태는 클라이언트에서만 발생하고 사용하는 상태를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;react-query는 자신을 복잡한 비동기 보일러플레이트 코드를 우리의 코드로부터 제거해준다고 소개한다. 그리고 자신만만하게 다음과 같이 얘기한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 코드를 리액트 쿼리로 마이그레이션 한다면, 아마 남아있는 클라이언트 상태는 거의 없을 거야.&lt;br /&gt;그런데 계속 클라이언트 상태 관리 라이브러리를 쓸 거야?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이그레이션 한 후 남은 전역 상태는 '라이트/다크 모드'와 같은 UI와 관련된 상태일 것이고, 이마저도 그리 많지 않을 것이다. 또는 next.js를 사용하며 서버 사이드에서 user 상태를 불러와 사용하는 경우도 흔치 않게 있을 것이다. 도큐먼트 말미에는 &quot;클라이언트 상태 관리 라이브러리를 걷어낼지는 당신에게 달려있어!&quot;라는 최소한의 보험을 두긴 하지만, redux에 질려버린 탓인지 이 말이 유독 &quot;리덕스를 꼭 쓸 필요는 없지 않아?&quot;처럼 들린다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가벼운 상태 관리 라이브러리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;redux에 진절머리 난 사람들이 대안으로 선택하는 가벼운, 보일러플레이트가 거의 없다시피 한 세 가지가 있다. 바로 recoil, jotai, zustand이다. 이 세 가지를 분류하자면, recoil과 jotai는 상태를 atom으로 관리하고 zustand는 redux와 같은 flux 패턴을 사용한다. 그래서 zustand는 redux를 닮았고, jotai는 recoil을 닮았다. 그리고 recoil은 Meta(전 Facebook)에서 공식 개발하는 라이브러리이지만, 글 작성 기준 아직 자신을 실험 단계(0.7.0v)로 소개하고 있다. 반면 jotai는 빠른 템포의 커밋으로 편리한 기능이 많이 추가됐고, 앞으로도 그럴 예정이다. 프로덕트 수준에서는 상대적으로 신뢰성 있는 recoil을 사용하는 것이 선호되겠지만, 개인적으로는 사이드 혹은 토이 프로젝트에서 jotai 또는 zustand를 사용하는 편이다. 굳이 분류했지만, 세 가지 모두 redux에 비한다면 상당히 가볍고 편리하다.&lt;br /&gt;여담으로, zustand와 jotai는 &lt;i&gt;dai-shi라는&lt;/i&gt; 도쿄에 사는 멋진 개발자가 개발했다. 앞서 언급하지 않았지만, proxy 기반의 상태 관리 라이브러리인 valtio까지 함께 개발하고 있다. 그리고 친절하게도 _dai-shi_님이 zustand와 jotai 둘 중 무엇을 선택해야 할지 가이드해주고 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useState + useContext의 대체품을 찾는 다면 jotai를 써라.&lt;/li&gt;
&lt;li&gt;리액트 바깥에서 상태를 업데이트하고 싶다면 zustand가 낫다.&lt;/li&gt;
&lt;li&gt;코드 스플리팅이 중요하다면 jotai가 더 잘 작동할 것이다.&lt;/li&gt;
&lt;li&gt;리덕스 개발자 도구를 선호한다면, zustand가 좋을 것이다.&lt;/li&gt;
&lt;li&gt;Suspense 사용을 원한다면, jotai를 사용해라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-04-03 16.11.48.png&quot; data-origin-width=&quot;2674&quot; data-origin-height=&quot;1492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs0iDC/btrymizFyVv/IGlewuLxkF2gWayS2rUPXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs0iDC/btrymizFyVv/IGlewuLxkF2gWayS2rUPXK/img.png&quot; data-alt=&quot;recoil vs jotai vs zustand 다운로드 비교&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs0iDC/btrymizFyVv/IGlewuLxkF2gWayS2rUPXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs0iDC%2FbtrymizFyVv%2FIGlewuLxkF2gWayS2rUPXK%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;783&quot; height=&quot;437&quot; data-filename=&quot;스크린샷 2022-04-03 16.11.48.png&quot; data-origin-width=&quot;2674&quot; data-origin-height=&quot;1492&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;recoil vs jotai vs zustand 다운로드 비교&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 사진은 recoil, jotai, zustand의 다운로드 수를 비교한 것인데 zustand의 가파른 성장세가 눈에 띈다. 작년만 해도 recoil과 비등비등했지만 22년 3월을 기준으로 두 배의 격차를 두고 고공 행진 중이다. 상태 관리 생태계의 새로운 삼국지가 시작됐고, 앞으로의 동향이 기대된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;react-query로 클라이언트 상태 관리를?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 언급한 세 가지 라이브러리 모두 매우 편리하지만, 외부 라이브러리라는 것은 변함없다. 전역으로 관리해야 하는 &lt;b&gt;진짜 클라이언트 상태&lt;/b&gt;가 한두 개뿐인데 라이브러리에 의존하는 것이 석연찮은 것은 자연스럽다. 그래서 react-query를 마치 클라이언트 상태 관리 라이브러리처럼 사용하는 방법을 소개하고자 한다. 사용자의 이름(&lt;code&gt;username&lt;/code&gt;)을 전역 상태로 관리해야 하는 상황을 예로 들겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2022-04-03 at 22.00.20.png&quot; data-origin-width=&quot;2674&quot; data-origin-height=&quot;1292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5Vdr8/btryfigwdnq/Tz1IjfgbEAXe7xRxAuCzxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5Vdr8/btryfigwdnq/Tz1IjfgbEAXe7xRxAuCzxk/img.png&quot; data-alt=&quot;디자이너 구함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5Vdr8/btryfigwdnq/Tz1IjfgbEAXe7xRxAuCzxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5Vdr8%2Fbtryfigwdnq%2FTz1IjfgbEAXe7xRxAuCzxk%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;705&quot; height=&quot;341&quot; data-filename=&quot;Screen Shot 2022-04-03 at 22.00.20.png&quot; data-origin-width=&quot;2674&quot; data-origin-height=&quot;1292&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;&lt;span style=&quot;color: #0593d3;&quot;&gt;파랑&lt;/span&gt; 컴포넌트에서 이름을 업데이트하면 이를 전역 상태에 반영하여 &lt;span style=&quot;color: #ef5369;&quot;&gt;빨강&lt;/span&gt; 컴포넌트에 반영되도록 하겠다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/App.js
import { QueryClient, QueryClientProvider } from 'react-query';

import Setting from './components/Setting';
import Profile from './components/Profile';

const queryClient = new QueryClient();

function App() {
  return (
    &amp;lt;QueryClientProvider client={queryClient}&amp;gt;
      &amp;lt;Setting /&amp;gt;
      &amp;lt;Profile /&amp;gt;
    &amp;lt;/QueryClientProvider&amp;gt;
  );
}

export default App;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;App&lt;/code&gt;에서 &lt;code&gt;QueryClientProvider&lt;/code&gt;를 사용해서 &lt;code&gt;queryClient&lt;/code&gt;를 사용하도록 설정했다. &lt;code&gt;Setting&lt;/code&gt;은 파랑 컴포넌트, &lt;code&gt;Profile&lt;/code&gt;은 빨강 컴포넌트이다. 우선 &lt;code&gt;Setting&lt;/code&gt; 컴포넌트를 살펴보겠다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Setting/index.jsx
import { useState } from 'react';
import { useQueryClient } from 'react-query';

function Setting() {
  const [username, setUsername] = useState('');
  const queryClient = useQueryClient();

  const handleClick = () =&amp;gt; queryClient.setQueryData('username', username);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input
        value={username}
        onChange={({ target: { value } }) =&amp;gt; setUsername(value)}
      /&amp;gt;
      &amp;lt;button
        onClick={handleClick}
      &amp;gt;
        update
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Setting;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;useQueryClient&lt;/code&gt;의 결괏값으로 해당 앱에서 사용하는 &lt;code&gt;queryClient&lt;/code&gt;를 가져온다. 그리고 update 버튼을 클릭하면 &lt;code&gt;setQueryData&lt;/code&gt;를 통해 특정 쿼리 키에 해당하는 데이터를 직접 수정한다. 위 코드에서는 &lt;code&gt;'username'&lt;/code&gt; 키에 해당하는 쿼리 데이터를 현재 컴포넌트의 &lt;code&gt;username&lt;/code&gt;으로 변경한다. 다음으로 &lt;code&gt;Profile&lt;/code&gt; 컴포넌트를 살펴보겠다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Profile/index.jsx
import { useQuery } from 'react-query';

function Profile() {
  const { data: username } = useQuery('username', {
    initialData: '',
    staleTime: Infinity,
  });

  return &amp;lt;h1&amp;gt;{username}&amp;lt;/h1&amp;gt;;
}

export default Profile;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 &lt;code&gt;useQuery&lt;/code&gt; 훅 사용과 매우 유사하다. 다른 점은 query function 인자를 생략했고, &lt;code&gt;initialData&lt;/code&gt;에 초기값을 입력하고 &lt;code&gt;staleTime&lt;/code&gt;을 &lt;code&gt;Infinity&lt;/code&gt; 값으로 설정한 것이다. 클라이언트 상태는 서버 상태와 달리 상하지 않는다. 즉 클라이언트 상태는 클라이언트가 재설정할 때까지 &lt;b&gt;최신 데이터&lt;/b&gt;이다. 그리고 &lt;code&gt;initialData&lt;/code&gt; 데이터에 초깃값을 설정한 것은 동기적으로 상태를 저장하기 위함이다. 이 부분은 설명을 추가하기보단 아래의 두 코드를 비교해보면 어떻게 작동하는지 이해될 것이다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;// 1. sync
const { data: username } = useQuery('username', {
  initialData: '',
  staleTime: Infinity,
});

// 2. async
const { data: username } = useQuery('username', () =&amp;gt; '', {
  staleTime: Infinity,
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지가 react-query를 사용해서 클라이언트 상태 관리를 하는 방법을 간단하게 알아보았다. 하지만 실제로 사용하기에는 조잡한 면이 있다.&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;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { useQuery, useQueryClient } from 'react-query';

export const useSetClientState = (key) =&amp;gt; {
  const queryClient = useQueryClient();
  return (state) =&amp;gt; queryClient.setQueryData(key, state);
};

export const useClientValue = (key, initialData) =&amp;gt;
  useQuery(key, {
    initialData,
    staleTime: Infinity,
  }).data;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커스텀 훅의 이름은 recoil을 계승했다. 위와 같이 커스텀 훅을 만들고 나면, 컴포넌트는 아래와 같아진다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Profile/index.jsx
import { useClientValue } from '../index';

function Profile() {
  const username = useClientValue('username', '');

  return &amp;lt;h1&amp;gt;{username}&amp;lt;/h1&amp;gt;;
}

export default Profile;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// src/components/Setting/index.jsx
import { useState } from 'react';

import { useSetClientState } from '../index';

function Setting() {
  const [username, setUsername] = useState('');
  const setClientState = useSetClientState('username');

  const handleClick = () =&amp;gt; setClientState(username);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input
        value={username}
        onChange={({ target: { value } }) =&amp;gt; setUsername(value)}
      /&amp;gt;
      &amp;lt;button
        type='button'
        onClick={handleClick}
      &amp;gt;
        update
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

export default Setting;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 다른 클라이언트 상태 관리 라이브러리에 버금갈 정도의 모습이 됐다. 실제로 사용하기 위해 추가하면 좋을 두 가지 보완점을 제시하겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재의 상태 값과 같은 값으로 업데이트 시도 시 업데이트하지 않기.&lt;/li&gt;
&lt;li&gt;서버 상태 쿼리와의 키 중복을 피하기 위해서 커스텀 훅 내부에서 처리하기.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 공식 도큐먼트에서 나오는 것이 아닌, 그저 이런 방법도 있다 정도의 소개이다. 더 선호하는 방법으로는 Context API로 Provider 패턴을 사용하는 것이다. 이 포스트의 예제는 아래서 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;iframe src=&quot;https://codesandbox.io/embed/react-query-client-state-itp3g1?fontsize=14&amp;amp;hidenavigation=1&amp;amp;module=%2Fsrc%2FApp.jsx&amp;amp;theme=dark&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1648998492350&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hyunmindev/Study_React-Query-Client-State&quot; data-og-description=&quot;Contribute to hyunmindev/Study_React-Query-Client-State development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hyunmindev/Study_React-Query-Client-State&quot; data-og-url=&quot;https://github.com/hyunmindev/Study_React-Query-Client-State&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/QLFJl/hyNUnFVp2N/rRTxW2lBDgKoKm6EhV9zgk/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202&quot;&gt;&lt;a href=&quot;https://github.com/hyunmindev/Study_React-Query-Client-State&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hyunmindev/Study_React-Query-Client-State&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/QLFJl/hyNUnFVp2N/rRTxW2lBDgKoKm6EhV9zgk/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hyunmindev/Study_React-Query-Client-State&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to hyunmindev/Study_React-Query-Client-State development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leerob.io/blog/react-state-management&quot;&gt;https://leerob.io/blog/react-state-management&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react-query.tanstack.com/guides/does-this-replace-client-state&quot;&gt;https://react-query.tanstack.com/guides/does-this-replace-client-state&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react-query.tanstack.com/guides/initial-query-data&quot;&gt;https://react-query.tanstack.com/guides/initial-query-data&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/pmndrs/jotai&quot;&gt;https://github.com/pmndrs/jotai&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/pmndrs/jotai/issues/13&quot;&gt;https://github.com/pmndrs/jotai/issues/13&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/facebookexperimental/Recoil&quot;&gt;https://github.com/facebookexperimental/Recoil&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/dai-shi&quot;&gt;https://github.com/dai-shi&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/pmndrs/valtio&quot;&gt;https://github.com/pmndrs/valtio&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/React</category>
      <category>jotai</category>
      <category>REACT</category>
      <category>react-query</category>
      <category>recoil</category>
      <category>Zustand</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/23</guid>
      <comments>https://hyunmindev.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 3 Apr 2022 00:31:23 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 후기</title>
      <link>https://hyunmindev.tistory.com/20</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JPEG image-BD210DD65780-1.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/M5OQ5/btrwnaYX5AK/pRbtH2K2OKwpFlOuNjy5JK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/M5OQ5/btrwnaYX5AK/pRbtH2K2OKwpFlOuNjy5JK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/M5OQ5/btrwnaYX5AK/pRbtH2K2OKwpFlOuNjy5JK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FM5OQ5%2FbtrwnaYX5AK%2FpRbtH2K2OKwpFlOuNjy5JK%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; alt=&quot;한강 야경&quot; loading=&quot;lazy&quot; width=&quot;567&quot; height=&quot;425&quot; data-filename=&quot;JPEG image-BD210DD65780-1.jpeg&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;2021년 7월 19부터 2021년 12월 3일까지, 138일간 주중 주말할 것 없이 달렸다.&lt;br /&gt;이 글에서 138일간의 회고와 다음 기수를 위한 정보를 두서없이 작성했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 했을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;지금 생각해보면 부스트캠프에 지원하는 것은 정말 대책 없는 행동이었다.&lt;br /&gt;수료 이후 바로 진행되는 '네트워킹 데이'에서 기업이 채용 설명을 한다. 선착순으로 기업별 개인 상담도 진행했다. 그리고 수십 개의 회사가 부스트캠프 수료생을 대상으로 채용을 진행한다. 대부분 기업은 졸업 예정자 또는 졸업자에게만 지원 자격을 준다. 하지만 나는 졸업 예정은커녕 3학년 1학기를 수료한 &lt;b&gt;그냥 대학생&lt;/b&gt;이다. 기업들의 채용 공고가 올라오고 지원조차 못 할 때마다 졸업장 없는 설움을 절실히 느꼈다. 부스트캠프를 지원한 주목적이 취업이 아니었음에도, 취업에 대한 커지는 욕심은 막을 수 없었다.&lt;br /&gt;내가 부스트캠프를 지원한 주목적은 &lt;b&gt;'고립된 생태계 벗어나기'&lt;/b&gt; 였다.&lt;br /&gt;2019년 8월, 일병을 달자마자 웹 개발 공부를 시작했다. 충분한 사전 조사 없이 그냥 Vue.js로 시작했다. 그렇게 개발을 하다 문득 내가 작성한 이 코드가 잘못된 방식은 아닌지 불안하기 시작했다. 더 나은 방법은 없는지 어느 점이 부족한지 알고 싶었지만 뾰족한 묘수는 없었다. 시간이 흘러 2021년 5월경 부스트캠프 관련 기사를 봤고, 관심이 생겼다. 그리고 소개 사이트에서 아래 문구를 발견하고, 바로 지원 준비를 했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최고의 동료와 함께 문제를 해결하고 학습할 수 있는 환경을 제공합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;모집 과정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모집 과정은 서류, 1차 코테, 2차 코테 순서로 진행됐다. 코딩 테스트는 백준 기준 브론즈, 프로그래머스 기준 레벨 1~2 정도였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경쟁률을 포함한 구체적인 내용을 알고 싶다면 아래 글을 참고 바란다.&lt;/p&gt;
&lt;figure id=&quot;og_1648796378986&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;부스트캠프 웹 풀스택 6기 챌린지 합격&quot; data-og-description=&quot;부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야로 지원했고, 누군가에게 도움이 되&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/3&quot; data-og-url=&quot;https://blog.hyunmin.dev/3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/boCTMm/hyNTteyV4v/3v9NKkANqo6a7T0Nowwbi0/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/xQGAm/hyNTqhQAq1/VH4TZRyTkxzryf2lVikjyK/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/2MPEN/hyNSdRXfUr/0PVJkEw3rzHYroTc4K9Kek/img.png?width=1042&amp;amp;height=642&amp;amp;face=0_0_1042_642&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/3&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/boCTMm/hyNTteyV4v/3v9NKkANqo6a7T0Nowwbi0/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/xQGAm/hyNTqhQAq1/VH4TZRyTkxzryf2lVikjyK/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/2MPEN/hyNSdRXfUr/0PVJkEw3rzHYroTc4K9Kek/img.png?width=1042&amp;amp;height=642&amp;amp;face=0_0_1042_642');&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;부스트캠프 웹 풀스택 6기 챌린지 합격&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야로 지원했고, 누군가에게 도움이 되&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;졸업예정자가 아닌데요!&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여유가 있어 한 두 학기 휴학하는 것이 부담되지 않는다면 어느 시점에라도 부스트캠프를 지원해도 된다고 생각한다. 부스트캠프 수료 이후에는 &lt;b&gt;자신에게 맞는 개발 공부 방법&lt;/b&gt;을 찾게 되고 이것이 취업 준비에 효율을 상당히 높여줄 것이기 때문이다. 하지만 현실적인 문제로 여유가 없다면, 4학년 1학기를 수료하고 지원하는 것을 추천한다. 내가 알게 된 캠퍼 중 전자와 후자의 비율은 2:8 정도였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;뭘 했을까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트캠프는 크게 챌린지와 멤버십 과정으로 나뉜다. 멤버십은 다시 스프린트와 프로젝트, 챌린지는 미션과 릴레이 프로젝트로 나뉜다. 진행하는 콘텐츠는 큰 틀은 같지만, 세부적으로 조금씩 달라지는 것으로 알고 있다.&lt;br /&gt;부스트캠프의 콘텐츠는 전체적으로 &lt;b&gt;자유도가 높다&lt;/b&gt;. 그렇기에 &lt;b&gt;주도적&lt;/b&gt;으로 참여하는 만큼 얻을 수 있는 것이 달라진다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;챌린지 (4주)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;미션 (16일)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4주 동안 월요일부터 목요일까지 매일 새로운 미션이 공개된다. 미션은 CS를 이론으로만 공부하는 것이 아닌 실제 코드로 만들어보는 것이었는데, 굉장히 참신했다. 구현의 행복을 느낄 수 있는 재밌는 미션들이 다수 존재한다. 하지만 미션 제출 시간이 다가올수록 &lt;b&gt;머리털&lt;/b&gt;이 빠지는 듯한 스트레스도 느낄 수 있었다. 부캠 전 과정 중에서 가장 잠을 적게 잤던 시기다.&lt;br /&gt;매일 아침에 배정받은 팀원들끼리 어제 구현했던 내용을 공유하며 토론했다. 부캠의 전 과정이 이런 식으로 공유를 중요시한다. 공유를 목표로 시작했기에 이러한 부분은 상당히 만족스러웠다. 그리고 투머치 토커인 나에게는 일용할 양식과도 같은 시간이었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;릴레이 프로젝트 (4일)&lt;/h4&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;프로젝트의 스택으로 Flutter 2.0을 사용했는데, 너무 편리하고 매력적인 프레임워크인 것을 알게 됐다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;멤버십 (14주)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아쉽지만, 챌린지 과정을 수료한 모든 캠퍼가 멤버십 과정에 입과 하지는 못한다. 무슨 기준으로 선별하는진 모르겠지만 지금 생각해보면 아주 복잡한 프로세스는 아닌 것 같다. 그냥 상식적인 선에서 적극적으로 열심히 하면 되지 않을까 조심스레 추측해본다. 몇 명 중 몇 명이 입과했는지는 아래 글에서 확인할 수 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1648796365173&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;부스트캠프 웹 풀스택 6기 멤버십 합격&quot; data-og-description=&quot;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://hyunmindev.tistory.com/8?category=1035592&quot; data-og-url=&quot;https://blog.hyunmin.dev/8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bj9BMH/hyNR3PkE4h/rJEbHfrklRgILQO2KuOvok/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/rZXUw/hyNToYCqDE/Td75CniyTxP8RV4Rk2L3v0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bKVBUp/hyNTkPtjDV/ZAahjRuBO02kpQ1SGOVMn1/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://hyunmindev.tistory.com/8?category=1035592&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hyunmindev.tistory.com/8?category=1035592&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bj9BMH/hyNR3PkE4h/rJEbHfrklRgILQO2KuOvok/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/rZXUw/hyNToYCqDE/Td75CniyTxP8RV4Rk2L3v0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bKVBUp/hyNTkPtjDV/ZAahjRuBO02kpQ1SGOVMn1/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&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;부스트캠프 웹 풀스택 6기 멤버십 합격&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;스프린트 (8주)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주짜리 스프린트를 총 네 번 진행한다. 소규모 프로젝트 수준의 요구사항과 디자인이 제공되고 이를 구현하는 것을 목표로 한다. 처음에는 하루 단위로 진행했던 챌린지 미션보다 상당히 여유롭다고 느꼈다. 하지만 해야 할 일이 14배가 된 것을 보고 '이 집 밸런스 패치 잘하네'라고 생각했다.&lt;br /&gt;매 스프린트마다 학습에 중점을 둘지 구현에 중점을 둘지 선택하기 어려웠다. 둘 다 챙기기엔 2주라는 시간은 부족했기 때문이다. 멀리 본다면 학습 위주로 프로젝트를 진행하는 것이 더 큰 득이 있다는 것을 알았지만, 어떻게 구현의 행복을 저버리겠는가. 돌이켜보면 구현에 조금 더 치우쳐 있었다고 생각된다.&lt;br /&gt;가장 많은 성장을 이루었다고 생각되는 시기가 이때다. 4개 중 3개의 스프린트에서 리액트 사용이 제한됐다. '익숙함에 속아 소중함을 잃지 말자' 라는 싸이월드 감성의 말을 납득하는 순간이었다. 이 말이 조금 오글거려서 그렇지 진리이긴 한가보다. &lt;b&gt;리액트의 소중함과 Vanilla JS의 중요성&lt;/b&gt;을 동시에 깨달은 시기기도 하다. 그리고 이 때의 경험으로 나의 공부 철학을 다시금 잡았다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;프로젝트 (6주)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6주 동안 기획, 개발, QA를 진행했고, 각각 1주, 4주, 1주로 할당했다. 주제는 자유 선정이었다.&lt;br /&gt;면접에서는 주로 이때의 과정을 질문한다. 주도적으로 야무지게 하지 않는다면 취업의 난이도가 올라갈 것이라는 생각이 든다. 그리고 매일 회의, 코드 리뷰를 하므로 소프트 스킬을 업그레이드할 좋은 기회였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 개발 통계를 보여주는 WakaTime이라는 서비스가 있다. 사용하고 있는 IDE에 플러그인을 설치하면 에디터에 포커스를 두었던 시간을 측정해준다. 프로젝트 기간에 하루 평균 8시간 10분, 주 57시간 &lt;b&gt;코드를 작성&lt;/b&gt;했고, 전세계에서 최고 52등까지 올라보았다. 이때부터 아파진 등이 아직 아프다. 건강하고 오래오래 행복하게 살자고 하는 공부인데 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 가지 팁이자 반성을 남기자면 프로젝트 주제를 선정할 때 &lt;b&gt;'참신한 서비스를 해야지'와 같은 욕심&lt;/b&gt;은 크게 도움이 되지 않았다. 참신한 아이디어를 떠올릴 시간에 기술적으로 깊어질 고민을 했더라면 조금 더 가치 있는 아웃풋을 만들었을 것이다. 그리고 '많은 스택을 사용해봐야지'라는 목표를 잡는다면 깊게 파고드는 것을 조금 내려놓아야 한다는 것을 명심해야 한다. 한정된 시간에서 &lt;b&gt;깊이와 너비는 트레이드오프&lt;/b&gt; 관계이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;수료 이후&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힘들었던 날을 뒤로하고 쉬고 싶은 마음이 굴뚝같았지만, 바로 다음 주부터 채용 공고가 올라왔다. 마치 PT 받을 때 트레이너 선생님이 '두 개 더..., 한 개만 더...'라고 하는 것 같았다. 물론 PT를 받아본 적은 없다. 그렇게 수료 이후 새로운 마라톤을 시작했다. 자소서 쓰고, 면접 준비하고, 코테를 준비했다. 그렇게 끝이라고 생각했던 시간으로부터 3개월을 더 달렸고, 최종 합격 메일을 받았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2022-03-19 at 22.39.15.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAe4YV/btrwkwIHrsN/0eZP1XuiiVwT67v4Yo7cSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAe4YV/btrwkwIHrsN/0eZP1XuiiVwT67v4Yo7cSk/img.png&quot; data-alt=&quot;눈물 젖은 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAe4YV/btrwkwIHrsN/0eZP1XuiiVwT67v4Yo7cSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAe4YV%2FbtrwkwIHrsN%2F0eZP1XuiiVwT67v4Yo7cSk%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; alt=&quot;합격 메일&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;399&quot; data-filename=&quot;Screen Shot 2022-03-19 at 22.39.15.png&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1402&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;작년 7월부터 시작한 긴 여정을 마무리하고 곧바로 제주도로 떠났다. 그리고 이 글을 작성하는 지금은 입사 후 2주가 지난 시점이다. 학교는 3학기가 남았지만, 학과 사무실에 문의한 결과 무기한 휴학 연장이 된다는 답변을 들었고, 학교가 필요하다고 판단될 때 다시 돌아갈 예정이다.&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://blog.hyunmin.dev/4&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 1주차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/5&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 2주차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/6&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 3주차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/7&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/8&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 합격&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/9&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/13&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/17&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/18&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 4회차&lt;/a&gt;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/20</guid>
      <comments>https://hyunmindev.tistory.com/20#entry20comment</comments>
      <pubDate>Sat, 19 Mar 2022 18:52:14 +0900</pubDate>
    </item>
    <item>
      <title>타입스크립트에서 prop-types를 사용할까?</title>
      <link>https://hyunmindev.tistory.com/19</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2021-12-30 at 9.07.47 PM.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ep8qJE/btrpoyyejXS/nZpEUTKO7x1QGLYBUNkOak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ep8qJE/btrpoyyejXS/nZpEUTKO7x1QGLYBUNkOak/img.png&quot; data-alt=&quot;prop-type와 타입스크립트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ep8qJE/btrpoyyejXS/nZpEUTKO7x1QGLYBUNkOak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fep8qJE%2FbtrpoyyejXS%2FnZpEUTKO7x1QGLYBUNkOak%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;1800&quot; height=&quot;848&quot; data-filename=&quot;Screen Shot 2021-12-30 at 9.07.47 PM.png&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;prop-type와 타입스크립트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 prop-types 라이브러리를 사용해 props의 타입을 체크할 수 있다. 그리고 타입스크립트를 사용해 props의 타입을 체크할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 일을 하는 것 같지만 다른 일을 한다. 각각 무슨 일을 하는지 알아보고 타입스크립트에서 prop-types를 사용할지 체크해보길 바란다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;타입스크립트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트는 동적 언어인 자바스크립트를 정적 언어로 사용하기 위한 언어이다. 정적 언어는 컴파일 시에 타입이 결정되고, 동적 언어는 런타임에 타입이 결정된다.&lt;br /&gt;&lt;b&gt;타입스크립트는 런타임에 타입 체크를 하지 않는다.&lt;/b&gt; 이는 &lt;a href=&quot;https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals#goals&quot;&gt;타입스크립트 Design Goals&lt;/a&gt; 3번 '실행한 프로그램에 런타임 오버헤드를 부과하지 않는다.'에 부합한다.&lt;br /&gt;타입스크립트로 Props의 타입을 체크하기 위해 일반적으로 아래와 같이 작성한다.&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;interface Props {
  title: string;
  id: string;
}

function Label({ title, id }: Props) {
  return (
    &amp;lt;p&amp;gt;
      {id}:{title}
    &amp;lt;/p&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Label&lt;/code&gt; 컴포넌트에 문자열 타입의 &lt;code&gt;title&lt;/code&gt;과 &lt;code&gt;id&lt;/code&gt;를 받도록 지정한 것이다. 그리고 &lt;code&gt;Label&lt;/code&gt; 컴포넌트를 사용하겠다.&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;function Home() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Label title='first' id='1' /&amp;gt; // (A)
      &amp;lt;Label title='second' id={2} /&amp;gt; // (B)
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(B)에서 오류가 발생하는 것은 분명하다. 이는 컴파일 단계에서 검출될 뿐만 아니라, IDE에서 미리 경고를 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2021-12-30 at 11.26.09 PM.png&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lE63W/btrpjxzIpig/3P16kSD5eRcUkMCAYrSkAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lE63W/btrpjxzIpig/3P16kSD5eRcUkMCAYrSkAk/img.png&quot; data-alt=&quot;TS2322: Type 'number' is not assignable to type 'string'.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lE63W/btrpjxzIpig/3P16kSD5eRcUkMCAYrSkAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlE63W%2FbtrpjxzIpig%2F3P16kSD5eRcUkMCAYrSkAk%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;603&quot; height=&quot;117&quot; data-filename=&quot;Screen Shot 2021-12-30 at 11.26.09 PM.png&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;TS2322: Type 'number' is not assignable to type 'string'.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 런타임 단계에서 타입 불일치가 발생할 경우는 어떻게 되는 것일까? 이 고민보다 선행돼야 하는 고민은 '&lt;b&gt;어떤 경우에 런타임 단계에서 타입 불일치가 발생할까?'이다.&lt;/b&gt; 컴파일 단계를 건너뛰고 런타임에 처음 등장하는 데이터는 외부 데이터뿐이다. API 호출을 통해 받아온 응답 Body, 로컬 스토리지 등의 외부 데이터는 컴파일 단계에서 타입 체크를 할 수 없다. 즉, &lt;b&gt;외부 데이터는 런타임 단계에서 타입 불일치가 발생할 가능성이 있다.&lt;/b&gt;&lt;br /&gt;이것을 증명하기 위해 &lt;a href=&quot;https://api.sampleapis.com/coffee/hot&quot;&gt;커피 데이터를&lt;/a&gt; 활용해 메뉴판을 만드는 컴포넌트를 작성하겠다. 이 커피 배열의 한 요소의 타입은 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;interface Coffee {
  title: string;
  id: number;
  description: string;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 분명 어제까지만 해도 &lt;code&gt;id&lt;/code&gt;의 타입은 string이었고, 수정한 서버 개발자가 이를 알려주지 않아 수정하지 않았다고 가정하겠다. 그렇다면 아래와 같이 컴포넌트를 작성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;interface Coffee {
  title: string;
  id: string;
}

function Home() {
  const [coffees, setCoffees] = useState&amp;lt;Coffee[]&amp;gt;([]);

  useEffect(() =&amp;gt; {
    fetch('https://api.sampleapis.com/coffee/hot')
      .then((res) =&amp;gt; res.json())
      .then((data) =&amp;gt; setCoffees(data));
  }, []);

  return (
    &amp;lt;&amp;gt;
      {coffees.map(({ title, id }) =&amp;gt; (
        &amp;lt;Label title={title} id={id} key={id} /&amp;gt;
      ))}
    &amp;lt;/&amp;gt;
  );
}

interface Props {
  title: string;
  id: string;
}

function Label({ title, id }: Props) {
  console.log(typeof id); // ⭐️
  return (
    &amp;lt;p&amp;gt;
      {id}:{title}
    &amp;lt;/p&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;Screen Shot 2021-12-30 at 11.55.19 PM.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;3054&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lJgy7/btrpeJnSeCj/q5x8RXodvKNIUCjnKJxawK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lJgy7/btrpeJnSeCj/q5x8RXodvKNIUCjnKJxawK/img.png&quot; data-alt=&quot;실행 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lJgy7/btrpeJnSeCj/q5x8RXodvKNIUCjnKJxawK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlJgy7%2FbtrpeJnSeCj%2Fq5x8RXodvKNIUCjnKJxawK%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;489&quot; height=&quot;536&quot; data-filename=&quot;Screen Shot 2021-12-30 at 11.55.19 PM.png&quot; data-origin-width=&quot;2784&quot; data-origin-height=&quot;3054&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;&lt;code&gt;id&lt;/code&gt;의 타입을 string으로 지정했지만, 실제 타입은 number다. 하지만 아무런 오류도 없다. 컴파일 단계에선 문제가 없었기 때문이다. 언제 터질지 모르는 폭탄이 생겨버린 것이다.&lt;br /&gt;이제 런타임 과정에서 발생하는 타입 불일치를 확인할 방법을 알아보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;prop-types&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime type checking for React props and similar objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prop-types 라이브러리는 런타임에 타입 체크를 한다. 이전에 예제에 추가해보겠다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;interface Props {
  title: string;
  id: string;
}

function Label({ title, id }: Props) {
  return (
    &amp;lt;p&amp;gt;
      {id}:{title}
    &amp;lt;/p&amp;gt;
  );
}

Label.propTypes = {
  title: PropTypes.string.isRequired,
  id: PropTypes.string.isRequired,
};&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;Screen Shot 2022-01-02 at 10.07.10 AM.png&quot; data-origin-width=&quot;2384&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EP6uR/btrpwQzao2F/dLysjByGNA44iOcy2oZtk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EP6uR/btrpwQzao2F/dLysjByGNA44iOcy2oZtk1/img.png&quot; data-alt=&quot;id는 string이 아니라 number!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EP6uR/btrpwQzao2F/dLysjByGNA44iOcy2oZtk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEP6uR%2FbtrpwQzao2F%2FdLysjByGNA44iOcy2oZtk1%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;2384&quot; height=&quot;1280&quot; data-filename=&quot;Screen Shot 2022-01-02 at 10.07.10 AM.png&quot; data-origin-width=&quot;2384&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;id는 string이 아니라 number!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;prop-types는 &lt;code&gt;id&lt;/code&gt;의 실제 타입과 명시한 타입의 불일치를 인지한다. 이를 통해 문제 상황을 조기에 발견했기에 큰 문제로 번지지 않았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가정한 상황 이외에도 실제 API 응답 값의 타입과 명시된 타입이 달라질 시나리오는 많다. API 이외에도 로컬 스토리지와 같은 외부 데이터를 런타임에 가져오는 상황이라면 타입 불일치 가능성을 염두에 두길 바란다. 타입스크립트를 사용하는 이유 중 큰 비중을 차지하는 것이 휴먼 에러를 미연에 방지하자는 것이 아닌가? &lt;b&gt;완벽한 휴먼 에러 퇴치를 원한다면 prop-types 사용을 권장한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 prop-types 라이브러리로 런타입 타입 체크를 한다면 추가의 개발 리소스를 필요로 하는 것은 사실이다. API의 타입이 바뀔 가능성이 정말 없다면 런타임 타입 체크를 생략하는 것도 방법의 하나다. 그리고 추가적인 리소스를 최소화하기 위해 아래와 같은 도구들이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://gist.github.com/brieb/48698aca8565310db4453b9ff875dee3&quot;&gt;brieb/props-type.ts&lt;/a&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트 유틸리티 타입을 통해 런타임 타입 체크를 하는 구현 방법이다.&lt;br /&gt;해당 구현의 자세한 설명은 &lt;a href=&quot;https://youtu.be/P-J9Eg7hJwE?t=1063&quot;&gt;Adopting Typescript at Scale&lt;/a&gt;를 참고 바란다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://github.com/grncdr/ts-react-loader#ts-react-loader&quot;&gt;ts-react-loader&lt;/a&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props 인터페이스를 기반으로 런타임 타입 체크 코드를 자동으로 생성하는 웹팩 로더이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://github.com/gcanti/prop-types-ts&quot;&gt;prop-types-ts&lt;/a&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입스크립트 런타임 타입 시스템인 &lt;a href=&quot;https://github.com/gcanti/io-ts&quot;&gt;io-ts&lt;/a&gt;를 기반으로 제작된 라이브러리이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://github.com/milesj/babel-plugin-typescript-to-proptypes&quot;&gt;babel-plugin-typescript-to-proptypes&lt;/a&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props 인터페이스를 기반으로 런타임 타입 체크 코드를 자동으로 생성하는 바벨 플러그인이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://ko.reactjs.org/docs/typechecking-with-proptypes.html&quot;&gt;https://ko.reactjs.org/docs/typechecking-with-proptypes.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/41746028/proptypes-in-a-typescript-react-application&quot;&gt;https://stackoverflow.com/questions/41746028/proptypes-in-a-typescript-react-application&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://medium.com/@taehwannoh/react-component-props-typing-with-proptypes-and-defaultprops-in-typescript-233eadb86314&quot;&gt;https://medium.com/@taehwannoh/react-component-props-typing-with-proptypes-and-defaultprops-in-typescript-233eadb86314&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals#goals&quot;&gt;https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals#goals&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/TypeScript</category>
      <category>prop-types</category>
      <category>TS</category>
      <category>typeScript</category>
      <category>타입스크립트</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/19</guid>
      <comments>https://hyunmindev.tistory.com/19#entry19comment</comments>
      <pubDate>Sun, 2 Jan 2022 10:50:45 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 멤버십 스프린트 4회차</title>
      <link>https://hyunmindev.tistory.com/18</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGpOKC/btriB5DwcVN/dM60bFVGr2ARGaYZlpCWoK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGpOKC/btriB5DwcVN/dM60bFVGr2ARGaYZlpCWoK/img.jpg&quot; data-alt=&quot;마지막 스프린트&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGpOKC/btriB5DwcVN/dM60bFVGr2ARGaYZlpCWoK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGpOKC%2FbtriB5DwcVN%2FdM60bFVGr2ARGaYZlpCWoK%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;620&quot; height=&quot;349&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;마지막 스프린트&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1634996597471&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/17&quot; data-og-url=&quot;https://blog.hyunmin.dev/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bV7Bl9/hyL4GUOGFx/7lHpGaGfjlCAKuQHJYzYu1/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bn8u3u/hyL4DjupHI/HJcYEIXtooOukrSWpdyk81/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bziDec/hyL4EinQwG/Kwk7GIxhrlMLyHUBaUrlXk/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bV7Bl9/hyL4GUOGFx/7lHpGaGfjlCAKuQHJYzYu1/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bn8u3u/hyL4DjupHI/HJcYEIXtooOukrSWpdyk81/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bziDec/hyL4EinQwG/Kwk7GIxhrlMLyHUBaUrlXk/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440');&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;  TL;DR&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마지막 스프린트는 팀 프로젝트로 진행했다. 2인 1조로 랜덤 하게 팀이 구성되어 2주간 협업했다. 하루에 많으면 10시간씩 얘기하며 협업하다 보니 부스트캠프 활동 처음으로 지친다는 생각이 조금 들었다. 하지만 다행히도 좋은 팀원을 만나서 2주를 잘 마무리할 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp;&lt;/b&gt;미션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;React&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 미션부터는 React 라이브러리 사용이 허용됐다. 바닐라 JS로 SPA를 구현 후에 React를 다시 보니 이전에 보이지 않던 부분이 보였다. '아, 이 부분은 이런 식으로 구현이 돼 있겠지.'라는 생각을 많이 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;React로 처음 개발을 시작하면 JS 문법과 React 문법을 구분하지 못할 수도 있다는 얘기를 들었다. 내가 그랬다. 하지만 이번 계기로 한 단계 성장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;React 학습 전에 바닐라 JS 학습은 필수에 가깝다고 생각한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;페어 프로그래밍&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그룹 프로젝트와 페어 프로그래밍은 사뭇 달랐다. 따로 작업을 하고 병합하는 것이 아닌, 함께 같은 부분을 작업했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;코드를 작성하는 것을 실시간으로 누군가가 지켜보고 있다는 것이 익숙하지 않았다. 하지만 동료와의 훈수 교환으로 쉽게 성장시킬 수 없는 부분을 성장시킨 느낌이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Socket.IO&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Socket.IO가 웹소켓만 사용한다고 착각하고 있었다. 폴링, 롱 폴링, 웹소켓 등 다양한 이론 지식을 공부했고, Socket.IO의 자세한 동작 방식을 이해할 수 있었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;MongoDB, Mongoose&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;늘 MySQL만 사용하다 이번에는 NoSQL을 DB로 선택했다. 조금 더 편리하다고 느껴졌다. 서비스의 성격에 맞게 잘 선택해야겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;  마무리&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마지막 스프린트가 끝이 나고, 부스트캠프도 끝을 향해 달려가고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음 주면 마지막인 그룹 프로젝트가 시작이다.&lt;/p&gt;
&lt;figure id=&quot;og_1648798164311&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;부스트캠프 웹 풀스택 6기 후기&quot; data-og-description=&quot;2021년 7월 19부터 2021년 12월 3일까지, 138일간 주중 주말할 것 없이 달렸다. 이 글에서 138일간의 회고와 다음 기수를 위한 정보를 두서없이 작성했다. 왜 했을까? 지금 생각해보면 부스트캠프에 지&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/20&quot; data-og-url=&quot;https://blog.hyunmin.dev/20&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb5sSH/hyNTxgZzlu/7hIF0aLVzxfJLQPWaQsihK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bxmQZd/hyNTsfGV3R/kBAqhboesVkaCD8CXWsWd1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/HDClh/hyNTr184FX/MMqj8zPjgbJGreHdvHIBG0/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/20&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb5sSH/hyNTxgZzlu/7hIF0aLVzxfJLQPWaQsihK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bxmQZd/hyNTsfGV3R/kBAqhboesVkaCD8CXWsWd1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/HDClh/hyNTr184FX/MMqj8zPjgbJGreHdvHIBG0/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024');&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;부스트캠프 웹 풀스택 6기 후기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;2021년 7월 19부터 2021년 12월 3일까지, 138일간 주중 주말할 것 없이 달렸다. 이 글에서 138일간의 회고와 다음 기수를 위한 정보를 두서없이 작성했다. 왜 했을까? 지금 생각해보면 부스트캠프에 지&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/18</guid>
      <comments>https://hyunmindev.tistory.com/18#entry18comment</comments>
      <pubDate>Sun, 24 Oct 2021 00:15:40 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차</title>
      <link>https://hyunmindev.tistory.com/17</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; width=&quot;416&quot; height=&quot;555&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8TcyO/btrhh8HtkfZ/z7xh0f0IPxnjbTzFvlD1T1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8TcyO/btrhh8HtkfZ/z7xh0f0IPxnjbTzFvlD1T1/img.jpg&quot; data-alt=&quot;블로그 대신 써줄 사람&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8TcyO/btrhh8HtkfZ/z7xh0f0IPxnjbTzFvlD1T1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8TcyO%2Fbtrhh8HtkfZ%2Fz7xh0f0IPxnjbTzFvlD1T1%2Fimg.jpg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1440&quot; width=&quot;416&quot; height=&quot;555&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&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;figure id=&quot;og_1633787590425&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 &quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/13&quot; data-og-url=&quot;https://blog.hyunmin.dev/13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jfVbj/hyLTFP3JN7/ZMck2cAjnF57FvYkNolVMk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cBikIn/hyLTt9Wqx5/avmK9FRBpbHPoCT9BtTzKK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bWLvQB/hyLTABdDbF/5zkKSw8lZ8rCYVVdYj9rHK/img.jpg?width=960&amp;amp;height=720&amp;amp;face=0_0_960_720&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jfVbj/hyLTFP3JN7/ZMck2cAjnF57FvYkNolVMk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cBikIn/hyLTt9Wqx5/avmK9FRBpbHPoCT9BtTzKK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bWLvQB/hyLTABdDbF/5zkKSw8lZ8rCYVVdYj9rHK/img.jpg?width=960&amp;amp;height=720&amp;amp;face=0_0_960_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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;  TL;DR&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구현의 집착을 버리고 한결 가볍게 개발했다. 학습해야 할 키워드가 끝도 없이 제공돼서 2주 만에 엄청나게 성장해버린 기분이다. 이 정도면 튼 살이 생길 지경이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt; &amp;nbsp;&lt;/b&gt;미션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SPA&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;바닐라 JS로 SPA를 구현하는 것은 항상 머리가 아프다. 저번 미션까지는 준일님의 블로그를 참고하여 SPA 모듈을 설계했다. 하지만 이번에는 양방향 데이터 바인딩, 관찰자 패턴을 도입해&amp;nbsp;Vue.js 스럽게 탈바꿈하여 기술 독립을&amp;nbsp;했다.&lt;/p&gt;
&lt;figure id=&quot;og_1633999185611&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;자바스크립트의 Data Binding&quot; data-og-description=&quot;Vue React Angular 단방향, 양방향 바인딩 단방향 바인딩 단방향, 양방향 바인딩 프론트엔드 프레임워크 및 라이브러리 삼대장은 모두 데이터 바인딩을 지원한다. 그만큼 필요하다는 뜻이라고 생각&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/15&quot; data-og-url=&quot;https://blog.hyunmin.dev/15&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eKI8g/hyLUpmnBQC/nBoPn2sLdcOQ8y8qSXBKJ1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bswfxX/hyLV1c9SfQ/BvFVjJcuNxENKwRcDkqJk0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/fjXMG/hyLVRImCf8/4pwssmW199K0KQoV5lksx1/img.png?width=2528&amp;amp;height=1198&amp;amp;face=0_0_2528_1198&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/15&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eKI8g/hyLUpmnBQC/nBoPn2sLdcOQ8y8qSXBKJ1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bswfxX/hyLV1c9SfQ/BvFVjJcuNxENKwRcDkqJk0/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/fjXMG/hyLVRImCf8/4pwssmW199K0KQoV5lksx1/img.png?width=2528&amp;amp;height=1198&amp;amp;face=0_0_2528_1198');&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;자바스크립트의 Data Binding&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Vue React Angular 단방향, 양방향 바인딩 단방향 바인딩 단방향, 양방향 바인딩 프론트엔드 프레임워크 및 라이브러리 삼대장은 모두 데이터 바인딩을 지원한다. 그만큼 필요하다는 뜻이라고 생각&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;가상 돔의 비교 알고리즘, 데이터 바인딩 등 원리를 아는 것이 더 수준 높은 개발자로 가는 길이라고 믿고 공부하겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;ORM&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;데이터를 객체에 매핑해&amp;nbsp;관계형 데이터베이스를 객체지향적으로 사용할 수 있게 해주는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 스프린트에서는 MySQL과 Sequelize를 사용해서 데이터베이스를 관리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;왜 이것에 그리 집착하는지 몰랐다. 사용해보니 알겠다. 유지보수, 직관성, 가독성 측면에서 선택하지 않을 이유가 없었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;OAuth&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 부분도 나에게 기술 잔반이었다. firbase, auth0처럼 인증만 전문적으로 해주는 서비스를 사용하면서 만족했던 과거의 나에게 잔소리를 한 바가지 해주고 싶다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Promise&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로미스를 객체를 직접 구현해보라는 요구 사항이 있었다.&lt;/p&gt;
&lt;figure id=&quot;og_1633999199700&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;자바스크립트의 Promise 직접 구현하기&quot; data-og-description=&quot;사용할 줄 안다는 것과 이해했다는 것은 차이가 있다. 이번 포스트에서 Promise 객체를 직접 구현해보며 이해하도록 하겠다.   사전 지식 Promise Classes   요구사항 1. resolve, reject new Promise((resolve.&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/14&quot; data-og-url=&quot;https://blog.hyunmin.dev/14&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UN7bW/hyLUlqNtY8/yMaXFzl1uX8Gkg2kmseUk1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/D3Fcp/hyLUkrR6Ep/xwzD6drYfxktpefXZgwHZk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cerXLz/hyLVVKLAXj/voKIk8n5XMjGaMCceeJreK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/14&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/14&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UN7bW/hyLUlqNtY8/yMaXFzl1uX8Gkg2kmseUk1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/D3Fcp/hyLUkrR6Ep/xwzD6drYfxktpefXZgwHZk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/cerXLz/hyLVVKLAXj/voKIk8n5XMjGaMCceeJreK/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트의 Promise 직접 구현하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;사용할 줄 안다는 것과 이해했다는 것은 차이가 있다. 이번 포스트에서 Promise 객체를 직접 구현해보며 이해하도록 하겠다.   사전 지식 Promise Classes   요구사항 1. resolve, reject new Promise((resolve.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 요구 사항에 대한 주변 캠퍼 반응은 '다른 거 공부하기도 벅찬데, 그거 할 시간이 어딨냐?'였다. 하지만 나는 반대로 프로미스 객체 구현 먼저 시작했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로미스를 100% 이해한다고 자신할 수 없었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;직접 구현해보며 다양한 테스트 케이스를 만들어 보았고, 이 과정에서 프로미스의 복잡한 작동 방식을 이해했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;  마무리&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다음은 마지막 스프린트이다. 슬슬 면접과 코테를 준비하라는 조언이 들린다. 행복 코딩하느라 정신없지만, 이제부턴 미래를 위한 시간을 할당해야겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음 글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1635002154417&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 4회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/18&quot; data-og-url=&quot;https://blog.hyunmin.dev/18&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FeCbk/hyL4L2YYkA/8B4n9hukWj50I2CQvLW5D1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bd9UrI/hyL4ECKGCm/T1qXPxv9IRccKXWcUJYXd1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ctjaBR/hyL4CStJGs/frEtXLMeAMj49DdfyrGvu0/img.jpg?width=1182&amp;amp;height=665&amp;amp;face=0_0_1182_665&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/18&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/18&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FeCbk/hyL4L2YYkA/8B4n9hukWj50I2CQvLW5D1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bd9UrI/hyL4ECKGCm/T1qXPxv9IRccKXWcUJYXd1/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/ctjaBR/hyL4CStJGs/frEtXLMeAMj49DdfyrGvu0/img.jpg?width=1182&amp;amp;height=665&amp;amp;face=0_0_1182_665');&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 4회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <category>부스트캠프 멤버십</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/17</guid>
      <comments>https://hyunmindev.tistory.com/17#entry17comment</comments>
      <pubDate>Sat, 9 Oct 2021 19:00:03 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트의 Data Binding</title>
      <link>https://hyunmindev.tistory.com/15</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Evoky/btrg9kOA91s/vjEBKvxbLKZNEKMBSyeePK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Evoky/btrg9kOA91s/vjEBKvxbLKZNEKMBSyeePK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Evoky/btrg9kOA91s/vjEBKvxbLKZNEKMBSyeePK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEvoky%2Fbtrg9kOA91s%2FvjEBKvxbLKZNEKMBSyeePK%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;1920&quot; height=&quot;1080&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&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;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;Angular&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;React&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;Vue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;단방향, 양방향&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;단방향&lt;/td&gt;
&lt;td style=&quot;width: 33.333333333333336%;&quot;&gt;단방향, 양방향&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드 프레임워크 및 라이브러리 삼대장은 모두 데이터 바인딩을 지원한다. 그만큼 필요하다는 뜻이라고 생각한다. 이번 포스트에서 데이터 바인딩에 대해서 알아보겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이 포스트는 데이터 바인딩 개념 자체를 알아보는 글이다. vue에서의 데이터 바인딩을 알아보고 싶다면 &lt;a title=&quot;v-model&quot; href=&quot;https://v3.ko.vuejs.org/guide/migration/v-model.html&quot;&gt;v-model&lt;/a&gt;, angular에서의 데이터 바인딩을 알아보고 싶다면 &lt;a href=&quot;https://angular.io/guide/binding-syntax&quot;&gt;Binding syntax&lt;/a&gt; 을 참고하면 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;사전 지식&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Observation pattern&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes&quot;&gt;클래스&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Data Binding&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 프로그래밍에서 데이터 바인딩은 제공자와 소비자로부터 데이터 원본을 결합시켜 이것들을 동기화하는 기법이다. (위키백과)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 소비자와 제공자는 뷰와 데이터이다. 즉, 데이터와 &lt;b&gt;뷰&lt;/b&gt;를 묶는다는 뜻이다.&lt;br /&gt;웹 어플리케이션의 복잡도가 증가한다면 뷰와 데이터를 일치시키기가 어려워진다. 그래서 데이터와 뷰가 자동으로 일치하도록 묶어 두는 것이 &lt;b&gt;데이터 바인딩&lt;/b&gt;이다.&lt;br /&gt;데이터 바인딩은 다시 &lt;b&gt;단방향&lt;/b&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;2528&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXVSlt/btrg7IbUuo1/kwhmHMXgA0MJwUfqtfki10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXVSlt/btrg7IbUuo1/kwhmHMXgA0MJwUfqtfki10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXVSlt/btrg7IbUuo1/kwhmHMXgA0MJwUfqtfki10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXVSlt%2Fbtrg7IbUuo1%2FkwhmHMXgA0MJwUfqtfki10%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;2528&quot; height=&quot;1198&quot; data-origin-width=&quot;2528&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 것은 코드와 함께 알아보겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1 way, 2 way&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1초 뒤 &lt;code&gt;data&lt;/code&gt; 변수의 값이 변경되면 변경된 값을 화면 &lt;code&gt;p&lt;/code&gt; 태그에 반영하고 싶다. 이것의 코드는 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;p id=&quot;view&quot;&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;script&amp;gt;
  let data = '';
  const view = document.getElementById('view');
  setTimeout(() =&amp;gt; changeData(1), 1000);

  function changeData(newData) {
    data = newData;        // 데이터 변경
    view.innerText = data; // 변경된 데이터를 뷰에 반영
  }
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수의 값을 변경한 후에 뷰에 반영해주는 작업을 직접 해야 한다. 그렇지 않으면 값의 변경은 뷰에 반영되지 않는다.&lt;br /&gt;직접 뷰에 반영해주는 것이 뭐가 그리 문제냐고 생각할 수 있다. 하지만 데이터에 연관된 뷰가 많아질 경우를 생각해보자. 그리고 데이터가 하나가 아닌 수십수백 개가 된다면 어떤가?&lt;br /&gt;뷰와 데이터를 묶어서 복잡함을 없애보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;단방향 바인딩 (1 way)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 변경을 뷰에 반영하는 과정은 이렇다.&lt;br /&gt;&lt;b&gt;1. 뷰가 특정 데이터를 구독한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;2. 그 데이터가 변경된다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;3. 그 데이터를 구독한 모든 뷰(구독자)에게 알림을 발송한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;4. 알림을 받은(구독을 한) 뷰가 새로운 데이터로 업데이트된다.&lt;/b&gt;&lt;br /&gt;위 과정을 관찰자 패턴으로 간단하게 구현하면 다음과 같다. 예제 코드를 이해하기 위해선 &lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes&quot;&gt;클래스&lt;/a&gt;에 대한 이해가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class Data {
  constructor(값) {
    this.값 = 값;
    this.구독자들 = [];
  }

  구독(새로운_구독자) {
    this.구독자들.push(새로운_구독자);
  }

  알림_발송() {
    this.구독자들.forEach(구독자 =&amp;gt; 구독자.업데이트(this.값));
  }

  업데이트(새로운_값) {
    this.값 = 새로운_값;
    this.알림_발송();
  }
}

class View {
  constructor(뷰) {
    this.뷰 = 뷰;
  }

  업데이트(새로운_값) {
    this.뷰.innerText = 새로운_값;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 클래스를 사용해서 바인딩을 구현하겠다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const 데이터 = new Data('');
const 뷰 = new View(view);

데이터.구독(뷰);

setTimeout(() =&amp;gt; 데이터.업데이트(1), 1000);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰가 데이터를 구독한다. 그리고 1초 뒤, 데이터가 업데이트되면 뷰에 새로운 데이터가 반영된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 데이터를 업데이트 하면 수동으로 뷰를 업데이트해야 할 의무가 사라졌다. 즉, 데이터와 뷰를 묶었다.&lt;br /&gt;이제 추가적인 상황이 필요하다. 바로 아래와 같은 상황이다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;input id=&quot;inputView&quot;&amp;gt;
&amp;lt;p id=&quot;pView&quot;&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;script&amp;gt;
    const data = '';
    setTimeout(() =&amp;gt; data = 'new', 1000);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가&lt;code&gt;input&lt;/code&gt;태그에 값을 입력하면 그 값을 데이터에 반영하고 싶음과 동시에 데이터의 변경을 다시 p에 반영하고 싶다. 데이터의 변경을 뷰에 반영하는 것은 성공했으니, 뷰의 변경을 데이터에 반영해보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;양방향 바인딩 (2 way)  &lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰의 변경을 데이터에 반영하는 과정은 이렇다.&lt;br /&gt;&lt;b&gt;1. 데이터가 특정 뷰를 구독한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;2. 그 뷰가 변경된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 그 뷰를 구독한 모든 데이터(구독자)에게 알림을 발송한다.&lt;/b&gt;&lt;br /&gt;&lt;b&gt;4. 알림을 받은(구독을 한) 데이터가 업데이트 된다.&lt;/b&gt;&lt;i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 봤던 과정과 같고, 입장만 바뀐 것이다. 이를 바탕으로 View 클래스를 수정하겠다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class View {
  constructor(뷰) {
    this.뷰 = 뷰;
  }

  구독(새로운_구독자) {
    this.뷰.addEventListener('input', () =&amp;gt; {
      새로운_구독자.업데이트(this.뷰.value);
    });
  }

  업데이트(새로운_값) {
    this.뷰.innerText = 새로운_값;
    this.뷰.value = 새로운_값;
  }
}​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력을 통해 &lt;code&gt;input&lt;/code&gt;의 값을 변경하면서 3초 뒤에 데이터를 변경해보겠다. 여기서 3초 뒤에 데이터를 변경하는 이유는 데이터의 변경이 뷰에 잘 반영되는지 보기 위함이다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;input id=&quot;inputView&quot;&amp;gt;
&amp;lt;p id=&quot;pView&quot;&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;script&amp;gt;
  const 데이터 = new Data('');
  const 인풋_뷰 = new View(inputView1);
  const 피_뷰 = new View(pView);

  인풋_뷰.구독(데이터);

  데이터.구독(인풋_뷰);
  데이터.구독(피_뷰);

  setTimeout(() =&amp;gt; 데이터.업데이트('new'), 3000);
&amp;lt;/script&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-origin-width=&quot;600&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cISJR3/btrg4KnUaiS/KgYEeVzzQPYP9kNqkeoMWk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cISJR3/btrg4KnUaiS/KgYEeVzzQPYP9kNqkeoMWk/img.gif&quot; data-alt=&quot;양방향으로 데이터가 묶임&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cISJR3/btrg4KnUaiS/KgYEeVzzQPYP9kNqkeoMWk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cISJR3/btrg4KnUaiS/KgYEeVzzQPYP9kNqkeoMWk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;553&quot; height=&quot;226&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;245&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;양방향 바인딩을 구현하여 복잡도를 줄였지만, 아직 충분히 아름답지 않다. 아쉬운 점은 뷰와 데이터가 묶여있다는 것이 직관적이지 않다는 것이다. 코드를 좀 더 &lt;b&gt;선언적&lt;/b&gt;으로 변경하여 개선해보겠다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;input model=&quot;데이터1&quot;&amp;gt;
&amp;lt;input model=&quot;데이터2&quot;&amp;gt;
&amp;lt;p bind=&quot;데이터1&quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p bind=&quot;데이터1&quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p bind=&quot;데이터2&quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p bind=&quot;데이터2&quot;&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;script&amp;gt;
  const 데이터들 = {};
  데이터들.데이터1 = new Data('');
  데이터들.데이터2 = new Data('');
  const $양방향_뷰들 = document.querySelectorAll('[model]');
  const $단방향_뷰들 = document.querySelectorAll('[bind]');

  $양방향_뷰들.forEach(($양방향_뷰) =&amp;gt; {
    const 데이터_이름 = $양방향_뷰.getAttribute('model');
    const 양방향_뷰 = new View($양방향_뷰);

    양방향_뷰.구독(데이터들[데이터_이름]);
    데이터들[데이터_이름].구독(양방향_뷰);
  });

  $단방향_뷰들.forEach(($단방향_뷰) =&amp;gt; {
    const 데이터_이름 = $단방향_뷰.getAttribute('bind');
    const 단방향_뷰 = new View($단방향_뷰);
    데이터들[데이터_이름].구독(단방향_뷰);
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;bind&lt;/b&gt;는 단방향 데이터 바인딩을, &lt;b&gt;model&lt;/b&gt;은 양방향 데이터 바인딩을 의미한다. 데이터가 변경되면 어떤 뷰가 변경될지, 해당 뷰를 변경하면 어떤 데이터가 변경될지 한눈에 알 수 있다. 실행결과는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2022-03-25 at 16.15.27.gif&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;1044&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTMYPn/btrxgoCiJ2b/Dn4tEq6K2o1429KwACedVK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTMYPn/btrxgoCiJ2b/Dn4tEq6K2o1429KwACedVK/img.gif&quot; data-alt=&quot;선언적 양방향 바인딩 실행 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTMYPn/btrxgoCiJ2b/Dn4tEq6K2o1429KwACedVK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cTMYPn/btrxgoCiJ2b/Dn4tEq6K2o1429KwACedVK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1826&quot; height=&quot;1044&quot; data-filename=&quot;Screen Recording 2022-03-25 at 16.15.27.gif&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;1044&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;선언적 양방향 바인딩 실행 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 코드는 아래 저장소에서 확인할 수 있다.&lt;/p&gt;
&lt;figure id=&quot;og_1648796792822&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hyunmindev/Study_Data-Binding&quot; data-og-description=&quot;Contribute to hyunmindev/Study_Data-Binding development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hyunmindev/Study_Data-Binding&quot; data-og-url=&quot;https://github.com/hyunmindev/Study_Data-Binding&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UAnYV/hyNScS1Ea3/XxJKVR1HDkUKWxHUcAkjU0/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202&quot;&gt;&lt;a href=&quot;https://github.com/hyunmindev/Study_Data-Binding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hyunmindev/Study_Data-Binding&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UAnYV/hyNScS1Ea3/XxJKVR1HDkUKWxHUcAkjU0/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hyunmindev/Study_Data-Binding&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to hyunmindev/Study_Data-Binding development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%B0%94%EC%9D%B8%EB%94%A9&quot;&gt;https://ko.wikipedia.org/wiki/데이터_바인딩&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/13504906/what-is-two-way-binding&quot;&gt;https://stackoverflow.com/questions/13504906/what-is-two-way-binding&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://blog.jeremylikness.com/blog/client-side-javascript-databinding-without-a-framework/&quot;&gt;https://blog.jeremylikness.com/blog/client-side-javascript-databinding-without-a-framework/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/JavaScript</category>
      <category>JavaScript</category>
      <category>자바스크립트</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/15</guid>
      <comments>https://hyunmindev.tistory.com/15#entry15comment</comments>
      <pubDate>Thu, 7 Oct 2021 17:55:37 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트의 Promise 직접 구현하기</title>
      <link>https://hyunmindev.tistory.com/14</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.001.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cynqWg/btrg5DuXXo2/SblWFhHPqqSIu6INfgiRl1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cynqWg/btrg5DuXXo2/SblWFhHPqqSIu6INfgiRl1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cynqWg/btrg5DuXXo2/SblWFhHPqqSIu6INfgiRl1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcynqWg%2Fbtrg5DuXXo2%2FSblWFhHPqqSIu6INfgiRl1%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;1920&quot; height=&quot;1080&quot; data-filename=&quot;JS.001.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 줄 안다는 것과 이해했다는 것은 차이가 있다. 이번 포스트에서 Promise 객체를 직접 구현해보며 이해하도록 하겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;사전 지식&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;b&gt;Promise&lt;/b&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Classes&quot;&gt;Classes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;요구사항&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. resolve, reject&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;new Promise((resolve, reject) =&amp;gt; {
  //...
})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. then, catch, finally&lt;/h4&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;doSome()
  .then(() =&amp;gt; {})
  .catch(() =&amp;gt; {})
  .finally(() =&amp;gt; {})&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. state&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise는 다음 중 하나의 상태를 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대기(pending): 이행하거나 거부되지 않은 초기 상태.&lt;/li&gt;
&lt;li&gt;이행(fulfilled): 연산이 성공적으로 완료됨.&lt;/li&gt;
&lt;li&gt;거부(rejected): 연산이 실패함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. chaining&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;doFirst()
  .then(firstResult =&amp;gt; doSecond(firstResult))
  .then(secondResult =&amp;gt; doFinal(secondResult))
  .then(finalResult =&amp;gt; {
    console.log(`Got the final result: ${finalResult}`);
  })
  .catch(failureCallback);&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;1. Simplest 프로미스&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;class Promise {
  constructor(callback) {
    callback((value) =&amp;gt; {
      this.value = value;
    });
  }

  then(callback) {
    callback(this.value);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상에서 가장 간단한 프로미스 클래스다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function myFunc() {
  return new Promise((resolve) =&amp;gt; {
    resolve('my resolve');
  });
}

myFunc().then((result) =&amp;gt; console.log(result)); // my resolve&lt;/code&gt;&lt;/pre&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;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;2. Simpler 프로미스&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;class Promise {
  constructor(callback) {
    const resolve = (value) =&amp;gt; {
      this.value = value;
    };
    const reject = (value) =&amp;gt; {
      this.value = value;
    };
    callback(resolve, reject);
  }

  then(callback) {
    callback(this.value);
  }

  catch(callback) {
    callback(this.value);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;reject&lt;/code&gt;를 추가했다. 바로 다음 단계로 넘어가겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;3. Simple 프로미스&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class Promise {
  constructor(callback) {
    this.state = 'pending';

    const resolve = (value) =&amp;gt; {
      this.state = 'fulfilled';
      this.value = value;
    };
    const reject = (value) =&amp;gt; {
      this.state = 'rejected';
      this.value = value;
    };
    callback(resolve, reject);
  }

  then(callback) {
    if (this.state === 'fulfilled') {
      callback(this.value);
    }
    return this;
  }

  catch(callback) {
    if (this.state === 'rejected') {
      callback(this.value);
    }
    return this;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;pending&lt;/code&gt;, &lt;code&gt;fulfilled&lt;/code&gt;, &lt;code&gt;rejected&lt;/code&gt; 상태를 추가했다. 그리고 &lt;code&gt;then&lt;/code&gt;과 &lt;code&gt;catch&lt;/code&gt; 메소드에서 &lt;code&gt;this&lt;/code&gt;를 리턴한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 아래와 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function myResolve() {
  return new Promise((resolve, reject) =&amp;gt; {
    resolve('my resolve');
  });
}

function myReject() {
  return new Promise((resolve, reject) =&amp;gt; {
    reject('my reject');
  });
}

myResolve()
    .then((result) =&amp;gt; console.log(result)) // my resolve
    .catch((result) =&amp;gt; console.log(result));

myReject()
    .then((result) =&amp;gt; console.log(result))
    .catch((result) =&amp;gt; console.log(result)); // my reject&lt;/code&gt;&lt;/pre&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;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;4. 비동기 지원 프로미스&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;function myResolve() {
  return new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; resolve('my resolve'), 1000);
  });
}

myResolve()
    .then((result) =&amp;gt; console.log(result))
    .catch((result) =&amp;gt; console.log(result));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 실행하면 아무것도 출력되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1초 뒤 생성자에서 &lt;code&gt;resolve&lt;/code&gt; 함수가 실행되어 &lt;code&gt;fulfilled&lt;/code&gt; 상태로 변경되지만, 이미 &lt;code&gt;then&lt;/code&gt;함수를 호출한 뒤의 이야기다. 즉, &lt;code&gt;resolve&lt;/code&gt;가 &lt;code&gt;then&lt;/code&gt; 보다 늦게 실행된다는 점이 문제를 일으킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 보완하겠다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class Promise {
  constructor(callback) {
    this.state = 'pending';
    this.onFulfilledCallback = null;
    this.onRejectedCallback = null;
    const resolve = (value) =&amp;gt; {
      this.state = 'fulfilled';
      this.value = value;
      if (this.onFulfilledCallback !== null) {
        this.onFulfilledCallback(value);
      }
    };
    const reject = (value) =&amp;gt; {
      this.state = 'rejected';
      this.value = value;
      if (this.onRejectedCallback !== null) {
        this.onRejectedCallback(value);
      }
    };
    callback(resolve, reject);
  }

  then(callback) {
    if (this.state === 'pending') { //  
      this.onFulfilledCallback = callback;
    }
    if (this.state === 'fulfilled') {
      callback(this.value);
    }
    return this;
  }

  catch(callback) {
    if (this.state === 'pending') { //  
      this.onRejectedCallback = callback;
    }
    if (this.state === 'rejected') {
      callback(this.value);
    }
    return this;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;pending&lt;/code&gt; 상태일 때 콜백 함수를 멤버 변수에 저장한다. 그리고, 비동기 처리 후 &lt;code&gt;resolve&lt;/code&gt; 또는 &lt;code&gt;reject&lt;/code&gt;가 호출되면 콜백을 실행하도록 변경했다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function myResolve() {
  return new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; resolve('my resolve'), 1000);
  });
}

myResolve()
    .then((result) =&amp;gt; console.log(result)); // my resolve&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1초 뒤 콜백들이 잘 실행 되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 가지 기능을 더 추가해보자.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;5. 체이닝 지원 프로미스&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;myResolve()
    .then((result) =&amp;gt; `next ${result}`)
    .then((result) =&amp;gt; console.log(result)) // next my resolve&lt;/code&gt;&lt;/pre&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 class=&quot;javascript&quot;&gt;&lt;code&gt;  then(callback) {
    return new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onFulfilledCallback = () =&amp;gt; {
          const result = callback(this.value);
          resolve(result);
        };
      }
      if (this.state === 'fulfilled') {
        const result = callback(this.value);
        resolve(result);
      }
    });
  }

  catch(callback) {
    return new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onRejectedCallback = () =&amp;gt; {
          const result = callback(this.value);
          resolve(result);
        };
      }
      if (this.state === 'rejected') {
        const result = callback(this.value);
        resolve(result);
      }
    });
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;then&lt;/code&gt;과 &lt;code&gt;catch&lt;/code&gt; 메소드에서 새로운 프로미스 객체를 반환함으로써 체이닝이 가능해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환하는 프로미스 객체의 &lt;code&gt;resolve&lt;/code&gt; 또는 &lt;code&gt;reject&lt;/code&gt;에 이전 콜백 함수의 결괏값을 넣는 것이 핵심이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;catch&lt;/code&gt; 메소드 에서 &lt;code&gt;reject&lt;/code&gt;가 아닌 &lt;code&gt;resolve&lt;/code&gt;를 호출한 것에 의문을 품을 수 있다. 실제 프로미스 객체의 프로미스 체이닝 작동방식을 보면 &lt;code&gt;catch&lt;/code&gt; 뒤의 &lt;code&gt;then&lt;/code&gt; 콜백이 실행되는 것을 볼 수 있다. 그 부분과 똑같이 작동하기 위해서는 &lt;code&gt;catch&lt;/code&gt;에서 &lt;code&gt;resolve&lt;/code&gt;를 호출해야 한다. (이 부분은 현재 문제가 있다. 7번 과정에서 해결된다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 다 왔다. 몇 가지 문제점을 더 해결할 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;6. 비동기 체이닝 지원 프로미스&lt;/b&gt;&lt;/h2&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 class=&quot;coffeescript&quot;&gt;&lt;code&gt;getUserId(username)
    .then((id) =&amp;gt; {
      return getUserAge(id);
    })
    .then((age) =&amp;gt; console.log(username + ' is ' + age));&lt;/code&gt;&lt;/pre&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;pre class=&quot;javascript&quot;&gt;&lt;code&gt;  then(callback) {
    return new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onFulfilledCallback = () =&amp;gt; {
          this.handleCallback(callback, resolve);
        };
      }
      if (this.state === 'fulfilled') {
        this.handleCallback(callback, resolve);
      }
    });
  }

  catch(callback) {
    return new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onRejectedCallback = () =&amp;gt; {
          this.handleCallback(callback, resolve);
        };
      }
      if (this.state === 'rejected') {
        this.handleCallback(callback, resolve);
      }
    });
  }

  handleCallback(callback, resolve, reject) { //  
    const result = callback(this.value);
    if (result instanceof Promise) {
      result.then(resolve);
    } else {
      resolve(result);
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;instaceof&lt;/code&gt; 함수를 통해 콜백의 결과가 프로미스 객체이면 객체의 &lt;code&gt;then&lt;/code&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;code&gt;then&lt;/code&gt;을 호출한다는 것이다. 이 부분을 수정해서 &lt;code&gt;handleCallback&lt;/code&gt; 메소드를 다시 작성하겠다.&lt;/p&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;  handleCallback(callback, resolve, reject) { //  
    const result = callback(this.value);
    if (result instanceof Promise) {
      if (result.state === 'fulfilled') {
        result.then(resolve);
      }
      if (result.state === 'rejected') {
        result.catch(reject);
      }
      if (result.state === 'pending') {
        result.onFulfilledCallback = () =&amp;gt; result.then(resolve);
        result.onRejectedCallback = () =&amp;gt; result.catch(reject);
      }
    } else {
      resolve(result);
    }
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주안점은 &lt;code&gt;pending&lt;/code&gt; 상태일 경우, 실행해야할 함수를 &lt;code&gt;result&lt;/code&gt; 인스턴스에 저장했다가 실행한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로미스 객체의 핵심 기능을 모두 구현했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  7. 해치웠나?&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx7VWm/btrgclU90we/IYkHOFiGUD9WPEUClkaP90/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx7VWm/btrgclU90we/IYkHOFiGUD9WPEUClkaP90/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx7VWm/btrgclU90we/IYkHOFiGUD9WPEUClkaP90/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bx7VWm/btrgclU90we/IYkHOFiGUD9WPEUClkaP90/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;576&quot; height=&quot;323&quot; data-origin-width=&quot;576&quot; data-origin-height=&quot;323&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;b&gt;첫 번째&lt;/b&gt;로, &lt;code&gt;reject&lt;/code&gt;의 고장이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;then&lt;/code&gt;과 &lt;code&gt;catch&lt;/code&gt;를 호출할 때마다 새로운 프로미스 인스턴스가 만들어진다. 그리고 1초 뒤 첫 번째 인스턴스에서 &lt;code&gt;reject&lt;/code&gt;를 호출하기 때문에 마지막 인스턴스의 콜백은 당연히 실행되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 현재 인스턴스에서 실행할 콜백이 없을 시 &lt;b&gt;fall through&lt;/b&gt; 하도록 해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 동기적 프로미스도 위와 같은 이유로 &lt;b&gt;fall through&lt;/b&gt; 기능이 필요하다. 해당 부분을 다음과 같이 수정했다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;  resolve = (value) =&amp;gt; {
    if (this.state === 'pending') {
      this.state = 'fulfilled';
      this.value = value;
      if (this.onFulfilledCallback !== null) {
        this.onFulfilledCallback(value);
      } else {
        this.child?.resolve(value); //  
      }
    }
  };

  reject = (value) =&amp;gt; {
    if (this.state === 'pending') {
      this.state = 'rejected';
      this.value = value;
      if (this.onRejectedCallback !== null) {
        this.onRejectedCallback();
      } else {
        this.child?.reject(value); //  
      }
    }
  };

  then(callback) {
    this.child = new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onFulfilledCallback = () =&amp;gt; {
          this.handleCallback(callback, resolve, reject);
        };
      }
      if (this.state === 'fulfilled') {
        this.handleCallback(callback, resolve, reject);
      }
      if (this.state === 'rejected') { //  
        reject(this.value);
      }
    });
    return this.child;
  }

  catch(callback) {
    this.child = new Promise((resolve, reject) =&amp;gt; {
      if (this.state === 'pending') {
        this.onRejectedCallback = () =&amp;gt; {
          this.handleCallback(callback, resolve, reject);
        };
      }
      if (this.state === 'rejected') {
        this.handleCallback(callback, resolve, reject);
      }
      if (this.state === 'fulfilled') { //  
        resolve(this.value);
      }
    });
    return this.child;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 번째&lt;/b&gt;로, 콜백에서의 예외 발생이다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;myResolve()
    .then((result) =&amp;gt; {
      return 'next ' + result;
    })
    .then((result) =&amp;gt; {
      throw 'error';
    })
    .catch((error) =&amp;gt; {
      console.error(error);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 콜백 내부 예외 상황을 지원하기 위해, &lt;code&gt;handleCallback&lt;/code&gt; 메소드에 &lt;code&gt;try catch&lt;/code&gt;를 추가했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;세 번째&lt;/b&gt;로, 한 인스턴스에 여러개의 콜백이 있을 경우이다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const promise = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; resolve('first'), 1000);
});

promise
    .then((result) =&amp;gt; {
      console.log('1', result);
    });
promise
    .then((result) =&amp;gt; {
      console.log('2', result);
    });
promise
    .then((result) =&amp;gt; {
      console.log('3', result);
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러개의 콜백을 실행하기 위해 기존에 변수로 저장하던 콜백을 배열로 변경했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  &lt;b&gt;8. 마무리 작업&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 만든 프로미스 객체를 마무리하기 위해 아래와 같은 과정을 거치겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;code&gt;finally&lt;/code&gt; 메소드 추가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 접근 제한자 추가&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;최종 코드&lt;/h4&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&gt;&lt;code&gt;export default class Promise {
  #value = null;
  #state = 'pending';
  #child = null;
  #onFulfilledCallbacks = [];
  #onRejectedCallbacks = [];
  #onFinallyCallbacks = [];

  constructor(callback) {
    callback(this.#resolve, this.#reject);
  }

  #resolve = (value) =&amp;gt; {
    if (this.#state === 'pending') {
      this.#state = 'fulfilled';
      this.#value = value;
      this.#onFinallyCallbacks.forEach((callback) =&amp;gt; callback());
      if (this.#onFulfilledCallbacks.length !== 0) {
        this.#onFulfilledCallbacks.forEach((callback) =&amp;gt; callback(value));
      } else {
        this.#child?.#resolve(value);
      }
    }
  };

  #reject = (value) =&amp;gt; {
    if (this.#state === 'pending') {
      this.#state = 'rejected';
      this.#value = value;
      this.#onFinallyCallbacks.forEach((callback) =&amp;gt; callback());
      if (this.#onRejectedCallbacks.length !== 0) {
        this.#onRejectedCallbacks.forEach((callback) =&amp;gt; callback(value));
      } else {
        this.#child?.#reject(value);
      }
    }
  };

  then(callback) {
    this.#child = new Promise((resolve, reject) =&amp;gt; {
      if (this.#state === 'pending') {
        this.#onFulfilledCallbacks.push(() =&amp;gt; {
          this.#handleCallback(callback, resolve, reject);
        });
      }
      if (this.#state === 'fulfilled') {
        this.#handleCallback(callback, resolve, reject);
      }
      if (this.#state === 'rejected') {
        reject(this.#value);
      }
    });
    return this.#child;
  }

  catch(callback) {
    this.#child = new Promise((resolve, reject) =&amp;gt; {
      if (this.#state === 'pending') {
        this.#onRejectedCallbacks.push(() =&amp;gt; {
          this.#handleCallback(callback, resolve, reject);
        });
      }
      if (this.#state === 'rejected') {
        this.#handleCallback(callback, resolve, reject);
      }
      if (this.#state === 'fulfilled') {
        resolve(this.#value);
      }
    });
    return this.#child;
  }

  finally(callback) {
    this.#child = new Promise((resolve, reject) =&amp;gt; {
      if (this.#state === 'pending') {
        this.#onFinallyCallbacks.push(() =&amp;gt; {
          this.#handleCallback(callback, resolve, reject);
        });
      }
      if (this.#state === 'fulfilled' || this.#state === 'rejected') {
        this.#handleCallback(callback, resolve, reject);
      }
    });
    return this.#child;
  }

  #handleCallback(callback, resolve, reject) {
    try {
      const result = callback(this.#value);
      if (result instanceof Promise) {
        if (result.#state === 'fulfilled') {
          result.then(resolve);
        }
        if (result.#state === 'rejected') {
          result.catch(reject);
        }
        if (result.#state === 'pending') {
          result.#onFulfilledCallbacks.push(() =&amp;gt; result.then(resolve));
          result.#onRejectedCallbacks.push(() =&amp;gt; result.catch(reject));
        }
      } else {
        resolve(result);
      }
    } catch (error) {
      reject(error);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&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;figure id=&quot;og_1648796993501&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hyunmindev/Web_Promise: 프로미스 객체를 직접 구현&quot; data-og-description=&quot;프로미스 객체를 직접 구현. Contribute to hyunmindev/Web_Promise development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hyunmindev/Study_Promise&quot; data-og-url=&quot;https://github.com/hyunmindev/Web_Promise&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bDga1N/hyNR99QJQN/cQBdAzFFhczXqj3VGN1qr0/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202&quot;&gt;&lt;a href=&quot;https://github.com/hyunmindev/Study_Promise&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hyunmindev/Study_Promise&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bDga1N/hyNR99QJQN/cQBdAzFFhczXqj3VGN1qr0/img.png?width=1200&amp;amp;height=600&amp;amp;face=969_129_1036_202');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hyunmindev/Web_Promise: 프로미스 객체를 직접 구현&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;프로미스 객체를 직접 구현. Contribute to hyunmindev/Web_Promise development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/stefanpenner/es6-promise&quot;&gt;https://github.com/stefanpenner/es6-promise&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://medium.com/swlh/implement-a-simple-promise-in-javascript-20c9705f197a&quot;&gt;https://medium.com/swlh/implement-a-simple-promise-in-javascript-20c9705f197a&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/JavaScript</category>
      <category>JavaScript</category>
      <category>js</category>
      <category>promise</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/14</guid>
      <comments>https://hyunmindev.tistory.com/14#entry14comment</comments>
      <pubDate>Mon, 20 Sep 2021 20:45:36 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차</title>
      <link>https://hyunmindev.tistory.com/13</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;back.jpeg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k4DxK/btrfBrIAlUI/x5rFMN3l52yQs7ZR1knlV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k4DxK/btrfBrIAlUI/x5rFMN3l52yQs7ZR1knlV0/img.jpg&quot; data-alt=&quot;스프린트 마무리 후 등산&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k4DxK/btrfBrIAlUI/x5rFMN3l52yQs7ZR1knlV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk4DxK%2FbtrfBrIAlUI%2Fx5rFMN3l52yQs7ZR1knlV0%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;585&quot; height=&quot;438&quot; data-filename=&quot;back.jpeg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프린트 마무리 후 등산&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1648797162591&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/9&quot; data-og-url=&quot;https://blog.hyunmin.dev/9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RHzhf/hyNR3ofXOt/z28botbDIXBJcpQJpekfqk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/6gUTE/hyNTrui2MI/U1dmQbsvXS8xZvOXGQUsy0/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cKcpvu/hyNTstc3za/clXxjVZipgUn33IDOd02EK/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RHzhf/hyNR3ofXOt/z28botbDIXBJcpQJpekfqk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/6gUTE/hyNTrui2MI/U1dmQbsvXS8xZvOXGQUsy0/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cKcpvu/hyNTstc3za/clXxjVZipgUn33IDOd02EK/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024');&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트캠프 멤버십은 학습 스프린트 8주, 그룹 프로젝트 6주 총 14주간의 과정이다.&lt;br /&gt;학습 스프린트는 2주를 주기로 총 네 번의 스프린트가 진행된다.&lt;br /&gt;스프린트는 애자일의 다양한 개발 방법론 중 가장 대표적인 스크럼에서 개발 주기를 뜻한다.&lt;br /&gt;두 번째 스프린트가 마무리됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  일정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 여유로웠던 1회 차 스프린트를 지나고, 자신감에 차 있었다. 2회 차 스프린트를 하며 그것이 교만함이었다는 사실을 깨달았다. 매번 나의 교만함을 짓밟는 커리큘럼을 만들어주신 부스트캠프 운영진과 마스터님들, 이 글을 빌려 감사의 말씀을 전한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주 차에는 정신적으로 약해졌었다. 추석 연휴라는 한 줄기의 빛만 보고 묵묵히 버텼다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  미션&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;CSR&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR과 세트로 따라왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평소 진행하던 프로젝트가 Vue.js와 React로 CSR을 만드는 것이었기 때문에 이전 스프린트보다 더 친숙하게 접근했다. 그러나 상속, 디자인 패턴 등 다양한 배경지식이 필요했고 얕게만 알고 있던 지식이 전부 들통났다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현 vs 학습&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프린트 내도록 나를 괴롭혔던 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배경지식을 학습하면 좀 더 단단하고 빠르게 개발할 수 있겠지만, 그 시간만큼 구현할 시간이 줄어든다. 이 고민은 마치 '배럭 하나를 더 지을까? 그 미네랄로 마린 세 마리를 뽑을까?'와 같은 고민이었다. 2주라는 한정된 시간 동안 타협점을 찾는 것이 축구공 위에 올라서서 균형 잡는 느낌이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'이번 미션의 목표는 미션에 실패하는 것이다.'라고 말한 한 캠퍼의 말이 기억에 남는다. 역설적인 이 말에서 나만의 정답을 찾을 수 있었다. 미션의 목표를 '개발 완성'을 넘어 '성장'으로 변경하면 답은 간단했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Webpack&lt;/b&gt;&lt;/h4&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;/b&gt;이었고, 스프린트 미션에 잘 비벼있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비빔밥을 한번 먹어보니까, 웬만하면 편식하지 않는 것이 이롭다는 생각을 할 수 있었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트캠프가 지옥이라는 말은 아니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;b&gt;  마무리&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추석 연휴 한 주간 부스트캠프 일정이 없다. 잘 쉬고, 부족했던 부분을 보충해서 추진력을 얻도록 하겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음 글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1648797185736&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/17&quot; data-og-url=&quot;https://blog.hyunmin.dev/17&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bgsde2/hyNTvjbmpN/K4Jaa4HDazAAjEIoC55Xj0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/dl4TE5/hyNTyfSUgb/jJPXcHOu9vOG1yWC13yIPK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/WX4Cg/hyNTy1hAp0/GAa1l8DAMNbWtdY4cOYwHK/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/17&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bgsde2/hyNTvjbmpN/K4Jaa4HDazAAjEIoC55Xj0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/dl4TE5/hyNTyfSUgb/jJPXcHOu9vOG1yWC13yIPK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/WX4Cg/hyNTy1hAp0/GAa1l8DAMNbWtdY4cOYwHK/img.jpg?width=1080&amp;amp;height=1440&amp;amp;face=0_0_1080_1440');&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 3회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차 부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/13</guid>
      <comments>https://hyunmindev.tistory.com/13#entry13comment</comments>
      <pubDate>Mon, 20 Sep 2021 18:45:23 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트의 bind, call, apply</title>
      <link>https://hyunmindev.tistory.com/11</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JS.003.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceUIwG/btrg1XOLP7O/HHimyxZCvs6kTxu5uWlvN0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceUIwG/btrg1XOLP7O/HHimyxZCvs6kTxu5uWlvN0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceUIwG/btrg1XOLP7O/HHimyxZCvs6kTxu5uWlvN0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceUIwG%2Fbtrg1XOLP7O%2FHHimyxZCvs6kTxu5uWlvN0%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;1920&quot; height=&quot;1080&quot; data-filename=&quot;JS.003.jpeg&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트의 함수는 함수처럼, 객체처럼, 객체 지향의 생성자처럼 동작하며, 함수에 붙어있는 프로토타입 객체를 통해 공통되는 메소드를 공유한다. 즉, 함수에서 사용할 수 있는 메소드가 있다. 이번 포스팅은 그중 bind, call, apply에 관한 정리이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  this&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;class Five {
  constructor() {
    this.number = 5;
  }

  printNumber() {
    console.log(this.number);
  }
}&lt;/code&gt;&lt;/pre&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 class=&quot;reasonml&quot;&gt;&lt;code&gt;const five = new Five();
five.printNumber(); // 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 다음과 같은 상황일 때도 같은 결과인지 한번 생각해보자.&lt;/p&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;const five = new Five();
const printFive = five.printNumber;
printFive(); // Cannot read property 'number' of undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 변수에 전달하고 호출했을 뿐인데 실행결과가 다르다. 이는 &lt;code&gt;printFive&lt;/code&gt; 변수에 &lt;code&gt;printNumber&lt;/code&gt; 함수가 객체에서 분리되어 전달되었기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체에서 분리되었기 때문에 &lt;code&gt;printFive&lt;/code&gt; 함수 실행에서 &lt;code&gt;this&lt;/code&gt;는 &lt;code&gt;undefined&lt;/code&gt;이다. &lt;code&gt;number&lt;/code&gt; 변수가 있을 리가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀 더 범용적인 예시를 들겠다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const five = new Five();
setTimeout(five.printNumber, 0); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Node.js 환경에서 &lt;code&gt;printNumber&lt;/code&gt; 함수 내의 &lt;code&gt;this&lt;/code&gt;는 &lt;code&gt;Timeout&lt;/code&gt; 객체이다. 마찬가지로 &lt;code&gt;number&lt;/code&gt; 변수를 기대하기 힘들다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 전달할 때, this(컨텍스트)를 사라지지 않게 하려면 어떤 방법이 있을까.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  bind&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 함수는 &lt;code&gt;this&lt;/code&gt;를 수정하게 해주는 내장 메서드 bind를 제공한다. 기본 문법은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;const boundFunc = func.bind(context);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에서 내포하듯 &lt;code&gt;bind&lt;/code&gt; 함수는 묶어준다. 무엇과 무엇을 묶냐면 &lt;code&gt;func&lt;/code&gt; 함수에서의 &lt;code&gt;this&lt;/code&gt;와 &lt;code&gt;bind&lt;/code&gt;의 파라미터인 &lt;code&gt;context&lt;/code&gt;를 묶는다.&amp;nbsp;즉, &lt;code&gt;boundFunc&lt;/code&gt; 함수에서의 &lt;code&gt;this&lt;/code&gt;는 &lt;code&gt;context&lt;/code&gt;가 된다.&amp;nbsp;이전의 예시로 다시 살펴보겠다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;const five = new Five();
const printFive = five.printNumber.bind(five);
printFive() // 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;printNumber&lt;/code&gt;내의 &lt;code&gt;this&lt;/code&gt;를 five로 고정됐기 때문에 &lt;code&gt;printFive&lt;/code&gt; 함수를 호출하면 &lt;code&gt;five&lt;/code&gt; 객체 값인 5가 출력된다.&amp;nbsp;물론 &lt;code&gt;setTimeout&lt;/code&gt;에도 bind 된 함수를 전달할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const five = new Five();
const printFive = five.printNumber.bind(five);
setTimeout(printFive, 1000); // 5

five.printNumber = function() {
  console.log(4);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 함수가 변경되어도 변경 이전의 함수를 실행하는 것을 볼 수 있다.&lt;/p&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;function printNumber(name) {
  console.log(name, this.number);
}

printNumber('hyunmin'); // hyunmin undefined

const printFive = printNumber.bind({number: 5});
printFive('hyunmin') // hyunmin 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;printNumber&lt;/code&gt; 함수에 &lt;code&gt;{number: 5}&lt;/code&gt; 객체를 바인딩했고, 바인딩된 함수 &lt;code&gt;printFive&lt;/code&gt; 함수를 호출할 때 파라미터로 hyunmin을 넘기면 &lt;code&gt;hyunmin 5&lt;/code&gt;를 출력한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;☎️ call, apply&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;function printNumber() {
  console.log(this.number);
}

printNumber.bind({number: 5})(); // (1)
printNumber.call({number: 5});   // (2)
printNumber.apply({number: 5});  // (3)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(1)&lt;/b&gt;, &lt;b&gt;(2)&lt;/b&gt;, &lt;b&gt;(3)&lt;/b&gt; 실행 결과가 모두 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;call&lt;/code&gt;과 &lt;code&gt;apply&lt;/code&gt;는 함수를 즉시 실행다는 것에 &lt;code&gt;bind&lt;/code&gt;와 차이가 있다. 함수가 나중에 사용되어야 한다면 &lt;code&gt;bind&lt;/code&gt; 그 외에는 &lt;code&gt;call&lt;/code&gt;과 &lt;code&gt;apply&lt;/code&gt;를 쓸 수 있다. &lt;code&gt;call&lt;/code&gt; 과 &lt;code&gt;apply의&lt;/code&gt; 근본적인 차이점은 &lt;code&gt;call&lt;/code&gt;은 함수 함수에 전달될 인수 리스트를 받는 데 비해, &lt;code&gt;apply&lt;/code&gt;는 인수들의 단일 배열을 받는다는 점이다.&amp;nbsp;이게 무슨 말인지는 다음 예제를 보면 알 수 있다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;function printNumber(first, second, third) {
  console.log(this.number, first, second, third);
}

printNumber.call({number: 5}, 1, 2, 3);
printNumber.apply({number: 5}, [1, 2, 3]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'이 정도로 친절하다고?'라는 생각이 든다. 상황에 따라서 유용하게 나눠 쓸 수 있겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;ℹ️ tip&lt;/b&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두 번 bind 하면?&lt;/h4&gt;
&lt;pre class=&quot;fortran&quot;&gt;&lt;code&gt;function printNumber() {
  console.log(this.number);
}

const printFive = printNumber.bind({number: 5}).bind({number: 444});
printFive() // 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한번 묶인 함수는 처음 묶였을 그 당시의 컨텍스트만 기억한다. 즉, 한번 bind 하면 다시 bind 할 수 없다.&amp;nbsp;bind의 바람기 없는 면모를 확인할 수 있는 부분이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;bind 함수의 프로퍼티?&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function printNumber() {
  console.log(this.number);
}
printNumber.user = 'hyunmin';
console.log(printNumber.user); // hyunmin

const printFive = printNumber.bind({number: 5});
console.log(printFive.user); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bind를 적용하면 또 다른 객체가 반환된다. 새로운 객체엔 user 프로퍼티가 없으므로 undefined가 출력된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  참조&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/bind&quot;&gt;https://ko.javascript.info/bind&lt;/a&gt;&lt;/p&gt;</description>
      <category>Web/JavaScript</category>
      <category>apply</category>
      <category>bind</category>
      <category>Call</category>
      <category>function</category>
      <category>JavaScript</category>
      <category>js</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/11</guid>
      <comments>https://hyunmindev.tistory.com/11#entry11comment</comments>
      <pubDate>Sat, 11 Sep 2021 15:39:47 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차</title>
      <link>https://hyunmindev.tistory.com/9</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&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/MUQVw/btrd0X4qDGK/iKHNN9VWwCWWcoU0567ul1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MUQVw/btrd0X4qDGK/iKHNN9VWwCWWcoU0567ul1/img.jpg&quot; data-alt=&quot;스프린트 1회차&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MUQVw/btrd0X4qDGK/iKHNN9VWwCWWcoU0567ul1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMUQVw%2Fbtrd0X4qDGK%2FiKHNN9VWwCWWcoU0567ul1%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;548&quot; height=&quot;411&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프린트 1회차&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1648797373827&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;부스트캠프 웹 풀스택 6기 멤버십 합격&quot; data-og-description=&quot;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/8&quot; data-og-url=&quot;https://blog.hyunmin.dev/8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bavuUG/hyNTwWGmPP/TSQwcIu0IPoGtG1jfjUKu0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/plWbi/hyNTstdgVw/xGMuJMvGPAXVeQEHkLa3SK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bPNQFk/hyNTy71XRx/ojrh9JBU7SAWZb3QabcXNK/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bavuUG/hyNTwWGmPP/TSQwcIu0IPoGtG1jfjUKu0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/plWbi/hyNTstdgVw/xGMuJMvGPAXVeQEHkLa3SK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bPNQFk/hyNTy71XRx/ojrh9JBU7SAWZb3QabcXNK/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&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;부스트캠프 웹 풀스택 6기 멤버십 합격&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트캠프 멤버십은 학습 스프린트 8주, 그룹 프로젝트 6주 총 14주간의 과정이다.&amp;nbsp;학습 스프린트는 2주를 주기로 총 네 번의 스프린트가 진행된다.&amp;nbsp;첫 번째 스프린트가 마무리됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  일정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챌린지와 비교했을 때 상대적으로 일정이 여유로워졌다. 일정표에 점심시간이 생겼고, 그룹 회의도 이르면 11시에 끝나기 때문이다. 무엇보다도 개발 주기가 하루에서 2주로 늘어나면서 심리적 여유도 생겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매주 스터디 그룹이 배정되고 첫 주차 월요일 아침에 그룹원들과 만나서 간단하게 인사를 나누고, 함께 &lt;b&gt;과제를 분석&lt;/b&gt;한다. 그리고 다음 날 아침부터는 오전 10시에 만나 &lt;b&gt;스크럼 회의&lt;/b&gt;를 진행한다. 월요일과 수요일 오후 한 시부터는 &lt;b&gt;마스터님들의 수업&lt;/b&gt;이 있다. 금요일에는 두 그룹이 함께 &lt;b&gt;한 주를 리뷰&lt;/b&gt;하고 마무리한다. 위 일정을 제외하면 전부 개발 시간이다.코딩 테스트를 대비하기 위해 체크인 하기 전에 한 시간 동안 알고리즘 스터디도 시작했다. 그리고 오후 7시가 되면 무조건 운동하는 것으로 일정을 잡았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  미션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챌린지의 미션은 CS 지식을 기반으로 했다면, 멤버십의 미션은 실제 프로덕트를 만들어내는 프로젝트이다.&lt;br /&gt;미션은 외부 프레임워크나 라이브러리를 사용하지 않는 바닐라JS로 SSR 을 만들어내는 것이었다. 기획서와 디자인이 figma로 공유됐다. 현업에서 하는 방식과 최대한 유사하게 진행하고자 한다고 말씀하셨다.&lt;br /&gt;평소에 React나 Vue를 활용해서 웹 개발은 해봤지만 바닐라JS로 웹 개발은 처음이었다. 미션을 하면서 다시금 깨달은 것은 정말, 리액트와 뷰는 위대한 모듈이다. 물론 사용 편의성만 놓고 본다면 말이다.&lt;br /&gt;기능을 구현하며 다양한 DOM API와 window 객체를 사용했고, 이로 인해 웹의 근원적인 부분을 들여다볼 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주짜리 프로젝트를 하루 단위로 썰었다. 그리고 매일 그 썰린 것들을 해치워나갔다. 하지만, 허술했다. 일별 계획은 당연히 필요하고, 시간 단위 계획도 필요하다는 것을 느꼈다.&lt;br /&gt;다음 스프린트에서는 오전에는 리팩토링 및 최적화 오후에는 기능개발을 하려 한다. 또한 구현해야 할 기능을 전부 GitHub issue로 등록하고, commit 할 때 issue를 종료하는 식으로 진행할 계획이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음 글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1648798113640&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 &quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/13&quot; data-og-url=&quot;https://blog.hyunmin.dev/13&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bU93xn/hyNR8JSRO5/ackQS6Mup10m6hQqeBYyc1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bzGi9H/hyNTxuxtfZ/2iAruK07KsAN0ZnldbqPok/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/DZ030/hyNTukhyt8/tW8EbNRw6aYsOfPxqanCK1/img.jpg?width=960&amp;amp;height=720&amp;amp;face=0_0_960_720&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/13&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bU93xn/hyNR8JSRO5/ackQS6Mup10m6hQqeBYyc1/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bzGi9H/hyNTxuxtfZ/2iAruK07KsAN0ZnldbqPok/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/DZ030/hyNTukhyt8/tW8EbNRw6aYsOfPxqanCK1/img.jpg?width=960&amp;amp;height=720&amp;amp;face=0_0_960_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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 2회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차 부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>멤버십</category>
      <category>부스트캠프</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/9</guid>
      <comments>https://hyunmindev.tistory.com/9#entry9comment</comments>
      <pubDate>Sat, 4 Sep 2021 18:12:46 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 멤버십 합격</title>
      <link>https://hyunmindev.tistory.com/8</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JPEG image-B3FE3FA785DF-1.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c9JseK/btrcM0uuLSR/yxb7XXdKSDJ3kGAPOyDDeK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c9JseK/btrcM0uuLSR/yxb7XXdKSDJ3kGAPOyDDeK/img.jpg&quot; data-alt=&quot;중랑천 노을&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c9JseK/btrcM0uuLSR/yxb7XXdKSDJ3kGAPOyDDeK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc9JseK%2FbtrcM0uuLSR%2Fyxb7XXdKSDJ3kGAPOyDDeK%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;454&quot; height=&quot;605&quot; data-filename=&quot;JPEG image-B3FE3FA785DF-1.jpeg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;중랑천 노을&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1648797535218&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;부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/7&quot; data-og-url=&quot;https://blog.hyunmin.dev/7&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qVMdx/hyNTpwtRHZ/fsQxYUIkEMzNqgdpBJPDik/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/racW4/hyNTwCo2u1/pJhsQOd8q7jKuihKLbRbN0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bWE6Pw/hyNR9WkvkE/371kScZ9bSUHkhCkKRSfKk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/7&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qVMdx/hyNTpwtRHZ/fsQxYUIkEMzNqgdpBJPDik/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/racW4/hyNTwCo2u1/pJhsQOd8q7jKuihKLbRbN0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bWE6Pw/hyNR9WkvkE/371kScZ9bSUHkhCkKRSfKk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&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;부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다.&amp;nbsp;챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;챌린지 이후&lt;/b&gt;&lt;/h2&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;합격&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목요일에는 약속이 있어 하루 종일 밖에 있었다. 정신없이 저녁이 되었고, 식당에서 밥을 먹다가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6시 57분에 메일이 도착했다는 알림을 받았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Shot 2021-08-21 at 5.36.05 PM.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FXtMq/btrcOiVxzt2/NPBP6luz7RYkDsKxqByaRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FXtMq/btrcOiVxzt2/NPBP6luz7RYkDsKxqByaRK/img.png&quot; data-alt=&quot;언제나 설레는 합격 통보 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FXtMq/btrcOiVxzt2/NPBP6luz7RYkDsKxqByaRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFXtMq%2FbtrcOiVxzt2%2FNPBP6luz7RYkDsKxqByaRK%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;476&quot; height=&quot;231&quot; data-filename=&quot;Screen Shot 2021-08-21 at 5.36.05 PM.png&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;732&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;'멤버십 입과를 축하드립니다!' 이 문장만 눈에 들어왔다. 다른 글은 보이지도 않았다.&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;widthContent&quot; data-filename=&quot;KakaoTalk_Photo_2021-08-21-17-31-48.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1020&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btfTY1/btrcNKkl8lZ/IyZFxhawnKsbcmc1udTju0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btfTY1/btrcNKkl8lZ/IyZFxhawnKsbcmc1udTju0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btfTY1/btrcNKkl8lZ/IyZFxhawnKsbcmc1udTju0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtfTY1%2FbtrcNKkl8lZ%2FIyZFxhawnKsbcmc1udTju0%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;377&quot; height=&quot;410&quot; data-filename=&quot;KakaoTalk_Photo_2021-08-21-17-31-48.png&quot; data-origin-width=&quot;936&quot; data-origin-height=&quot;1020&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;이후 슬랙 초대 메일을 받았고, 첫 주차 그룹을 확인할 수 있었다. 약 360명으로 시작했던 부스트캠프가 이제 약 210명이 되었다. 웹 분야는 228명으로 시작했지만 132명의 캠퍼만 남게 되었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다짐&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;15주간 멤버십을 해야 할 것으로 생각하니 조금 겁이 나긴 한다. 하지만 챌린지가 그랬듯 평생 오지 않을 소중한 기회라 생각하고 부지런하게 하겠다.&lt;/p&gt;
&lt;figure id=&quot;og_1648797553106&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/9&quot; data-og-url=&quot;https://blog.hyunmin.dev/9&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RHzhf/hyNR3ofXOt/z28botbDIXBJcpQJpekfqk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/6gUTE/hyNTrui2MI/U1dmQbsvXS8xZvOXGQUsy0/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cKcpvu/hyNTstc3za/clXxjVZipgUn33IDOd02EK/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/9&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/9&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RHzhf/hyNR3ofXOt/z28botbDIXBJcpQJpekfqk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/6gUTE/hyNTrui2MI/U1dmQbsvXS8xZvOXGQUsy0/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cKcpvu/hyNTstc3za/clXxjVZipgUn33IDOd02EK/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024');&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;부스트캠프 웹 풀스택 6기 멤버십 스프린트 1회차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 멤버십 합격 챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>멤버십</category>
      <category>부스트캠프</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/8</guid>
      <comments>https://hyunmindev.tistory.com/8#entry8comment</comments>
      <pubDate>Sat, 21 Aug 2021 13:27:12 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료</title>
      <link>https://hyunmindev.tistory.com/7</link>
      <description>&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;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EKzXu/btrb81Vge7I/8xeQ8pRXbahcE5RXEEdhOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EKzXu/btrb81Vge7I/8xeQ8pRXbahcE5RXEEdhOk/img.jpg&quot; data-alt=&quot;수료식 당일 노을&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EKzXu/btrb81Vge7I/8xeQ8pRXbahcE5RXEEdhOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEKzXu%2Fbtrb81Vge7I%2F8xeQ8pRXbahcE5RXEEdhOk%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;476&quot; height=&quot;635&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;수료식 당일 노을&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1648798043551&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;부스트캠프 웹 풀스택 6기 챌린지 3주차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 챌린지 2주차 부스트캠프 웹 풀스택 챌린지 1주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/6&quot; data-og-url=&quot;https://blog.hyunmin.dev/6&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dkytoZ/hyNSa10cVD/bdnGOAFyjxF86qiiUbNWsk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/AKciv/hyNTkvbZV5/H7fKFkWzPQdCkcuaDUHJak/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cYxOWZ/hyNTrODSb4/h7CCCpp4WDH7wFsZYQLqAk/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/6&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dkytoZ/hyNSa10cVD/bdnGOAFyjxF86qiiUbNWsk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/AKciv/hyNTkvbZV5/H7fKFkWzPQdCkcuaDUHJak/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/cYxOWZ/hyNTrODSb4/h7CCCpp4WDH7wFsZYQLqAk/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024');&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;부스트캠프 웹 풀스택 6기 챌린지 3주차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 2주차 부스트캠프 웹 풀스택 챌린지 1주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7월 19일부터 8월 13일까지 25일간의 챌린지 과정이 막을 내렸다. 미션 16개, 릴레이 프로젝트 4개, 코드 약 5000라인, 하루 평균 코딩 시간 10시간. 한 달에 챌린지를 꾹꾹 눌러 담았다. 그렇기에, 단기간에 이정로도 성장했다는 느낌을 받을 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;미션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 미션을 제외한 마지막 주 미션들은 무난했다. 마지막 미션을 제외하고, 챌린지 과정의 주차별 주관적 미션 난이도를 정렬하면 아래와 같다.&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;3 &amp;gt; 4 &amp;gt;= 2 &amp;gt; 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 마지막 미션을 합쳐 주관적 난이도를 정렬하면 아래와 같이 바뀐다.&lt;/p&gt;
&lt;pre class=&quot;basic&quot;&gt;&lt;code&gt;4 &amp;gt;&amp;gt; 3 &amp;gt; 2 &amp;gt; 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간호사가 주사를 놓기 전에 주사 부위를 톡톡 두드리는 것은 미리 고통을 주어 고통에 대한 역치 값을 올려서 주삿바늘이 살을 파고 들어갈 때 고통을 상대적으로 적게 느끼기 위해서이다. 화요일 수요일이 톡 톡이었고, 마지막 미션인 목요일이 톱날 같은 주삿바늘이었다.&lt;br /&gt;하지만 마지막 미션을 끝냈을 때의 그 개운함은 정말 상쾌했다. 미션 내용을 유출하면 잡혀가기 때문에, 짧게 후기를 남기겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;월&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 상&lt;br /&gt;후기: 무난하지 않은 출발이었다. 2주 차 월요일의 미션과 비슷하듯 차이점이 있었다. 제출 시간인 오후 7시를 한 시간 반 넘겨 8시 반에 제출했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 중&lt;br /&gt;후기: 폭풍전야의 시작이었다. 정규식을 알고 있었지만, 어떻게 활용하느냐에 따라 20줄짜리 코드가 2줄이 되는 것을 경험했다. 정규식의 힘을 알게 되어 이후 미션에서도 많이 사용했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 중&lt;br /&gt;후기: 2주 차 목요일 미션의 업그레이드 버전 같았다. 다른 미션보다 상대적으로 모듈/클래스 설계가 쉬운 미션이었다. 난이도는 비교적 쉬웠지만, 구현 요구사항이 많아 7시 40분쯤 미션을 완료할 수 있었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;목&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 최상 * 최상&lt;br /&gt;후기: 처음으로 미션을 받은 당일날 해결하지 못했다.&lt;br /&gt;지금까지 해결했던 미션을 다시 활용해서 해결하는 미션이었다. 당연히 이전 미션의 복습이 선행되어야 했다.&lt;br /&gt;금요일 오전 0시 50분에 미션을 겨우 끝낼 수 있었다. 점심 저녁밥 먹는 시간을 제외하면 11시간 30분을 책상에만 앉아있었다. 이때 처음으로 머리에서 &lt;a href=&quot;https://12bme.tistory.com/504&quot;&gt;쓰로틀링&lt;/a&gt; 현상이 발생하는 것을 경험할 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;릴레이 프로젝트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 주차 릴레이 프로젝트의 첫 번째 임무는 마무리하는 것이다. 그래서 이어받은 프로젝트의 디자인을 전면 개선하는 데 힘썼다. 수료식 일정이 있었기 때문에, 주어진 시간은 4시간밖에 되지 않았다. 하지만 Webstorm의 code with me 기능으로 7명이 동시에 작업하는 pair programming을 했고, 이 결과 빠르게 디자인을 개선하고 남은 시간에는 놀 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이 프로젝트 발표는 &lt;a href=&quot;https://www.gather.town/&quot;&gt;게더타운&lt;/a&gt;이라는 메타버스에서 진행된다. ZOOM 과는 달리 '같은 공간'에 있다는 사실이 주는 느낌은 사뭇 달랐다. 박람회처럼 팀마다 부스가 있고, 부스에 방문하면 관계자가 발표를 시작한다. 회의를 거쳐 부스를 지킬 순서를 정하는 등 여러모로 현실 반영이 많이 되어있다. 마지막 릴레이 프로젝트 발표가 끝나고 바로 수료식이 시작됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;수료식&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;593&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LwQYD/btrcgOUZK21/0VOVY7z3sKwcVB5qBcg3M0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LwQYD/btrcgOUZK21/0VOVY7z3sKwcVB5qBcg3M0/img.gif&quot; data-alt=&quot;수료식날 모여서 춤추는 캠퍼들&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LwQYD/btrcgOUZK21/0VOVY7z3sKwcVB5qBcg3M0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/LwQYD/btrcgOUZK21/0VOVY7z3sKwcVB5qBcg3M0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;455&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;593&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;수료식도 릴레이 프로젝트 발표와 마찬가지로 게더타운에서 진행됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수료식에서는 내가 나한테 주는 상 내준 내상, 수료식 축하 영상 등 재밌는 콘텐츠가 있었다. 축하 영상은 희망 하에 자유롭게 제출하는 방식이었는데, 웃긴 영상, 감동적인 영상 다양하게 있었다. 미션 하느라 정신없던 나로서는 영상을 제출한 캠퍼들이 존경스럽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게더타운에서 30분 정도 메타버스 수료식을 즐긴 뒤 마지막으로 줌에 모여서 작별 인사를 했다. 처음에는 아무도 몰랐던 약 350명의 캠퍼 중에서 한 페이지를 넘길 때마다 익숙한 용안이 나왔다. 몇몇 캠퍼들이 수료후기를 말하고, 단체사직을 찍었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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/dU7cYe/btrcgP0zksx/pvq7k0ggKS9YKb3klQsa71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dU7cYe/btrcgP0zksx/pvq7k0ggKS9YKb3klQsa71/img.png&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;330&quot; style=&quot;width: 46.525614964286376%; margin-right: 10px;&quot; data-widthpercent=&quot;47.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dU7cYe/btrcgP0zksx/pvq7k0ggKS9YKb3klQsa71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdU7cYe%2FbtrcgP0zksx%2Fpvq7k0ggKS9YKb3klQsa71%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;587&quot; height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3aezw/btrb7tRQNGE/vjq0sPO2LXTibC2ywm4sZ0/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3aezw/btrb7tRQNGE/vjq0sPO2LXTibC2ywm4sZ0/img.webp&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;480&quot; style=&quot;width: 52.3115943380392%;&quot; data-widthpercent=&quot;52.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3aezw/btrb7tRQNGE/vjq0sPO2LXTibC2ywm4sZ0/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3aezw%2Fbtrb7tRQNGE%2Fvjq0sPO2LXTibC2ywm4sZ0%2Fimg.webp&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;960&quot; height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iz3mf/btrcgOHmKIg/xP12bkqNZwA1K8zMsHX7OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iz3mf/btrcgOHmKIg/xP12bkqNZwA1K8zMsHX7OK/img.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;1200&quot; style=&quot;width: 32.55813953488373%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iz3mf/btrcgOHmKIg/xP12bkqNZwA1K8zMsHX7OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIz3mf%2FbtrcgOHmKIg%2FxP12bkqNZwA1K8zMsHX7OK%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;1200&quot; height=&quot;1200&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz9N1u/btrcb80EtM4/JbUSzQLBDYGn5eIMFtCr20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz9N1u/btrcb80EtM4/JbUSzQLBDYGn5eIMFtCr20/img.png&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;512&quot; style=&quot;width: 32.55813953488373%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz9N1u/btrcb80EtM4/JbUSzQLBDYGn5eIMFtCr20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz9N1u%2Fbtrcb80EtM4%2FJbUSzQLBDYGn5eIMFtCr20%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;512&quot; height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pI8eo/btrclJMhDRy/GvwVMH76cOiPmwbjlUYAs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pI8eo/btrclJMhDRy/GvwVMH76cOiPmwbjlUYAs1/img.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; style=&quot;width: 32.55813953488373%; margin-top: 10px;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pI8eo/btrclJMhDRy/GvwVMH76cOiPmwbjlUYAs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpI8eo%2FbtrclJMhDRy%2FGvwVMH76cOiPmwbjlUYAs1%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;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eBns5C/btrb820XBMD/f7IV8yKkq1yvdZwQyA7xx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eBns5C/btrb820XBMD/f7IV8yKkq1yvdZwQyA7xx1/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;484&quot; style=&quot;width: 57.880694488690665%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;58.56&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eBns5C/btrb820XBMD/f7IV8yKkq1yvdZwQyA7xx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeBns5C%2Fbtrb820XBMD%2Ff7IV8yKkq1yvdZwQyA7xx1%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;484&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qc6vz/btrb7y0lQLi/gbLS6gorbPaYTkbMQmCI20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qc6vz/btrb7y0lQLi/gbLS6gorbPaYTkbMQmCI20/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;684&quot; style=&quot;width: 40.95651481363491%; margin-top: 10px;&quot; data-widthpercent=&quot;41.44&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qc6vz/btrb7y0lQLi/gbLS6gorbPaYTkbMQmCI20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqc6vz%2Fbtrb7y0lQLi%2FgbLS6gorbPaYTkbMQmCI20%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;684&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hhec8/btrb827J0Bi/ZK8CrYYTRKX7aRDwJF56Q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hhec8/btrb827J0Bi/ZK8CrYYTRKX7aRDwJF56Q0/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1280&quot; style=&quot;width: 49.501106495321665%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hhec8/btrb827J0Bi/ZK8CrYYTRKX7aRDwJF56Q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHhec8%2Fbtrb827J0Bi%2FZK8CrYYTRKX7aRDwJF56Q0%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;1280&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QadEm/btrb8hRzg6m/nXdc4FeNPlF92c7GtU0sv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QadEm/btrb8hRzg6m/nXdc4FeNPlF92c7GtU0sv1/img.png&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;300&quot; style=&quot;width: 49.336102807003925%; margin-top: 10px;&quot; data-widthpercent=&quot;49.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QadEm/btrb8hRzg6m/nXdc4FeNPlF92c7GtU0sv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQadEm%2Fbtrb8hRzg6m%2FnXdc4FeNPlF92c7GtU0sv1%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;299&quot; height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;기억에 남는 것&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1648798050089&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;부스트캠프 웹 풀스택 6기 멤버십 합격&quot; data-og-description=&quot;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/8&quot; data-og-url=&quot;https://blog.hyunmin.dev/8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bavuUG/hyNTwWGmPP/TSQwcIu0IPoGtG1jfjUKu0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/plWbi/hyNTstdgVw/xGMuJMvGPAXVeQEHkLa3SK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bPNQFk/hyNTy71XRx/ojrh9JBU7SAWZb3QabcXNK/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bavuUG/hyNTwWGmPP/TSQwcIu0IPoGtG1jfjUKu0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/plWbi/hyNTstdgVw/xGMuJMvGPAXVeQEHkLa3SK/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bPNQFk/hyNTy71XRx/ojrh9JBU7SAWZb3QabcXNK/img.jpg?width=3024&amp;amp;height=4032&amp;amp;face=0_0_3024_4032');&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;부스트캠프 웹 풀스택 6기 멤버십 합격&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;챌린지에 입과한 모든 캠퍼가 멤버십에 입과 하는 것은 아니다. 특정 기준으로 멤버십에 입과할 자격을 심사한다. 챌린지 과정 동안 최선을 다했고, 멤버십에 입과할 수 있게 되었다. 챌린지 이&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <category>챌린지</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/7</guid>
      <comments>https://hyunmindev.tistory.com/7#entry7comment</comments>
      <pubDate>Sat, 14 Aug 2021 11:34:15 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 챌린지 3주차</title>
      <link>https://hyunmindev.tistory.com/6</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;JPEG image-F5D415A49316-1.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p1iWC/btrbtzqUA7Y/6nX1m0pYuMRgHeIywnk0e0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p1iWC/btrbtzqUA7Y/6nX1m0pYuMRgHeIywnk0e0/img.jpg&quot; data-alt=&quot;릴레이 프로젝트 구현 후 중랑천&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p1iWC/btrbtzqUA7Y/6nX1m0pYuMRgHeIywnk0e0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp1iWC%2FbtrbtzqUA7Y%2F6nX1m0pYuMRgHeIywnk0e0%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;751&quot; height=&quot;563&quot; data-filename=&quot;JPEG image-F5D415A49316-1.jpeg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;릴레이 프로젝트 구현 후 중랑천&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1648797991962&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;부스트캠프 웹 풀스택 6기 챌린지 2주차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 챌린지 1주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/5&quot; data-og-url=&quot;https://blog.hyunmin.dev/5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bg1bwl/hyNTpQNzH0/c4evx0m1nbUt9y59qObRwK/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/VfE5M/hyNToK6PxR/VSpPKlkkKCatmCFh62l611/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/cQqQRQ/hyNSaVeHN8/Mfn12IR67pCDbCQ4eKpfk1/img.jpg?width=4032&amp;amp;height=2384&amp;amp;face=0_0_4032_2384&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bg1bwl/hyNTpQNzH0/c4evx0m1nbUt9y59qObRwK/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/VfE5M/hyNToK6PxR/VSpPKlkkKCatmCFh62l611/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/cQqQRQ/hyNSaVeHN8/Mfn12IR67pCDbCQ4eKpfk1/img.jpg?width=4032&amp;amp;height=2384&amp;amp;face=0_0_4032_2384');&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;부스트캠프 웹 풀스택 6기 챌린지 2주차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 1주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부스트캠프 챌린지 과정이 이제 1주일밖에 남지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 많이 성장했다. 3주 차가 끝난 시점인 지금도 이 정도인데, 멤버십에 합격한다면 어디까지 성장하게 될지 궁금하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;온종일 책상 앞에 앉아있는 것이 몸도 고달프고 정신적으로도 힘들지만, 마지막 한 주 힘내도록 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;미션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미션의 난이도가 껑충 뛰었다. 첫 주차의 미션 난이도를 1, 둘째 주차의 난이도를 2라고 한다면 셋째 주차의 난이도는 4 정도 됐다. 상승률을 보면 다음 주의 난이도는 8로 예상할 수 있다. 16은 아니길 빈다. 어찌 됐건 다음 주도 그날 받은 미션은 당일 내로 제출할 수 있길 노력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주는 월요일을 제외하고 마감 시간인 7시 이전에 완성한 적이 없다. CS에서도 네트워크, 운영체제 같은 굵직한 주제들이 나왔고, 배경지식 학습 및 구조 설계에만 2시간을 쏟은 날도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미션의 내용을 유출하면 잡혀가기 때문에 요일별 후기를 간단하게 남기겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;월&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 중&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 6시 50분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 운영체제 수업에서 진행했던 과제와 비슷한 느낌을 받았다. 그래서 쉽게 접근해서 해결할 수 있었다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;화&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 7시 40분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: CS 개념이 굉장히 부족하다는 것을 알게 된 미션이다. 이 부분은 나중에 관련 책으로 따로 공부할 의향이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 최상상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 8시 30분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 직전 학기에 네트워크 수업을 들을까 고민하다 안 들었던 것이 후회된다. 덕분에 상당히 생소했다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;목&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 최상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 7시 40분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 구현 자체의 난이도는 중상~상 정도였다. 하지만 구현 요구사항이 너무 많았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;릴레이 프로젝트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;챌린지 과정에서 금요일은 미션 없이 릴레이 프로젝트를 진행한다. 매주 새로운 프로젝트를 이어받아, 몇 가지 기능을 개발 후 다음 주에 다른 팀에게 념겨주는 컨텐츠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주에는 비교적 쉬운 프로젝트를 이어받았다. 거기에 추가로 Flutter에 익숙한 팀원이 있어 분담 후 당일에 구현을 끝냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 주간의 고된 미션 후 긴장이 풀렸던 터라 피어세션보다 무겁지 않은 분위기에서 진행할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;릴레이 프로젝트를 하며 Flutter가 굉장히 매력적인 프레임워크라는 것을 알게 됐다. 이후에 진행할 여러 토이프로젝트에 Flutter를 적극적으로 활용하고 싶다는 생각을 했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다음 글&lt;/h2&gt;
&lt;figure id=&quot;og_1648797995905&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;부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료&quot; data-og-description=&quot;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/7&quot; data-og-url=&quot;https://blog.hyunmin.dev/7&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qVMdx/hyNTpwtRHZ/fsQxYUIkEMzNqgdpBJPDik/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/racW4/hyNTwCo2u1/pJhsQOd8q7jKuihKLbRbN0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bWE6Pw/hyNR9WkvkE/371kScZ9bSUHkhCkKRSfKk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/7&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qVMdx/hyNTpwtRHZ/fsQxYUIkEMzNqgdpBJPDik/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/racW4/hyNTwCo2u1/pJhsQOd8q7jKuihKLbRbN0/img.jpg?width=800&amp;amp;height=1066&amp;amp;face=0_0_800_1066,https://scrap.kakaocdn.net/dn/bWE6Pw/hyNR9WkvkE/371kScZ9bSUHkhCkKRSfKk/img.png?width=1200&amp;amp;height=1200&amp;amp;face=0_0_1200_1200');&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;부스트캠프 웹 풀스택 6기 챌린지 4주차, 수료&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <category>챌린지</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/6</guid>
      <comments>https://hyunmindev.tistory.com/6#entry6comment</comments>
      <pubDate>Sat, 7 Aug 2021 17:41:14 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 챌린지 2주차</title>
      <link>https://hyunmindev.tistory.com/5</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2384&quot; data-filename=&quot;JPEG image-91D0FBBEBC62-1.jpeg&quot; width=&quot;774&quot; height=&quot;457&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ltSzF/btraXWTWW3d/rkYSMbvdTWUoQqozEaiD1k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ltSzF/btraXWTWW3d/rkYSMbvdTWUoQqozEaiD1k/img.jpg&quot; data-alt=&quot;미션 제출 후 군자, 장안, 중랑천 야경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ltSzF/btraXWTWW3d/rkYSMbvdTWUoQqozEaiD1k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FltSzF%2FbtraXWTWW3d%2FrkYSMbvdTWUoQqozEaiD1k%2Fimg.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;2384&quot; data-filename=&quot;JPEG image-91D0FBBEBC62-1.jpeg&quot; width=&quot;774&quot; height=&quot;457&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;미션 제출 후 군자, 장안, 중랑천 야경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1627712320989&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;부스트캠프 웹 풀스택 챌린지 1주차 후기&quot; data-og-description=&quot;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/4&quot; data-og-url=&quot;https://blog.hyunmin.dev/4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cO7hcH/hyK3EYHSHZ/vHzFJKNmGLXFt4MGSDruok/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/mNNnn/hyK3HnDyYW/jHdnJdFXQKnoEBeOukwBqk/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bJzZMf/hyK4IkUHtm/K9EsY6eX7GmWLNour8KyjK/img.png?width=1024&amp;amp;height=768&amp;amp;face=0_0_1024_768&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cO7hcH/hyK3EYHSHZ/vHzFJKNmGLXFt4MGSDruok/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/mNNnn/hyK3HnDyYW/jHdnJdFXQKnoEBeOukwBqk/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bJzZMf/hyK4IkUHtm/K9EsY6eX7GmWLNour8KyjK/img.png?width=1024&amp;amp;height=768&amp;amp;face=0_0_1024_768');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 1주차 후기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;부스트캠프 챌린지 과정의 반이 지났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;일주일이 지나 슬슬 익숙해져 간다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;첫 주차와 크게 달라진 게 없다.&amp;nbsp;계획하기로는 운동을 4일 이상 하자였지만, 결국 3일밖에 하지 않았다. 요즘 들어 목, 어깨, 승모근 쪽이 계속 아프다. 운동하려면 건강해야 하므로 의도적으로 바른 자세로 고쳐 앉아야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;저번 주에 우려한 것과는 달리 12시 전에 침대로 갈 수 있었다. 제발 다음 주도 수면시간은 보장되길 바란다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;미션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미션을 하면서 '이게 맞나?' '내가 잘하고 있나?'라는 생각이 많이 들었다. 요구사항이 모호했고, 그래서 더 찾아보고 더 고민했다. 이것을 의도하고 기획한 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미션 4개 중 1개만 7시 이전에 제출했고, 나머지 2개는 아깝게 7시 30분쯤, 나머지 1개는 8시 30분에 제출했다. 저번 주는&amp;nbsp;7시 전에 제출한 날이 3일 있은 것에 비하면 난이도가 오른 것이 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미션의 내용을 유출하면 잡혀가기 때문에 요일별 후기를 간단하게 남기겠다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;월&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 최상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 8시 30분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 최대한 쉽게 구현하려고 설계한 결과 완성할 수 있었다. 주변 동료 캠퍼 중 실패한 캠퍼들이 정말 많았다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 중상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 7시 30분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 월요일에 비해 구현 난이도는 그럭저럭이었다. 하지만, 구현할 양이 너무 많았다. 체스로 치면 월요일은 퀸 1개 화요일은 폰 8개였다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;수&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 하&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 6시 50분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 쉬어가는 날을 받은 느낌이었다. 화요일 코드 라인수의 1/15 정도로 해결됐던 미션이다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;목&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난이도: 중&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출: 7시 15분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후기: 처음 미션을 받았을 때는 '이걸 만들라고?'였지만, 하다 보니 감이 잡혀서 금방 해결했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;릴레이 프로젝트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;매주 금요일은 릴레이 프로젝트를 진행한다. 첫 주에 다른 팀이 기획해놓은 것을 랜덤으로 받아 개발을 시작했다. 잘 뽑혀야 한다. 첫 주에 기획한 내용이 터무니없이 구현 난도가 높다면, 주말은 못 쉬는 것이다. 다행히도 우리 팀은 중하 난이도 느낌의 프로젝트를 받았고, 지금 순탄하게 개발 중이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;하면 할수록 정말 잘 짜인 교육이라고 생각된다. 2주밖에 되지 않았지만 지금도 성장한 것이 느껴진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제 반밖에 안 남았다. 힘 좀 내서 끝까지 하겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1629095424430&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;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기&quot; data-og-description=&quot;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/6&quot; data-og-url=&quot;https://blog.hyunmin.dev/6&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYALah/hyLgKWQ7RA/SpE6HxisjdKwgrUbKZe9hK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/burbj6/hyLfnPLexW/qbozMZ3oxabrZgQRu5Nthk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/s6bwE/hyLfsDxEjQ/eftAwDfKSvLYoatSQJdeZk/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/6&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/6&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYALah/hyLgKWQ7RA/SpE6HxisjdKwgrUbKZe9hK/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/burbj6/hyLfnPLexW/qbozMZ3oxabrZgQRu5Nthk/img.jpg?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/s6bwE/hyLfsDxEjQ/eftAwDfKSvLYoatSQJdeZk/img.jpg?width=4032&amp;amp;height=3024&amp;amp;face=0_0_4032_3024');&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;부스트캠프 웹 풀스택 6기 챌린지 3주차 후기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>부스트캠프</category>
      <category>챌린지</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/5</guid>
      <comments>https://hyunmindev.tistory.com/5#entry5comment</comments>
      <pubDate>Sat, 31 Jul 2021 16:48:39 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 챌린지 1주차</title>
      <link>https://hyunmindev.tistory.com/4</link>
      <description>&lt;p data-ke-size=&quot;size18&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;workspace.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvysUa/btrasvoNM08/34Q9dKgOYbDJtQ0dSP5HqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvysUa/btrasvoNM08/34Q9dKgOYbDJtQ0dSP5HqK/img.png&quot; data-alt=&quot;챌린지 과정 개발 환경&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvysUa/btrasvoNM08/34Q9dKgOYbDJtQ0dSP5HqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvysUa%2FbtrasvoNM08%2F34Q9dKgOYbDJtQ0dSP5HqK%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;796&quot; height=&quot;597&quot; data-filename=&quot;workspace.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;챌린지 과정 개발 환경&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;figure id=&quot;og_1627109196150&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;부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야로 지원했고, 누군가에게 도움이 되&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/3&quot; data-og-url=&quot;https://blog.hyunmin.dev/3&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/INmmR/hyKZ7kL3td/33jxIX8vSObqx8xXU2mS50/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/dy5ILR/hyKZeMyTF9/Kj9DkunI4Y7JQQxZHmfrn1/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/ZmU28/hyKZhoZ9DP/YkAwhS4KclKzN4nEp986rK/img.png?width=1042&amp;amp;height=642&amp;amp;face=0_0_1042_642&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/3&quot; data-source-url=&quot;https://blog.hyunmin.dev/3&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/INmmR/hyKZ7kL3td/33jxIX8vSObqx8xXU2mS50/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/dy5ILR/hyKZeMyTF9/Kj9DkunI4Y7JQQxZHmfrn1/img.png?width=800&amp;amp;height=492&amp;amp;face=0_0_800_492,https://scrap.kakaocdn.net/dn/ZmU28/hyKZhoZ9DP/YkAwhS4KclKzN4nEp986rK/img.png?width=1042&amp;amp;height=642&amp;amp;face=0_0_1042_642');&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;부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야로 지원했고, 누군가에게 도움이 되&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;부스트캠프&amp;nbsp;챌린지 과정을 시작하고 첫 주가 지났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;새로운 루틴, 환경에서 적응하느라 정신없었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;콘텐츠&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;챌린지 과정의 콘텐츠는 크게 4가지로 나뉜다.&amp;nbsp;&lt;b&gt;피어 세션, 미션, 학습 정리, 릴레이 프로젝트&lt;/b&gt;이다. 각각이 유기적으로 엮여 좋은 시너지를 낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;피어 세션&lt;/b&gt;은 피어 컴파일링과 피어 피드백으로 다시 분리된다. 피어 컴파일링은 어제 동료가 해결한 미션을 실행하며 체크하는 것이고, 피어 피드백은 동료와 함께 피드백을 주고받는 시간이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;미션&lt;/b&gt;은 금요일을 제외한 주중에 하루 한 개씩 제공된다. 미션의 마감기한은 7시까지이고, 실패하나 성공하나 제출해야 한다. 그 이후 결과물을 개선하거나 수정하는 것이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;학습 정리&lt;/b&gt;는 당일 나온 미션에 관련된 내용을 정리하며 스스로 복습을 할 수 있는 시간이다. 이를 바탕으로 다음 날 피어 피드백 시간에 동료들과 소통을 할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;릴레이 프로젝트&lt;/b&gt;는 첫 주의 기획을 바탕으로 매주 다른 프로젝트를 할당받아 기획서에 있는 기능을 개발하는 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일정&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&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;1670&quot; data-origin-height=&quot;2316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eFMmQr/btrM37KRFeo/Cv861RBwzBN5cVGPY96kB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eFMmQr/btrM37KRFeo/Cv861RBwzBN5cVGPY96kB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eFMmQr/btrM37KRFeo/Cv861RBwzBN5cVGPY96kB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeFMmQr%2FbtrM37KRFeo%2FCv861RBwzBN5cVGPY96kB0%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;688&quot; height=&quot;954&quot; data-origin-width=&quot;1670&quot; data-origin-height=&quot;2316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;목표는 매일 아침 운동하기였지만 수요일과 목요일에&amp;nbsp;한 시간을 더 자는 바람에 씻고 바로 코드 리뷰를 시작했다. 다음 주는 체력관리를 위해 4일 이상 운동을 목표로 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;챌린지 과정의 코어타임은 오전 10시부터 오후 7시까지 이지만 코드 리뷰를 9시에 시작할 수 있고 체크아웃 후 학습 정리를 하기 때문에 오전 9시 ~ 오후 10시까지 컴퓨터만 잡고 있었다. 물론 첫 주의 비교적 쉬운 미션 때문에 일찍 퇴근한 것을 고려하면 다음 주는 출근한 날에 퇴근할 수 있길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;밥 먹는 시간이 굉장히 애매하다. 피어 세션이 끝난 12시에 점심을 먹고 체크아웃하는 7시까지 버티는 것은 여간 쉬운 일이 아니다. 견과류 같은 가벼운 간식을 사서 먹어야겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;미션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;7시 이후에 결과물을 수정하거나 개선하는 것이 멤버십 선발에 영향이 있는 묻는 많은 질문에 &quot;개선할 것이 있다면 끝까지 개선해야 한다.&quot;, &quot;마감기한은 괜히 있는 것이 아니다.&quot;와 같은 모호한 답변을 해주셨다. 아래와 같이 평가되지 않을까 생각한다.&lt;/p&gt;
&lt;pre id=&quot;code_1627110886968&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;7시 전 성공 &amp;gt; 7시 후 성공 &amp;gt;&amp;gt; 7시 후 실패 &amp;gt;&amp;gt;&amp;gt;&amp;gt; 7시 전 실패&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미션별로 후기를 정리하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;월요일&lt;/b&gt;: 본격적인 챌린지 미션을 위한 준비운동을 하는 느낌이었다. '이대로라면 할만하겠는데?'라고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;화요일&lt;/b&gt;: 굉장히 낯선 부분이었기에 큰 당황을 했다. 첫 주 미션 중 유일하게 7시 이후 성공을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;수요일&lt;/b&gt;: 전공 수업을 들으며 배웠던 개념들이 등장했다. 이전에 비슷한 프로젝트를 한 경험이 있어 수월하게 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;목요일&lt;/b&gt;: 마찬가지로 전공 수업 과제와 흡사했다. 미션을 이해하는데 시간 투자를 많이 했고, 고군분투 끝에 6시 59분에 제출했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;첫 주차부터 예상보다 더 깊게 CS 관련 지식을 공부했다. 왜 2/3의 인원만 챌린지에서 멤버십으로 넘어갈 수 있는지 조금은 알 것 같다. 포기하지 말고 끝까지 해결하는 사람이 이기는 싸움이라고 생각한다. 남은 3주 동안 하루하루 미션을 해결해나가며 적극적으로 챌린지에 임하겠다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음 글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1628908674653&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;부스트캠프 웹 풀스택 6기 챌린지 2주차 후기&quot; data-og-description=&quot;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/5&quot; data-og-url=&quot;https://blog.hyunmin.dev/5&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cO9IWC/hyLeAgRRNp/hMowTtn5bRaxjc5F2ADnc1/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/ysm8z/hyLerRLqfD/2TkRnOTOmbQrqXdMSxlxBK/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/jSpD8/hyLer5iUwX/wJ6fYXswo0tpkxncTSAYU1/img.jpg?width=4032&amp;amp;height=2384&amp;amp;face=0_0_4032_2384&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/5&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/5&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cO9IWC/hyLeAgRRNp/hMowTtn5bRaxjc5F2ADnc1/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/ysm8z/hyLerRLqfD/2TkRnOTOmbQrqXdMSxlxBK/img.jpg?width=800&amp;amp;height=473&amp;amp;face=0_0_800_473,https://scrap.kakaocdn.net/dn/jSpD8/hyLer5iUwX/wJ6fYXswo0tpkxncTSAYU1/img.jpg?width=4032&amp;amp;height=2384&amp;amp;face=0_0_4032_2384');&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;부스트캠프 웹 풀스택 6기 챌린지 2주차 후기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>부스트캠프</category>
      <category>챌린지</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/4</guid>
      <comments>https://hyunmindev.tistory.com/4#entry4comment</comments>
      <pubDate>Sat, 24 Jul 2021 14:40:58 +0900</pubDate>
    </item>
    <item>
      <title>부스트캠프 웹 풀스택 6기 챌린지 합격</title>
      <link>https://hyunmindev.tistory.com/3</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;인트로.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GZX5q/btq9LrHhMW0/kXpYdemShH4G9gbaQjolE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GZX5q/btq9LrHhMW0/kXpYdemShH4G9gbaQjolE0/img.png&quot; data-alt=&quot;부스트캠프 슬로건&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GZX5q/btq9LrHhMW0/kXpYdemShH4G9gbaQjolE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGZX5q%2Fbtq9LrHhMW0%2FkXpYdemShH4G9gbaQjolE0%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;1042&quot; height=&quot;642&quot; data-filename=&quot;인트로.png&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;642&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;&lt;a href=&quot;https://boostcamp.connect.or.kr/about.html&quot;&gt;부스트캠프&lt;/a&gt;는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다.&amp;nbsp;2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다.&amp;nbsp;나는 6기 웹 분야로 지원했고, 다음 기수 지원자에게 도움이 되기를 바라며 후기를 작성한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 지원했나?&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사람들과 끊임없이 커뮤니케이션하고 서로에게 배우고 공유하며 문제를 해결해가는 사람, 그렇게 더 큰 미래를 그리는 사람이 좋은 개발자이고 지속 가능한 개발자라고 생각합니다. - 부스트캠프 소개 中&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 프로젝트를 진행하면서 문득문득 '최선의 선택을 했다고 생각한 것들이 정말 최선일까?'라는 생각을 하곤 했다. 팀원과 협업하면서 레퍼런스를 계승하고, 오픈소스를 들여다보며 보완을 해도 우리들만의 리그에서 허우적대고 있을 것 같다는 왠지 모를 찝찝함이 남아있었다.&lt;br /&gt;이러한 걱정은 기술의 깊이가 깊어질수록 더 커져만 갔고, 혼자 하는 공부의 효율이 흥미롭지 않은 시점에 다다랐다.&lt;br /&gt;그 시점에 &lt;b&gt;동료와 소통을 통해 함께 성장하는 분위기&lt;/b&gt;를 강조하는 부스트캠프 모집 소식을 듣게 됐고 자연스레 관심이 갔다.&lt;br /&gt;멤버십 과정에 합격한다면 휴학을 해야 하므로 '졸업 한 학기 늦게 하기'와 '부스트캠프를 통해 채용 기회 얻기' 사이의 고민이었다. 하지만 채용으로 이어지지 않을지라도 &lt;b&gt;개발자 인생에서 큰 경험&lt;/b&gt;을 얻었다는 내용의 후기 글들을 보았고, 기말 공부에 치여 환멸을 느끼고 있는 시기와 적절히 맞물려 지원서 작성을 시작했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;지원서&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모집대상: 하나를 파면 끝을 보는 &amp;lsquo;덕질 경험&amp;rsquo;이 있는 분 - 부스트캠프 모집 안내 中&lt;/p&gt;
&lt;/blockquote&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;/b&gt;를 4문항에 걸쳐 적절히 녹여냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2020년 자소서 문항과 2021년 자소서 문항이 다른 것을 보면 아마 2022년 문항도 2021년 문항과 달라질 것으로 예상된다. 2022년 부스트캠프에 지원할 계획이 있다면 지금부터라도 프로젝트를 진행해서 자소서 재료로 활용할 수 있도록 하는 것을 추천한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1차 코딩 테스트&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차 코딩테스트는 6월 24일에 진행됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2020년 1차 코딩테스트가 그리 어렵지 않다는 후기를 많이 봐서 마음이 가벼웠다. 그리고 8개월 정도 알고리즘 스터디를 해서 크게 긴장되지 않았다. 하지만 역시 시험은 시험인지라 당일부터 긴장이 됐다.&amp;nbsp;테스트 플랫폼은 프로그래머스로 보았고, 객관식 문제 10개와 알고리즘 문제 2개를 100분 동안 봤다. 20분 동안 객관식 10문제를 풀고 알고리즘 한 문제당 40분의 시간을 할당하는 전략을 세웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객관식 문제를 보자마자 문장의 모호함, 예상과 다른 문제 유형에 꽤 당황했다. 객관식 문제를 푸는 것에 약 35분 정도를 투자했다. 그리고 알고리즘 1번 문제를 10분 동안 풀고 2번 문제를 20분 만에 풀고 제출했다. 알고리즘 문제 유형은 문자열 다루기, 구현이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출을 하면 5개의 테스트케이스를 실행하고 5개를 다 맞으면 정답이라고 떴다. 추가로 실행하는 히든 테스트 케이스가 있는지는 모르겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번 문제를 제출했을 때는 5개의 테스트케이스를 전부 통과했지만 2번 문제는 5개 중 1개의 테스트 케이스가 통과되지 않았다. 2번 문제를 제출하고 남은 시간이 35분인 것을 보고 여유롭게 디버깅을 시작했다. 하지만 남은 시간이 15분, 10분, 5분이 되어도 하나의 테스트 케이스는 정답으로 바뀌지 않았다. 결국 눈물을 머금은 채 시험은 종료됐고, 고통의 기다림이 시작됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2차 코딩 테스트&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1차 합격.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbuAr9/btq9CtAvCtN/kAaMs1j88t42Tiee0pegTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbuAr9/btq9CtAvCtN/kAaMs1j88t42Tiee0pegTk/img.png&quot; data-alt=&quot;1차 코딩테스트 전형 합격 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbuAr9/btq9CtAvCtN/kAaMs1j88t42Tiee0pegTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbuAr9%2Fbtq9CtAvCtN%2FkAaMs1j88t42Tiee0pegTk%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;742&quot; height=&quot;216&quot; data-filename=&quot;1차 합격.png&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1차 코딩테스트 전형 합격 메일&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6월 30일 오후 1시 45분경 1차 코딩 테스트 합격 메일을 받았다. 2차 코딩 테스트는 합격 발표 후 3일 뒤인 7월 3일에 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;160분간 알고리즘 문제 3개를 풀어야 했다. 40분간 1번, 60분간 2번, 60분간 3번을 푼다는 전략을 세웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 전략이 무색하게도 1번 15분, 2번 20분, 3번 30분의 시간을 소비했다. 개인적인 난이도는 2번 &amp;gt; 3번 &amp;gt;= 1번이었는데 3번 문제를 풀 때 긴장이 확 풀려서 집중력이 떨어졌는지 잘 안 풀렸다. 문제 유형은 딱히 없다. 그냥 구현이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차 코테는 1차 코테와 달리 제출을 해도 따로 실행하는 테스트 케이스가 없다. 그래서 수동으로 테스트 케이스를 추가해 실행해보는 방법밖에 없다. 내가 직접 추가한 테스트케이스를 실행하는 거라 정답인지 오답인지 확실하게 알지 못한다. 그래서인지 3제출과 3솔의 경계가 모호해져 일명 폰3솔이 많이 출현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝나고 나니 2번 문제에 고려하지 않은 케이스가 있다는 것을 알게 되었고 합격 발표까지 지옥의 2주일이 시작됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;최종 결과&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2차 합격.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4QnbJ/btq9E6kAyVD/MDEd6XgS2iaLTfPK4fTq6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4QnbJ/btq9E6kAyVD/MDEd6XgS2iaLTfPK4fTq6k/img.png&quot; data-alt=&quot;최종 합격 메일&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4QnbJ/btq9E6kAyVD/MDEd6XgS2iaLTfPK4fTq6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4QnbJ%2Fbtq9E6kAyVD%2FMDEd6XgS2iaLTfPK4fTq6k%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;728&quot; height=&quot;194&quot; data-filename=&quot;2차 합격.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;194&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;7월 13일 오후 4시 20분경 여행 중에 최종 합격 이메일을 받았다. 함께 여행 간 친구 중 한 명과 함께 합격했다.&lt;br /&gt;20년 5기 부스트캠프 발표는 예정된 발표 3일 전 조기 발표가 났다는 소식을 듣고 3일 전부터 긴장이 됐었다. 하지만 이번 합격 발표는 정직하게 예정된 날짜에 발표했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;합격&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합격자 오픈채팅방의 투표를 보니 3솔, 감점 3솔, 3제출 2솔(매우적음)이 합격된 것을 알 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 스터디 멤버 중 한명이 감점 3 솔이지만 떨어졌다고 하니 (1차 + 자소서 -&amp;gt; 2차) 라기보다 (1차 -&amp;gt; 2차 + 자소서) 일 확률이 높다는 것을 알 수 있었다. 물론 불합격자의 투표를 보지 않아 3솔임에도 불구하고 떨어진 케이스가 많은지는 알지 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 약 60명, iOS 약 60명 웹 분야 약 220명이 선발됐다. 전 분야 통합 모집이기 때문에 정확한 경쟁률은 알기 어렵다. 심지어 분야별 지원 비율과 선발 비율이 같은지도 모른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2019년 이전 부스트캠프의 경쟁률은 3:1 ~ 5:1이고, 2019년 경쟁률이 5:1, 2020년 경쟁률이 8:1 ~ 9:1 인 것을 보았을 때 이번 경쟁률은 11:1 ~ 12:1 정도로 예상했다. 즉, 350명 모집에 4000명의 지원자가 있었다고 계산할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(운영진 피셜: 3000명이 넘는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 &lt;b&gt;부스트캠프 코딩 테스트를 준비하는 분들에게는 카카오 1번 2번 유형을 푸는 것을 추천한다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 경험이 시작되는 설렘과 잘할 수 있을까라는 두려움의 비율이 9:1 정도이다.&amp;nbsp;부스트캠프의 챌린지 과정이 부스트가 될지는 내게 달렸기 때문에 후회 없는 노력을 할 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;다음글&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1648797696132&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;부스트캠프 웹 풀스택 6기 챌린지 1주차&quot; data-og-description=&quot;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야&quot; data-og-host=&quot;blog.hyunmin.dev&quot; data-og-source-url=&quot;https://blog.hyunmin.dev/4&quot; data-og-url=&quot;https://blog.hyunmin.dev/4&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ofIYS/hyNTxuwZn0/Ajv85ts0PPFH09kZ3u0241/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/ctGbSD/hyNTqhRQOd/sMEKoOB8IGOV04K5NQGRIK/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bqBeYR/hyNTwvCTws/PDUskT94lkQOf04QsDPMZk/img.png?width=1024&amp;amp;height=768&amp;amp;face=0_0_1024_768&quot;&gt;&lt;a href=&quot;https://blog.hyunmin.dev/4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.hyunmin.dev/4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ofIYS/hyNTxuwZn0/Ajv85ts0PPFH09kZ3u0241/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/ctGbSD/hyNTqhRQOd/sMEKoOB8IGOV04K5NQGRIK/img.png?width=800&amp;amp;height=600&amp;amp;face=0_0_800_600,https://scrap.kakaocdn.net/dn/bqBeYR/hyNTwvCTws/PDUskT94lkQOf04QsDPMZk/img.png?width=1024&amp;amp;height=768&amp;amp;face=0_0_1024_768');&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;부스트캠프 웹 풀스택 6기 챌린지 1주차&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;부스트캠프 웹 풀스택 챌린지 합격 부스트캠프는 네이버 커넥트 재단에서 진행하는 개발자 양성 교육이다. 2016년을 시작으로 매년 한 번씩 진행되며 현재는 6기 모집이 끝났다. 나는 6기 웹 분야&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.hyunmin.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Life/부스트캠프</category>
      <category>boostcamp</category>
      <category>부스트캠프</category>
      <category>챌린지</category>
      <author>hyunmin!</author>
      <guid isPermaLink="true">https://hyunmindev.tistory.com/3</guid>
      <comments>https://hyunmindev.tistory.com/3#entry3comment</comments>
      <pubDate>Sat, 17 Jul 2021 13:39:11 +0900</pubDate>
    </item>
  </channel>
</rss>